audio: hal: QAF: Adding channel map support
-Support to send actual channel map returned by module
-Adding stream state to avoid back to back stream stop

CRs-fixed: 2058347 2043959
Change-Id: Ibda42c7a9b6c0389d410aad4b11ac38dfe6ef6b4
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index cca9590..5dba1d2 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -161,6 +161,13 @@
     MAX_QAF_MODULE_IN
 } mm_module_input_type;
 
+typedef enum {
+    STOPPED,    /*Stream is in stop state. */
+    STOPPING,   /*Stream is stopping, waiting for EOS. */
+    RUN,        /*Stream is in run state. */
+    MAX_STATES
+} qaf_stream_state;
+
 struct qaf_module {
     audio_session_handle_t session_handle;
     void *qaf_lib;
@@ -209,7 +216,7 @@
     float vol_left;
     float vol_right;
     bool is_vol_set;
-    bool drain_received[MAX_QAF_MODULE_IN];
+    qaf_stream_state stream_state[MAX_QAF_MODULE_IN];
 };
 
 struct qaf {
@@ -281,6 +288,21 @@
     return index;
 }
 
+static void set_stream_state(struct stream_out *out, int state)
+{
+    struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+    int index = get_input_stream_index(out);
+    if (qaf_mod && index >= 0) qaf_mod->stream_state[index] = state;
+}
+
+static bool check_stream_state(struct stream_out *out, int state)
+{
+    struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
+    int index = get_input_stream_index(out);
+    if (qaf_mod && index >= 0) return (qaf_mod->stream_state[index] == state);
+    return false;
+}
+
 /* Finds the right mm module for the QAF input stream format. */
 static mm_module_type get_mm_module_for_format(audio_format_t format)
 {
@@ -555,6 +577,8 @@
     int ret = 0;
     DEBUG_MSG("Output Stream 0x%x", out);
 
+    if (!check_stream_state(out, RUN)) return ret;
+
     struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
     if ((!qaf_mod) || (!qaf_mod->qaf_audio_stream_stop)) {
         return ret;
@@ -585,9 +609,14 @@
             status = p_qaf->passthrough_out->stream.common.standby(
                     (struct audio_stream *)p_qaf->passthrough_out);
         }
-    } else {
+    } else if (check_stream_state(out, RUN)) {
         //If QAF passthrough stream is not active then stop the QAF module stream.
         status = audio_extn_qaf_stream_stop(out);
+
+        if (status == 0) {
+            //Setting state to stopped as client not expecting drain_ready event.
+            set_stream_state(out, STOPPED);
+        }
     }
 
     if (!out->standby) {
@@ -685,6 +714,7 @@
 
     if (out->qaf_stream_handle) {
         ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
+        if(ret > 0) set_stream_state(out, RUN);
     }
     return ret;
 }
@@ -1027,16 +1057,19 @@
                     (struct audio_stream_out *)p_qaf->passthrough_out, type);
         }
         pthread_mutex_unlock(&p_qaf->lock);
+    } else if (check_stream_state(out, STOPPED)) {
+        //If stream is already stopped then send the drain ready.
+        out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
     } else {
+
         //Drain the module input stream.
         /* Stream stop will trigger EOS and on EOS_EVENT received
          from callback DRAIN_READY command is sent */
         status = audio_extn_qaf_stream_stop(out);
 
         if (status == 0) {
-            struct qaf_module *qaf_mod = get_qaf_module_for_input_stream(out);
-            int index = get_input_stream_index(out);
-            if (qaf_mod && index >= 0) qaf_mod->drain_received[index] = true;
+            //Setting state to stopping as client is expecting drain_ready event.
+            set_stream_state(out, STOPPING);
         }
     }
 
@@ -1161,6 +1194,21 @@
     }
 }
 
