audio: hal: qaf: QAF update.
 -Generic Main and Associated events
 -New Data event supporting timestamp and metadata
 -Output media format event

CRs-fixed: 2049086

Change-Id: I238c2e5fd082d38ac335f743b71bbb2db974f5f0
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index c0dad9c..2174364 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -193,6 +193,13 @@
     /*Output Stream from MM module */
     struct stream_out *stream_out[MAX_QAF_MODULE_OUT];
 
+    /*Media format associated with each output id raised by mm module. */
+    audio_qaf_media_format_t out_stream_fmt[MAX_QAF_MODULE_OUT];
+    /*Flag is set if media format is changed for an mm module output. */
+    bool is_media_fmt_changed[MAX_QAF_MODULE_OUT];
+    /*Index to be updated in out_stream_fmt array for a new mm module output. */
+    int new_out_format_index;
+
     struct qaf_adsp_hdlr_config_state adsp_hdlr_config[MAX_QAF_MODULE_IN];
 
     //BT session handle.
@@ -337,6 +344,19 @@
     return pcm_output_buffer_size;
 }
 
+static int get_media_fmt_array_index_for_output_id(
+        struct qaf_module* qaf_mod,
+        int output_id)
+{
+    int i;
+    for (i = 0; i < MAX_QAF_MODULE_OUT; i++) {
+        if (qaf_mod->out_stream_fmt[i].output_id == output_id) {
+            return i;
+        }
+    }
+    return -1;
+}
+
 /* Acquire Mutex lock on output stream */
 static void lock_output_stream(struct stream_out *out)
 {
@@ -1135,9 +1155,6 @@
         case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS):
             *format = AUDIO_FORMAT_DTS;
             return true;
-        case (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_FORMAT_DTS_HD):
-            *format = AUDIO_FORMAT_DTS_HD;
-            return true;
         default:
             return false;
     }
@@ -1166,11 +1183,121 @@
     struct qaf_module* qaf_mod = (struct qaf_module*)prv_data;
     struct audio_stream_out *bt_stream = NULL;
     int format;
+    int8_t *data_buffer_p = NULL;
+    uint32_t buffer_size = 0;
+    bool need_to_recreate_stream = false;
+    struct audio_config config;
 
     DEBUG_MSG_VV("Device 0x%X, Event = 0x%X, Bytes to write %d", device, event_id, size);
     pthread_mutex_lock(&p_qaf->lock);
 
