hal: SSR support for compress offload

- add support for time stamp error propagation
  to frameworks on compress driver error

- close active compress session on SSR.

Change-Id: I9cbd3a6c271097b81c9b79e71573fda8d78c7dbf
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 550d7ae..8542c70 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -275,6 +275,32 @@
     return 0;
 }
 
+static int get_snd_card_state(struct audio_device *adev)
+{
+    int snd_scard_state;
+
+    if (!adev)
+        return SND_CARD_STATE_OFFLINE;
+
+    pthread_mutex_lock(&adev->snd_card_status.lock);
+    snd_scard_state = adev->snd_card_status.state;
+    pthread_mutex_unlock(&adev->snd_card_status.lock);
+
+    return snd_scard_state;
+}
+
+static int set_snd_card_state(struct audio_device *adev, int snd_scard_state)
+{
+    if (!adev)
+        return -ENOSYS;
+
+    pthread_mutex_lock(&adev->snd_card_status.lock);
+    adev->snd_card_status.state = snd_scard_state;
+    pthread_mutex_unlock(&adev->snd_card_status.lock);
+
+    return 0;
+}
+
 int enable_audio_route(struct audio_device *adev,
                        struct audio_usecase *usecase)
 {
@@ -814,19 +840,17 @@
     int ret = 0;
     struct audio_usecase *uc_info;
     struct audio_device *adev = in->dev;
+    int snd_card_status = get_snd_card_state(adev);
 
     in->usecase = platform_update_usecase_from_source(in->source,in->usecase);
     ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
           __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
 
-    pthread_mutex_lock(&adev->snd_card_status.lock);
-    if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) {
-        ALOGE("%s: sound card is not active/SSR returning error", __func__);
+    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+        ALOGE("%s: sound card is not active/SSR returning error ", __func__);
         ret = -ENETRESET;
-        pthread_mutex_unlock(&adev->snd_card_status.lock);
         goto error_config;
     }
-    pthread_mutex_unlock(&adev->snd_card_status.lock);
 
     /* Check if source matches incall recording usecase criteria */
     ret = voice_check_and_set_incall_rec_usecase(adev, in);
@@ -1170,19 +1194,17 @@
     char prop_value[PROPERTY_VALUE_MAX] = {0};
     struct audio_usecase *uc_info;
     struct audio_device *adev = out->dev;
+    int snd_card_status = get_snd_card_state(adev);
 
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
           out->devices);
 
-    pthread_mutex_lock(&adev->snd_card_status.lock);
-    if (SND_CARD_STATE_OFFLINE == adev->snd_card_status.state) {
+    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
         ALOGE("%s: sound card is not active/SSR returning error", __func__);
         ret = -ENETRESET;
-        pthread_mutex_unlock(&adev->snd_card_status.lock);
         goto error_config;
     }
-    pthread_mutex_unlock(&adev->snd_card_status.lock);
 
     out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
     if (out->pcm_device_id < 0) {
@@ -1683,19 +1705,21 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
-    int scard_state = SND_CARD_STATE_ONLINE;
+    int snd_scard_state = get_snd_card_state(adev);
     ssize_t ret = 0;
 
     pthread_mutex_lock(&out->lock);
-    pthread_mutex_lock(&adev->snd_card_status.lock);
-    scard_state = adev->snd_card_status.state;
-    pthread_mutex_unlock(&adev->snd_card_status.lock);
 
-    if (out->pcm) {
-        if (SND_CARD_STATE_OFFLINE == scard_state) {
+    if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
+        if (out->pcm) {
             ALOGD(" %s: sound card is not active/SSR state", __func__);
             ret= -ENETRESET;
             goto exit;
+        } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+            //during SSR for compress usecase we should return error to flinger
+            ALOGD(" copl %s: sound card is not active/SSR state", __func__);
+            pthread_mutex_unlock(&out->lock);
+            return -ENETRESET;
         }
     }
 
@@ -1726,8 +1750,14 @@
         ALOGVV("%s: writing buffer (%d bytes) to compress device returned %d", __func__, bytes, ret);
         if (ret >= 0 && ret < (ssize_t)bytes) {
             send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
+        } else if (-ENETRESET == ret) {
+            ALOGE("copl %s: received sound card offline state on compress write", __func__);
+            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+            pthread_mutex_unlock(&out->lock);
+            out_standby(&out->stream.common);
+            return ret;
         }
-        if (!out->playback_started) {
+        if (!out->playback_started && ret >= 0) {
             compress_start(out->compr);
             out->playback_started = 1;
             out->offload_state = OFFLOAD_STATE_PLAYING;
@@ -1752,9 +1782,7 @@
     /* ToDo: There may be a corner case when SSR happens back to back during
        start/stop. Need to post different error to handle that. */
     if (-ENETRESET == ret) {
-        pthread_mutex_lock(&adev->snd_card_status.lock);
-        adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
-        pthread_mutex_unlock(&adev->snd_card_status.lock);
+        set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
     }
 
     pthread_mutex_unlock(&out->lock);
@@ -1776,15 +1804,25 @@
     struct stream_out *out = (struct stream_out *)stream;
     *dsp_frames = 0;
     if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
+        ssize_t ret =  -EINVAL;
         pthread_mutex_lock(&out->lock);
         if (out->compr != NULL) {
-            compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
+            ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
                     &out->sample_rate);
             ALOGVV("%s rendered frames %d sample_rate %d",
                    __func__, *dsp_frames, out->sample_rate);
         }
         pthread_mutex_unlock(&out->lock);
-        return 0;
+        if (-ENETRESET == ret) {
+            ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
+            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+            return -EINVAL;
+        } else if(ret < 0) {
+            ALOGE(" ERROR: Unable to get time stamp from compress driver");
+            return -EINVAL;
+        } else {
+            return 0;
+        }
     } else
         return -EINVAL;
 }
