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,
¬ify_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");