+    /* Default config initialization. */
+    config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
+    config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+    config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+    config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+    config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+
     if (event_id == AUDIO_DATA_EVENT) {
+        data_buffer_p = (int8_t*)buf;
+        buffer_size = size;
+    } 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.");
+            return;
+        }
+
+        data_buffer_p = (int8_t*)buf_payload->data + buf_payload->offset;
+        buffer_size = buf_payload->size - buf_payload->offset;
+
+        index = get_media_fmt_array_index_for_output_id(qaf_mod, buf_payload->output_id);
+
+        if (index < 0) {
+            /*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];
+            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.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;
+
+            if (p_cached_fmt->format == AUDIO_FORMAT_PCM) {
+                if (p_cached_fmt->bit_width == 16)
+                    config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+                else if (p_cached_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);
+
+            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;
+            }
+        }
+    }
+
+    if (event_id == AUDIO_OUTPUT_MEDIA_FORMAT_EVENT) {
+        audio_qaf_media_format_t *p_fmt = (audio_qaf_media_format_t*)buf;
+        audio_qaf_media_format_t *p_cached_fmt = NULL;
+        int index = -1;
+
+        if (size < sizeof(audio_qaf_media_format_t)) {
+            ERROR_MSG("Size is not proper for the event AUDIO_OUTPUT_MEDIA_FORMAT_EVENT.");
+            return ;
+        }
+
+        index = get_media_fmt_array_index_for_output_id(qaf_mod, p_fmt->output_id);
+
+        if (index >= 0) {
+            p_cached_fmt = &qaf_mod->out_stream_fmt[index];
+        } else if (index < 0 && qaf_mod->new_out_format_index < MAX_QAF_MODULE_OUT) {
+            index = qaf_mod->new_out_format_index;
+            p_cached_fmt = &qaf_mod->out_stream_fmt[index];
+            qaf_mod->new_out_format_index++;
+        }
+
+        if (p_cached_fmt == NULL) {
+            ERROR_MSG("Maximum output from a QAF module is reached. Can not process new output.");
+            return ;
+        }
+
+        if (memcmp(p_cached_fmt, p_fmt, sizeof(audio_qaf_media_format_t)) != 0) {
+            memcpy(p_cached_fmt, p_fmt, sizeof(audio_qaf_media_format_t));
+            qaf_mod->is_media_fmt_changed[index] = true;
+        }
+    } else if (event_id == AUDIO_DATA_EVENT || event_id == AUDIO_DATA_EVENT_V2) {
+
         if (p_qaf->passthrough_out != NULL) {
             //If QAF passthrough is active then all the module output will be dropped.
             pthread_mutex_unlock(&p_qaf->lock);
@@ -1196,21 +1323,20 @@
             //Closing all the PCM HDMI output stream from QAF.
             close_all_pcm_hdmi_output();
 
+            /* If Media format was changed for this stream then need to re-create the stream. */
+            if (need_to_recreate_stream && qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
+                adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                         (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]));
+                qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH] = NULL;
+                p_qaf->passthrough_enabled = false;
+            }
+
             if (!p_qaf->passthrough_enabled
                 && !(qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH])) {
 
-                struct audio_config config;
                 audio_devices_t devices;
 
-                //TODO: need to update the actual sample rate.
-                config.sample_rate = config.offload_info.sample_rate =
-                        QAF_OUTPUT_SAMPLING_RATE;
-                config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
-                config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
                 config.format = config.offload_info.format = format;
-                //TODO: need to update the actual bit width.
-                config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-                //TODO: What is the relevance of num of channels.
                 config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
 
                 flags = (AUDIO_OUTPUT_FLAG_NON_BLOCKING
@@ -1231,7 +1357,7 @@
                     return;
                 }
 
-                if (format & AUDIO_COMPRESSED_OUT_DDP) {
+                if (format & AUDIO_FORMAT_E_AC3) {
                     qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->compr_config.fragment_size =
                             COMPRESS_PASSTHROUGH_DDP_FRAGMENT_SIZE;
                 }
@@ -1244,8 +1370,8 @@
             if (qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]) {
                 ret = qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH]->stream.write(
                         (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_TRANSCODE_PASSTHROUGH],
-                        buf,
-                        size);
+                        data_buffer_p,
+                        buffer_size);
             }
         }
         else if ((device & AUDIO_DEVICE_OUT_AUX_DIGITAL)
@@ -1267,28 +1393,30 @@
                 return;
             }
 
+            /* If Media format was changed for this stream then need to re-create the stream. */
+            if (need_to_recreate_stream && qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]) {
+                adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                         (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]));
+                qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH] = NULL;
+                p_qaf->mch_pcm_hdmi_enabled = false;
+            }
+
             if (!p_qaf->mch_pcm_hdmi_enabled && !(qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH])) {
-                struct audio_config config;
                 audio_devices_t devices;
 
-                //TODO: need to update the actual sample rate.
-                config.sample_rate = config.offload_info.sample_rate =
-                        QAF_OUTPUT_SAMPLING_RATE;
-                config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
-                config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-                config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
-                //TODO: need to update the actual bit width.
-                config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+                if (event_id == AUDIO_DATA_EVENT) {
+                    config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
 
-                if (p_qaf->hdmi_sink_channels == 8) {
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_7POINT1;
-                } else if (p_qaf->hdmi_sink_channels == 6) {
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_5POINT1;
-                } else {
-                    config.offload_info.channel_mask = config.channel_mask =
-                            AUDIO_CHANNEL_OUT_STEREO;
+                    if (p_qaf->hdmi_sink_channels == 8) {
+                        config.offload_info.channel_mask = config.channel_mask =
+                                AUDIO_CHANNEL_OUT_7POINT1;
+                    } else if (p_qaf->hdmi_sink_channels == 6) {
+                        config.offload_info.channel_mask = config.channel_mask =
+                                AUDIO_CHANNEL_OUT_5POINT1;
+                    } else {
+                        config.offload_info.channel_mask = config.channel_mask =
+                                AUDIO_CHANNEL_OUT_STEREO;
+                    }
                 }
 
                 devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
@@ -1366,13 +1494,21 @@
             if (qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]) {
                 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH]->stream.write(
                         (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD_MCH],
-                        buf,
-                        size);
+                        data_buffer_p,
+                        buffer_size);
             }
         }
         else {
             /* CASE 3: PCM output.
              */
+
+            /* If Media format was changed for this stream then need to re-create the stream. */
+            if (need_to_recreate_stream && qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
+                adev_close_output_stream((struct audio_hw_device *)p_qaf->adev,
+                                         (struct audio_stream_out *)(qaf_mod->stream_out[QAF_OUT_OFFLOAD]));
+                qaf_mod->stream_out[QAF_OUT_OFFLOAD] = NULL;
+            }
+
             bt_stream = audio_extn_bt_hal_get_output_stream(qaf_mod->bt_hdl);
             if (bt_stream != NULL) {
                 if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
@@ -1381,22 +1517,10 @@
                     qaf_mod->stream_out[QAF_OUT_OFFLOAD] = NULL;
                 }
 
-                audio_extn_bt_hal_out_write(p_qaf->bt_hdl, buf, size);
+                audio_extn_bt_hal_out_write(p_qaf->bt_hdl, data_buffer_p, buffer_size);
             } else if (NULL == qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
-                struct audio_config config;
                 audio_devices_t devices;
 
-                //TODO: need to update the actual sample rate.
-                config.sample_rate = config.offload_info.sample_rate =
-                        QAF_OUTPUT_SAMPLING_RATE;
-                config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
-                config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
-                config.offload_info.format = config.format = AUDIO_FORMAT_PCM_16_BIT;
-                //TODO: need to update the actual bit width.
-                config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-                //TODO: need to update the actual num channels.
-                config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
-
                 if (qaf_mod->stream_in[QAF_IN_MAIN])
                     devices = qaf_mod->stream_in[QAF_IN_MAIN]->devices;
                 else
@@ -1495,8 +1619,8 @@
             if (qaf_mod->stream_out[QAF_OUT_OFFLOAD]) {
                 ret = qaf_mod->stream_out[QAF_OUT_OFFLOAD]->stream.write(
                         (struct audio_stream_out *)qaf_mod->stream_out[QAF_OUT_OFFLOAD],
-                        buf,
-                        size);
+                        data_buffer_p,
+                        buffer_size);
             }
         }
         DEBUG_MSG_VV("Bytes written = %d", ret);