@@ -1873,7 +1911,12 @@
     if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
         pthread_mutex_lock(&out->lock);
         if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
-            status = compress_pause(out->compr);
+            struct audio_device *adev = out->dev;
+            int snd_scard_state = get_snd_card_state(adev);
+
+            if (SND_CARD_STATE_ONLINE == snd_scard_state)
+                status = compress_pause(out->compr);
+
             out->offload_state = OFFLOAD_STATE_PAUSED;
         }
         pthread_mutex_unlock(&out->lock);
@@ -1890,7 +1933,12 @@
         status = 0;
         pthread_mutex_lock(&out->lock);
         if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
-            status = compress_resume(out->compr);
+            struct audio_device *adev = out->dev;
+            int snd_scard_state = get_snd_card_state(adev);
+
+            if (SND_CARD_STATE_ONLINE == snd_scard_state)
+                status = compress_resume(out->compr);
+
             out->offload_state = OFFLOAD_STATE_PLAYING;
         }
         pthread_mutex_unlock(&out->lock);
@@ -2100,15 +2148,12 @@
     struct stream_in *in = (struct stream_in *)stream;
     struct audio_device *adev = in->dev;
     int i, ret = -1;
-    int scard_state = SND_CARD_STATE_ONLINE;
+    int snd_scard_state = get_snd_card_state(adev);
 
     pthread_mutex_lock(&in->lock);
-    pthread_mutex_lock(&adev->snd_card_status.lock);
-    scard_state = adev->snd_card_status.state;
-    pthread_mutex_unlock(&adev->snd_card_status.lock);
 
     if (in->pcm) {
-        if(SND_CARD_STATE_OFFLINE == scard_state) {
+        if(SND_CARD_STATE_OFFLINE == snd_scard_state) {
             ALOGD(" %s: sound card is not active/SSR state", __func__);
             ret= -ENETRESET;
             goto exit;
@@ -2151,10 +2196,8 @@
     /* ToDo: There may be a corner case when SSR happens back to back during
        start/stop. Need to post different error to handle that. */
     if (-ENETRESET == ret) {
-        pthread_mutex_lock(&adev->snd_card_status.lock);
-        adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+        set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
         memset(buffer, 0, bytes);
-        pthread_mutex_unlock(&adev->snd_card_status.lock);
     }
     pthread_mutex_unlock(&in->lock);
 
@@ -2232,6 +2275,13 @@
     int i, ret = 0;
 
     *stream_out = NULL;
+
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+             (SND_CARD_STATE_OFFLINE == get_snd_card_state(adev))) {
+        ALOGE(" sound card is not active rejecting compress output open request");
+        return -EINVAL;
+    }
+
     out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
 
     ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
@@ -2534,15 +2584,29 @@
     ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
     if (ret >= 0) {
         char *snd_card_status = value+2;
-        pthread_mutex_lock(&adev->snd_card_status.lock);
         if (strstr(snd_card_status, "OFFLINE")) {
+            struct listnode *node;
+            struct audio_usecase *usecase;
+
             ALOGD("Received sound card OFFLINE status");
-            adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+
+            pthread_mutex_lock(&adev->lock);
+            //close compress session on OFFLINE status
+            usecase = get_usecase_from_list(adev,USECASE_AUDIO_PLAYBACK_OFFLOAD);
+            if (usecase && usecase->stream.out) {
+                ALOGD(" %s closing compress session on OFFLINE state", __func__);
+
+                struct stream_out *out = usecase->stream.out;
+
+                pthread_mutex_unlock(&adev->lock);
+                out_standby(&out->stream.common);
+            } else
+                pthread_mutex_unlock(&adev->lock);
         } else if (strstr(snd_card_status, "ONLINE")) {
             ALOGD("Received sound card ONLINE status");
-            adev->snd_card_status.state = SND_CARD_STATE_ONLINE;
+            set_snd_card_state(adev,SND_CARD_STATE_ONLINE);
         }
-        pthread_mutex_unlock(&adev->snd_card_status.lock);
     }
 
     pthread_mutex_lock(&adev->lock);
@@ -2626,15 +2690,15 @@
     char *str;
 
     pthread_mutex_lock(&adev->lock);
-
     audio_extn_get_parameters(adev, query, reply);
     voice_get_parameters(adev, query, reply);
     platform_get_parameters(adev->platform, query, reply);
+    pthread_mutex_unlock(&adev->lock);
+
     str = str_parms_to_str(reply);
     str_parms_destroy(query);
     str_parms_destroy(reply);
 
-    pthread_mutex_unlock(&adev->lock);
     ALOGV("%s: exit: returns - %s", __func__, str);
     return str;
 }