+static void set_out_stream_channel_map(struct stream_out *out, audio_qaf_media_format_t *media_fmt)
+{
+    if (media_fmt == NULL || out == NULL) {
+        return;
+    }
+    struct audio_out_channel_map_param chmap = {0};
+    int i = 0;
+    chmap.channels = media_fmt->channels;
+    for (i = 0; i < chmap.channels && i < AUDIO_CHANNEL_COUNT_MAX && i < AUDIO_QAF_MAX_CHANNELS;
+            i++) {
+        chmap.channel_map[i] = media_fmt->ch_map[i];
+    }
+    audio_extn_utils_set_channel_map(out, &chmap);
+}
+
 /* Call back function for mm module. */
 static void notify_event_callback(audio_session_handle_t session_handle /*__unused*/,
                                   void *prv_data,
@@ -1188,6 +1236,7 @@
     uint32_t buffer_size = 0;
     bool need_to_recreate_stream = false;
     struct audio_config config;
+    audio_qaf_media_format_t *media_fmt = NULL;
 
     DEBUG_MSG_VV("Device 0x%X, Event = 0x%X, Bytes to write %d", device, event_id, size);
     pthread_mutex_lock(&p_qaf->lock);
@@ -1206,7 +1255,6 @@
     } else if (event_id == AUDIO_DATA_EVENT_V2) {
         audio_qaf_out_buffer_t *buf_payload = (audio_qaf_out_buffer_t*)buf;
         int index = -1;
-        audio_qaf_media_format_t *p_cached_fmt = NULL;
 
         if (size < sizeof(audio_qaf_out_buffer_t)) {
             ERROR_MSG("AUDIO_DATA_EVENT_V2 payload size is not sufficient.");
@@ -1222,49 +1270,29 @@
             /*If media format is not received then switch to default values.*/
             event_id = AUDIO_DATA_EVENT;
         } else {
-            p_cached_fmt = &qaf_mod->out_stream_fmt[index];
+            media_fmt = &qaf_mod->out_stream_fmt[index];
             need_to_recreate_stream = qaf_mod->is_media_fmt_changed[index];
             qaf_mod->is_media_fmt_changed[index] = false;
 
-            config.sample_rate = config.offload_info.sample_rate = p_cached_fmt->sample_rate;
+            config.sample_rate = config.offload_info.sample_rate = media_fmt->sample_rate;
             config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
             config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-            config.format = config.offload_info.format = p_cached_fmt->format;
-            config.offload_info.bit_width = p_cached_fmt->bit_width;
+            config.format = config.offload_info.format = media_fmt->format;
+            config.offload_info.bit_width = media_fmt->bit_width;
 
-            if (p_cached_fmt->format == AUDIO_FORMAT_PCM) {
-                if (p_cached_fmt->bit_width == 16)
+            if (media_fmt->format == AUDIO_FORMAT_PCM) {
+                if (media_fmt->bit_width == 16)
                     config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
-                else if (p_cached_fmt->bit_width == 24)
+                else if (media_fmt->bit_width == 24)
                     config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
                 else
                     config.format = config.offload_info.format = AUDIO_FORMAT_PCM_32_BIT;
             }
 
-            device |= (p_cached_fmt->format & AUDIO_FORMAT_MAIN_MASK);
+            device |= (media_fmt->format & AUDIO_FORMAT_MAIN_MASK);
 
-            switch (p_cached_fmt->channels) {
-                case 1:
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_MONO;
-                break;
-                case 2:
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_STEREO;
-                break;
-                case 6:
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_5POINT1;
-                break;
-                case 8:
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_7POINT1;
-                break;
-                default:
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_5POINT1;
-                break;
-            }
+            config.channel_mask = audio_channel_out_mask_from_count(media_fmt->channels);
+            config.offload_info.channel_mask = config.channel_mask;
         }
     }
 
@@ -1435,6 +1463,7 @@
                     pthread_mutex_unlock(&p_qaf->lock);
                     return;
                 }
+                set_out_stream_channel_map(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH], media_fmt);
 
                 qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->compr_config.fragments =
                         COMPRESS_OFFLOAD_NUM_FRAGMENTS;
