audio: Propagate fatal error during offload to AF

Use offload callback thread to propagate fatal error
back to AF. AF can take action (invalidating tracks,
putting stream to standby) accordingly

Bug: 30075678
Change-Id: I426d6a7ff2a49cca7864ebea2c6be500bdb751b9
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 1e185e5..e4cd2b9 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1228,6 +1228,10 @@
             send_callback = true;
             event = STREAM_CBK_EVENT_DRAIN_READY;
             break;
+        case OFFLOAD_CMD_ERROR:
+            send_callback = true;
+            event = STREAM_CBK_EVENT_ERROR;
+            break;
         default:
             ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
             break;
@@ -1653,6 +1657,28 @@
     return 0;
 }
 
+static int out_on_error(struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    bool do_standby = false;
+
+    lock_output_stream(out);
+    if (!out->standby) {
+        if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+            stop_compressed_output_l(out);
+            send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
+        } else
+            do_standby = true;
+    }
+    pthread_mutex_unlock(&out->lock);
+
+    if (do_standby)
+        return out_standby(&out->stream.common);
+
+    return 0;
+}
+
 static int out_dump(const struct audio_stream *stream __unused, int fd __unused)
 {
     return 0;
@@ -1906,20 +1932,17 @@
     if (!valid_cb)
         return;
 
-    ALOGV("out_snd_mon_cb for card %d usecase %s", card,
-          use_case_table[out->usecase]);
-
     lock_output_stream(out);
     if (out->card_status != status)
         out->card_status = status;
     pthread_mutex_unlock(&out->lock);
 
-    // a better solution would be to report error back to AF and let
-    // it put the stream to standby
-    if (status == CARD_STATUS_OFFLINE) {
-        ALOGW("new state == offline, move stream to standby");
-        out_standby(&out->stream.common);
-    }
+    ALOGW("out_snd_mon_cb for card %d usecase %s, status %s", card,
+          use_case_table[out->usecase],
+          status == CARD_STATUS_OFFLINE ? "offline" : "online");
+
+    if (status == CARD_STATUS_OFFLINE)
+        out_on_error(stream);
 
     return;
 }
@@ -2024,11 +2047,12 @@
     pthread_mutex_unlock(&out->lock);
 
     if (ret != 0) {
+        out_on_error(&out->stream.common);
         if (out->pcm)
             ALOGE("%s: error %zu - %s", __func__, ret, pcm_get_error(out->pcm));
-        out_standby(&out->stream.common);
-        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
-               out_get_sample_rate(&out->stream.common));
+        if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD)
+            usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
+                   out_get_sample_rate(&out->stream.common));
     }
     return bytes;
 }
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 55c3be4..5ce3018 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -133,6 +133,7 @@
     OFFLOAD_CMD_DRAIN,              /* send a full drain request to DSP */
     OFFLOAD_CMD_PARTIAL_DRAIN,      /* send a partial drain request to DSP */
     OFFLOAD_CMD_WAIT_FOR_BUFFER,    /* wait for buffer released by DSP */
+    OFFLOAD_CMD_ERROR,              /* offload playback hit some error */
 };
 
 enum {