hal: Add support for listen playback concurrency

Add support for concurrency handling between number of
listen capture session and playback activity.

Change-Id: I4a0656f240c62f2cc6266a714a96fdcdc13ae9d8
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 965e93e..bab4563 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -152,18 +152,23 @@
 #ifndef AUDIO_LISTEN_ENABLED
 #define audio_extn_listen_init(adev, snd_card)                  (0)
 #define audio_extn_listen_deinit(adev)                          (0)
-#define audio_extn_listen_update_status(uc_info, event)         (0)
+#define audio_extn_listen_update_device_status(snd_dev, event)  (0)
+#define audio_extn_listen_update_stream_status(uc_info, event)  (0)
 #define audio_extn_listen_set_parameters(adev, parms)           (0)
 #else
 enum listen_event_type {
     LISTEN_EVENT_SND_DEVICE_FREE,
-    LISTEN_EVENT_SND_DEVICE_BUSY
+    LISTEN_EVENT_SND_DEVICE_BUSY,
+    LISTEN_EVENT_STREAM_FREE,
+    LISTEN_EVENT_STREAM_BUSY
 };
 typedef enum listen_event_type listen_event_type_t;
 
 int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card);
 void audio_extn_listen_deinit(struct audio_device *adev);
-void audio_extn_listen_update_status(snd_device_t snd_device,
+void audio_extn_listen_update_device_status(snd_device_t snd_device,
+                                     listen_event_type_t event);
+void audio_extn_listen_update_stream_status(struct audio_usecase *uc_info,
                                      listen_event_type_t event);
 void audio_extn_listen_set_parameters(struct audio_device *adev,
                                       struct str_parms *parms);
diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c
index 91bb04f..b1ed105 100644
--- a/hal/audio_extn/listen.c
+++ b/hal/audio_extn/listen.c
@@ -95,25 +95,75 @@
 
 static struct listen_audio_device *listen_dev;
 
-void audio_extn_listen_update_status(snd_device_t snd_device,
-                                    listen_event_type_t event)
+void audio_extn_listen_update_device_status(snd_device_t snd_device,
+                                     listen_event_type_t event)
 {
-    if (!platform_listen_update_status(snd_device)) {
-        ALOGV("%s(): no need to notify listen. device = %s. Event = %u",
-                __func__, platform_get_snd_device_name(snd_device), event);
+    bool raise_event = false;
+    int device_type = -1;
+
+    if (snd_device >= SND_DEVICE_OUT_BEGIN &&
+        snd_device < SND_DEVICE_OUT_END)
+        device_type = PCM_PLAYBACK;
+    else if (snd_device >= SND_DEVICE_IN_BEGIN &&
+        snd_device < SND_DEVICE_IN_END)
+        device_type = PCM_CAPTURE;
+    else {
+        ALOGE("%s: invalid device 0x%x, for event %d",
+                           __func__, snd_device, event);
         return;
     }
 
     if (listen_dev) {
-        ALOGI("%s(): %s listen. current active device = %s. Event = %u",
-                __func__,
-                (event == LISTEN_EVENT_SND_DEVICE_BUSY) ? "stop" : "start",
-                platform_get_snd_device_name(snd_device), event);
+        raise_event = platform_listen_device_needs_event(snd_device);
+        ALOGI("%s(): device 0x%x of type %d for Event %d, with Raise=%d",
+            __func__, snd_device, device_type, event, raise_event);
+        if (raise_event && (device_type == PCM_CAPTURE)) {
+            switch(event) {
+            case LISTEN_EVENT_SND_DEVICE_FREE:
+                listen_dev->notify_event(AUDIO_DEVICE_IN_INACTIVE);
+                break;
+            case LISTEN_EVENT_SND_DEVICE_BUSY:
+                listen_dev->notify_event(AUDIO_DEVICE_IN_ACTIVE);
+                break;
+            default:
+                ALOGW("%s:invalid event %d for device 0x%x",
+                                      __func__, event, snd_device);
+            }
+        }/*Events for output device, if required can be placed here in else*/
+    }
+}
 
-            if (event == LISTEN_EVENT_SND_DEVICE_FREE)
-                   listen_dev->notify_event(AUDIO_CAPTURE_INACTIVE);
-            else if (event == LISTEN_EVENT_SND_DEVICE_BUSY)
-                   listen_dev->notify_event(AUDIO_CAPTURE_ACTIVE);
+void audio_extn_listen_update_stream_status(struct audio_usecase *uc_info,
+                                     listen_event_type_t event)
+{
+    bool raise_event = false;
+    audio_usecase_t uc_id;
+    int usecase_type = -1;
+
+    if (uc_info == NULL) {
+        ALOGE("%s: usecase is NULL!!!", __func__);
+        return;
+    }
+    uc_id = uc_info->id;
+    usecase_type = uc_info->type;
+
+    if (listen_dev) {
+        raise_event = platform_listen_usecase_needs_event(uc_id);
+        ALOGI("%s(): uc_id %d of type %d for Event %d, with Raise=%d",
+            __func__, uc_id, usecase_type, event, raise_event);
+        if (raise_event && (usecase_type == PCM_PLAYBACK)) {
+            switch(event) {
+            case LISTEN_EVENT_STREAM_FREE:
+                listen_dev->notify_event(AUDIO_STREAM_OUT_INACTIVE);
+                break;
+            case LISTEN_EVENT_STREAM_BUSY:
+                listen_dev->notify_event(AUDIO_STREAM_OUT_ACTIVE);
+                break;
+            default:
+                ALOGW("%s:invalid event %d, for usecase %d",
+                                      __func__, event, uc_id);
+            }
+        }/*Events for capture usecase, if required can be placed here in else*/
     }
 }
 
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 5793cce..37bbcba 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -257,6 +257,7 @@
     audio_extn_dolby_set_dmid(adev);
     audio_extn_dolby_set_endpoint(adev);
 #endif
+    audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
     audio_extn_utils_send_audio_calibration(adev, usecase);
     audio_extn_utils_send_app_type_cfg(usecase);
     strcpy(mixer_path, use_case_table[usecase->id]);
@@ -285,6 +286,7 @@
     platform_add_backend_name(mixer_path, snd_device);
     ALOGV("%s: reset and update mixer path: %s", __func__, mixer_path);
     audio_route_reset_and_update_path(adev->audio_route, mixer_path);
+    audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
     ALOGV("%s: exit", __func__);
     return 0;
 }
@@ -337,12 +339,12 @@
         snd_device, device_name);
         /* due to the possibility of calibration overwrite between listen
             and audio, notify listen hal before audio calibration is sent */