@@ -1551,6 +1580,7 @@
                     pthread_mutex_unlock(&p_qaf->lock);
                     return;
                 }
+                set_out_stream_channel_map(qaf_mod->stream_out[QAF_OUT_OFFLOAD], media_fmt);
 
                 if ((qaf_mod->stream_in[QAF_IN_MAIN]
                     && qaf_mod->stream_in[QAF_IN_MAIN]->client_callback != NULL) ||
@@ -1634,9 +1664,6 @@
         struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
         struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
         struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
-        bool *main_drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
-        bool *main2_drain_received = &qaf_mod->drain_received[QAF_IN_MAIN_2];
-        bool *assoc_drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
 
         /**
          * TODO:: Only DD/DDP Associate Eos is handled, need to add support
@@ -1644,46 +1671,43 @@
          */
         if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
                 && (out_assoc != NULL)
-                && (*assoc_drain_received)) {
+                && (check_stream_state(out_assoc, STOPPING))) {
 
             lock_output_stream(out_assoc);
             out_assoc->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_assoc->client_cookie);
-            *assoc_drain_received = false;
+            set_stream_state(out_assoc, STOPPED);
             unlock_output_stream(out_assoc);
             DEBUG_MSG("sent associated DRAIN_READY");
         } else if (event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
                 && (out_main2 != NULL)
-                && (*main2_drain_received)) {
+                && (check_stream_state(out_main2, STOPPING))) {
 
             lock_output_stream(out_main2);
             out_main2->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_main2->client_cookie);
-            *main2_drain_received = false;
+            set_stream_state(out_main2, STOPPED);
             unlock_output_stream(out_main2);
             DEBUG_MSG("sent main2 DRAIN_READY");
-        } else if ((out != NULL) && (*main_drain_received)) {
+        } else if ((out != NULL) && (check_stream_state(out, STOPPING))) {
             lock_output_stream(out);
             out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
-            *main_drain_received = false;
+            set_stream_state(out, STOPPED);
             unlock_output_stream(out);
             DEBUG_MSG("sent main DRAIN_READY");
         }
     }
     else if (event_id == AUDIO_MAIN_EOS_EVENT || event_id == AUDIO_ASSOC_EOS_EVENT) {
         struct stream_out *out = NULL;
-        bool *drain_received = NULL;
 
         if (event_id == AUDIO_MAIN_EOS_EVENT) {
             out = qaf_mod->stream_in[QAF_IN_MAIN];
-            drain_received = &qaf_mod->drain_received[QAF_IN_MAIN];
         } else {
             out = qaf_mod->stream_in[QAF_IN_ASSOC];
-            drain_received = &qaf_mod->drain_received[QAF_IN_ASSOC];
         }
 
-        if ((out != NULL) && (*drain_received)) {
+        if ((out != NULL) && (check_stream_state(out, STOPPING))) {
             lock_output_stream(out);
             out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
-            *drain_received = false;
+            set_stream_state(out, STOPPED);
             unlock_output_stream(out);
             DEBUG_MSG("sent DRAIN_READY");
         }
@@ -1712,7 +1736,7 @@
         qaf_mod->qaf_audio_session_close(qaf_mod->session_handle);
         qaf_mod->session_handle = NULL;
         qaf_mod->is_vol_set = false;
-        memset(qaf_mod->drain_received, 0, sizeof(qaf_mod->drain_received));
+        memset(qaf_mod->stream_state, 0, sizeof(qaf_mod->stream_state));
     }
 
     for (j = 0; j < MAX_QAF_MODULE_OUT; j++) {
@@ -1746,6 +1770,7 @@
         return -EINVAL;
     }
 
+    set_stream_state(out,STOPPED);
     qaf_mod->stream_in[index] = NULL;
     memset(&qaf_mod->adsp_hdlr_config[index], 0, sizeof(struct qaf_adsp_hdlr_config_state));