hal: QAF: Fix to resolve hang in dual AAC mix case
-Hang, because Drain-Ready not sent for Assoc-AAC
--Fixed by adding Drain-Ready event for Assoc-AAC
-Hang, because data is written on assoc stream
event when no main or pcm stream is active. Module will
not process the associated data alone
--Fixed by dropping the data on assoc stream if no main or
pcm stream is active
-Hang, because EOS is not raised by module if only
assoc stream is running. Module will keep on waiting for
main or pcm data
--Fixed by sending the Drain-Ready event immediately on assoc
stream if no main or pcm stream is active
-Hang, due to race condition when main and associated
streams are closed simulteneously
--Fixed by protecting with lock.
-Hang in test app if drain ready event is received synchronously
--Fixed by adding a flag to indicated drain-ready event.
Change-Id: I19c0de43657a8de8845b440f8c18f03149e549e5
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 7a1c65f..9c57b2c 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -354,6 +354,22 @@
return (qaf_mod->stream_in[QAF_IN_MAIN] && qaf_mod->stream_in[QAF_IN_MAIN_2]);
}
+//Checks if any main or pcm stream is running in the session.
+static bool is_any_stream_running(struct qaf_module* qaf_mod)
+{
+ //Not checking associated stream.
+ struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
+ struct stream_out *out_pcm = qaf_mod->stream_in[QAF_IN_PCM];
+ struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
+
+ if ((out == NULL || (out != NULL && check_stream_state(out, STOPPED)))
+ && (out_main2 == NULL || (out_main2 != NULL && check_stream_state(out_main2, STOPPED)))
+ && (out_pcm == NULL || (out_pcm != NULL && check_stream_state(out_pcm, STOPPED)))) {
+ return false;
+ }
+ return true;
+}
+
/* Gets the pcm output buffer size(in samples) for the mm module. */
static uint32_t get_pcm_output_buffer_size_samples(struct qaf_module *qaf_mod)
{
@@ -713,6 +729,10 @@
return ret;
}
+ //If data received on associated stream when all other stream are stopped then drop the data.
+ if (out == qaf_mod->stream_in[QAF_IN_ASSOC] && !is_any_stream_running(qaf_mod))
+ return bytes;
+
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);
@@ -1049,6 +1069,9 @@
{
struct stream_out *out = (struct stream_out *)stream;
int status = 0;
+ struct qaf_module *qaf_mod = NULL;
+
+ qaf_mod = get_qaf_module_for_input_stream(out);
DEBUG_MSG("Output Stream %p", out);
lock_output_stream(out);
@@ -1062,11 +1085,11 @@
(struct audio_stream_out *)p_qaf->passthrough_out, type);
}
pthread_mutex_unlock(&p_qaf->lock);
- } else if (check_stream_state(out, STOPPED)) {
+ } else if (!is_any_stream_running(qaf_mod)) {
//If stream is already stopped then send the drain ready.
out->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->client_cookie);
+ set_stream_state(out, STOPPED);
} else {
-
//Drain the module input stream.
/* Stream stop will trigger EOS and on EOS_EVENT received
from callback DRAIN_READY command is sent */
@@ -1244,6 +1267,8 @@
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);
/* Default config initialization. */
@@ -1674,7 +1699,9 @@
|| event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
|| event_id == AUDIO_EOS_MAIN_AAC_EVENT
|| event_id == AUDIO_EOS_MAIN_AC4_EVENT
- || event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT) {
+ || event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
+ || event_id == AUDIO_EOS_ASSOC_AAC_EVENT
+ || event_id == AUDIO_EOS_ASSOC_AC4_EVENT) {
struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
struct stream_out *out_pcm = qaf_mod->stream_in[QAF_IN_PCM];
struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
@@ -1693,7 +1720,9 @@
set_stream_state(out_pcm, STOPPED);
unlock_output_stream(out_pcm);
DEBUG_MSG("sent pcm DRAIN_READY");
- } else if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
+ } else if ( (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
+ || event_id == AUDIO_EOS_ASSOC_AAC_EVENT
+ || event_id == AUDIO_EOS_ASSOC_AC4_EVENT)
&& (out_assoc != NULL)
&& (check_stream_state(out_assoc, STOPPING))) {
@@ -1799,6 +1828,8 @@
return -EINVAL;
}
+ pthread_mutex_lock(&p_qaf->lock);
+
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));
@@ -1813,6 +1844,8 @@
//If all streams are closed then close the session.
qaf_session_close(qaf_mod);
+ pthread_mutex_unlock(&p_qaf->lock);
+
DEBUG_MSG();
return ret;
}
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index 0fada71..f7f9e34 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -322,6 +322,7 @@
case QAHW_STREAM_CBK_EVENT_DRAIN_READY:
fprintf(log_file, "stream %d: received event - QAHW_STREAM_CBK_EVENT_DRAIN_READY\n", params->stream_index);
pthread_mutex_lock(¶ms->drain_lock);
+ params->drain_received = true;
pthread_cond_signal(¶ms->drain_cond);
pthread_mutex_unlock(¶ms->drain_lock);
break;
@@ -780,11 +781,14 @@
if ((!read_complete_file && (bytes_to_read <= 0)) || (bytes_read <= 0)) {
fprintf(log_file, "stream %d: end of file\n", params->stream_index);
if (is_offload) {
- pthread_mutex_lock(¶ms->drain_lock);
+ params->drain_received = false;
qahw_out_drain(params->out_handle, QAHW_DRAIN_ALL);
- pthread_cond_wait(¶ms->drain_cond, ¶ms->drain_lock);
+ if(!params->drain_received) {
+ pthread_mutex_lock(¶ms->drain_lock);
+ pthread_cond_wait(¶ms->drain_cond, ¶ms->drain_lock);
+ pthread_mutex_unlock(¶ms->drain_lock);
+ }
fprintf(log_file, "stream %d: out of compress drain\n", params->stream_index);
- pthread_mutex_unlock(¶ms->drain_lock);
}
/*
* Caution: Below ADL log shouldnt be altered without notifying
diff --git a/qahw_api/test/qahw_playback_test.h b/qahw_api/test/qahw_playback_test.h
index 1f524b9..3ec8f25 100644
--- a/qahw_api/test/qahw_playback_test.h
+++ b/qahw_api/test/qahw_playback_test.h
@@ -134,6 +134,7 @@
pthread_mutex_t write_lock;
pthread_cond_t drain_cond;
pthread_mutex_t drain_lock;
+ bool drain_received;
bool interactive_strm;
qahw_mix_matrix_params_t mm_params_pan_scale;
qahw_mix_matrix_params_t mm_params_downmix;