-        audio_extn_listen_update_status(snd_device,
-                       LISTEN_EVENT_SND_DEVICE_BUSY);
+        audio_extn_listen_update_device_status(snd_device,
+                                        LISTEN_EVENT_SND_DEVICE_BUSY);
         if (platform_get_snd_device_acdb_id(snd_device) < 0) {
             adev->snd_dev_ref_cnt[snd_device]--;
-            audio_extn_listen_update_status(snd_device,
-                           LISTEN_EVENT_SND_DEVICE_FREE);
+            audio_extn_listen_update_device_status(snd_device,
+                                        LISTEN_EVENT_SND_DEVICE_FREE);
             return -EINVAL;
         }
         audio_route_apply_and_update_path(adev->audio_route, device_name);
@@ -391,7 +393,7 @@
         } else
             audio_route_reset_and_update_path(adev->audio_route, device_name);
 
-        audio_extn_listen_update_status(snd_device,
+        audio_extn_listen_update_device_status(snd_device,
                                         LISTEN_EVENT_SND_DEVICE_FREE);
     }
 
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 81e7c43..ae136f1 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1885,15 +1885,65 @@
     return usecase;
 }
 
-bool platform_listen_update_status(snd_device_t snd_device)
+bool platform_listen_device_needs_event(snd_device_t snd_device)
 {
+    bool needs_event = false;
+
     if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
         (snd_device < SND_DEVICE_IN_END) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
-        return true;
-    else
-        return false;
+        needs_event = true;
+
+    return needs_event;
+}
+
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id)
+{
+    bool needs_event = false;
+
+    switch(uc_id){
+    /* concurrent playback usecases needs event */
+    case USECASE_AUDIO_PLAYBACK_DEEP_BUFFER:
+    case USECASE_AUDIO_PLAYBACK_MULTI_CH:
+    case USECASE_AUDIO_PLAYBACK_OFFLOAD:
+        needs_event = true;
+        break;
+    /* concurrent playback in low latency allowed */
+    case USECASE_AUDIO_PLAYBACK_LOW_LATENCY:
+        break;
+    /* concurrent playback FM needs event */
+    case USECASE_AUDIO_PLAYBACK_FM:
+        needs_event = true;
+        break;
+
+    /* concurrent capture usecases, no event, capture handled by device
+    *  USECASE_AUDIO_RECORD:
+    *  USECASE_AUDIO_RECORD_COMPRESS:
+    *  USECASE_AUDIO_RECORD_LOW_LATENCY:
+
+    *  USECASE_VOICE_CALL:
+    *  USECASE_VOICE2_CALL:
+    *  USECASE_VOLTE_CALL:
+    *  USECASE_QCHAT_CALL:
+    *  USECASE_VOWLAN_CALL:
+    *  USECASE_COMPRESS_VOIP_CALL:
+    *  USECASE_AUDIO_RECORD_FM_VIRTUAL:
+    *  USECASE_INCALL_REC_UPLINK:
+    *  USECASE_INCALL_REC_DOWNLINK:
+    *  USECASE_INCALL_REC_UPLINK_AND_DOWNLINK:
+    *  USECASE_INCALL_REC_UPLINK_COMPRESS:
+    *  USECASE_INCALL_REC_DOWNLINK_COMPRESS:
+    *  USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS:
+    *  USECASE_INCALL_MUSIC_UPLINK:
+    *  USECASE_INCALL_MUSIC_UPLINK2:
+    *  USECASE_AUDIO_SPKR_CALIB_RX:
+    *  USECASE_AUDIO_SPKR_CALIB_TX:
+    */
+    default:
+        ALOGV("%s:usecase_id[%d} no need to raise event.", __func__, uc_id);
+    }
+    return needs_event;
 }
 
 /* Read  offload buffer size from a property.
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 70e0b9e..13f5473 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -914,7 +914,12 @@
     return usecase;
 }
 
-bool platform_listen_update_status(snd_device_t snd_device)
+bool platform_listen_device_needs_event(snd_device_t snd_device)
 {
-     return false;
+    return false;
+}
+
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id)
+{
+    return false;
 }
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index ac747e4..364bbd2 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1997,15 +1997,22 @@
     return usecase;
 }
 
-bool platform_listen_update_status(snd_device_t snd_device)
+bool platform_listen_device_needs_event(snd_device_t snd_device)
 {
+    bool needs_event = false;
+
     if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
         (snd_device < SND_DEVICE_IN_END) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
-        return true;
-    else
-        return false;
+        needs_event = true;
+
+    return needs_event;
+}
+
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id)
+{
+    return false;
 }
 
 /* Read  offload buffer size from a property.
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 1e97adf..66b090e 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -67,7 +67,8 @@
 int64_t platform_render_latency(audio_usecase_t usecase);
 int platform_update_usecase_from_source(int source, audio_usecase_t usecase);
 
-bool platform_listen_update_status(snd_device_t snd_device);
+bool platform_listen_device_needs_event(snd_device_t snd_device);
+bool platform_listen_usecase_needs_event(audio_usecase_t uc_id);
 
 /* From platform_info_parser.c */
 int platform_info_init(const char *filename);