@@ -1543,8 +1667,7 @@
             DEBUG_MSG("sent main DRAIN_READY");
         }
     }
-#if 0
-    else if (event_id == AUDIO_MAIN_EOS_EVENT || event_id == AUDIO_ASSOC_EOS_EVENT) { //TODO: For DTS
+    else if (event_id == AUDIO_MAIN_EOS_EVENT || event_id == AUDIO_ASSOC_EOS_EVENT) {
         struct stream_out *out = NULL;
         bool *drain_received = NULL;
 
@@ -1564,7 +1687,6 @@
             DEBUG_MSG("sent DRAIN_READY");
         }
     }
-#endif
 
     pthread_mutex_unlock(&p_qaf->lock);
     return;
@@ -1598,7 +1720,10 @@
                                      (struct audio_stream_out *)(qaf_mod->stream_out[j]));
             qaf_mod->stream_out[j] = NULL;
         }
+        memset(&qaf_mod->out_stream_fmt[j], 0, sizeof(audio_qaf_media_format_t));
+        qaf_mod->is_media_fmt_changed[j] = false;
     }
+    qaf_mod->new_out_format_index = 0;
 
     DEBUG_MSG("Session Closed.");
 
@@ -1708,7 +1833,7 @@
         qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
                                              qaf_mod,
                                              &notify_event_callback,
-                                             AUDIO_DATA_EVENT);
+                                             AUDIO_DATA_EVENT_V2);
 
     set_hdmi_configuration_to_module();
 
@@ -2423,7 +2548,6 @@
 
             bool do_setparam = false;
             qaf_params = str_parms_create();
-#if 0 //TODO: Need to enable with DTS_M8 wrapper.
             if (platform_is_edid_supported_format(p_qaf->adev->platform, AUDIO_FORMAT_DTS)) {
                 do_setparam = true;
                 if (qaf_params) {
@@ -2432,7 +2556,6 @@
                                       AUDIO_QAF_PARAMETER_VALUE_REENCODE_DTS);
                 }
             }
-#endif
 
             if (do_setparam) {
                 if (p_qaf->qaf_msmd_enabled) {
@@ -2461,6 +2584,10 @@
         channels = platform_edid_get_max_channels(p_qaf->adev->platform);
 
         qaf_params = str_parms_create();
+
+        str_parms_add_str(qaf_params,
+                          AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                          AUDIO_QAF_PARAMETER_VALUE_PCM);
         switch (channels) {
             case 8:
                 DEBUG_MSG("Switching Qaf output to 7.1 channels");