hal: SSR support for pcm playback,pcm record usecases

- Added SSR event handling support in HAL

- Added support to drop incoming pcm data for pcm playback
  usecase during SSR

- Added support to send dummy input(mute/zero buffer) for
  record usecase during SSR

Change-Id: I158b62fa443bb523091128fe1308c9a9b1415502
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 1584624..628f7fd 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -819,6 +819,15 @@
     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__);
+        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);
     if (ret)
@@ -875,6 +884,8 @@
         }
         break;
     }
+    in->pcm_error_type = PCM_ERROR_NONE;
+
     ALOGV("%s: exit", __func__);
     return ret;
 
@@ -1164,6 +1175,16 @@
     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) {
+        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) {
         ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
@@ -1228,6 +1249,7 @@
             }
             break;
         }
+        out->pcm_error_type = PCM_ERROR_NONE;
     } else {
         out->pcm = NULL;
         out->compr = compress_open(adev->snd_card,
@@ -1663,9 +1685,28 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
+    int scard_state = SND_CARD_STATE_ONLINE;
     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) {
+            ALOGD(" %s: sound card is not active/SSR state", __func__);
+            ret= -ENETRESET;
+            goto exit;
+        } else if (PCM_ERROR_ENETRESET ==  out->pcm_error_type) {
+            ALOGD(" %s restarting pcm session on post SSR", __func__);
+            out->standby = false;
+            pthread_mutex_unlock(&out->lock);
+            out_standby(&out->stream.common);
+            pthread_mutex_lock(&out->lock);
+        }
+    }
+
     if (out->standby) {
         out->standby = false;
         pthread_mutex_lock(&adev->lock);
@@ -1716,14 +1757,24 @@
     }
 
 exit:
+
+    if (-ENETRESET == ret) {
+        pthread_mutex_lock(&adev->snd_card_status.lock);
+        adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+        out->pcm_error_type = PCM_ERROR_ENETRESET;
+        out->standby = true; /*standby will be called on post SSR */
+        pthread_mutex_unlock(&adev->snd_card_status.lock);
+    }
+
     pthread_mutex_unlock(&out->lock);
 
     if (ret != 0) {
         if (out->pcm)
             ALOGE("%s: error %d - %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));
+        usleep(bytes * 1000000 / audio_stream_frame_size(&out->stream.common) /
+                        out_get_sample_rate(&out->stream.common));
+
     }
     return bytes;
 }
@@ -2058,8 +2109,27 @@
     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;
 
     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) {
+            ALOGD(" %s: sound card is not active/SSR state", __func__);
+            ret= -ENETRESET;
+            goto exit;
+        } else if (PCM_ERROR_ENETRESET ==  in->pcm_error_type) {
+            ALOGD(" %s restarting pcm session on post SSR", __func__);
+            in->standby = false;
+            pthread_mutex_unlock(&in->lock);
+            in_standby(&in->stream.common);
+            pthread_mutex_lock(&in->lock);
+        }
+    }
+
     if (in->standby) {
         pthread_mutex_lock(&adev->lock);
         if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
@@ -2093,13 +2163,22 @@
         memset(buffer, 0, bytes);
 
 exit:
+
+    if (-ENETRESET == ret) {
+        pthread_mutex_lock(&adev->snd_card_status.lock);
+        adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+        in->pcm_error_type = PCM_ERROR_ENETRESET;
+        memset(buffer, 0, bytes);
+        in->standby = true; /*standby will be called on post SSR */
+        pthread_mutex_unlock(&adev->snd_card_status.lock);
+    }
     pthread_mutex_unlock(&in->lock);
 
     if (ret != 0) {
         in_standby(&in->stream.common);
         ALOGV("%s: read failed - sleeping for buffer duration", __func__);
-        usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
-               in_get_sample_rate(&in->stream.common));
+        usleep(bytes * 1000000 / audio_stream_frame_size(&in->stream.common) /
+                                   in_get_sample_rate(&in->stream.common));
     }
     return bytes;
 }
@@ -2466,10 +2545,23 @@
     int status = 0;
 
     ALOGD("%s: enter: %s", __func__, kvpairs);
-
-    pthread_mutex_lock(&adev->lock);
     parms = str_parms_create_str(kvpairs);
 
+    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")) {
+            ALOGD("Received sound card OFFLINE status");
+            adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+        } else if (strstr(snd_card_status, "ONLINE")) {
+            ALOGD("Received sound card ONLINE status");
+            adev->snd_card_status.state = SND_CARD_STATE_ONLINE;
+        }
+        pthread_mutex_unlock(&adev->snd_card_status.lock);
+    }
+
+    pthread_mutex_lock(&adev->lock);
     status = voice_set_parameters(adev, parms);
     if (status != 0)
         goto done;
@@ -2860,6 +2952,9 @@
     list_init(&adev->usecase_list);
     adev->cur_wfd_channels = 2;
 
+    pthread_mutex_init(&adev->snd_card_status.lock, (const pthread_mutexattr_t *) NULL);
+    adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
+
     /* Loads platform specific libraries dynamically */
     adev->platform = platform_init(adev);
     if (!adev->platform) {
@@ -2871,6 +2966,8 @@
         return -EINVAL;
     }
 
+    adev->snd_card_status.state = SND_CARD_STATE_ONLINE;
+
     if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
         adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
         if (adev->visualizer_lib == NULL) {