Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0345a209 authored by Harsh Bansal's avatar Harsh Bansal Committed by Garmond Leung
Browse files

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
parent ac4a7495
Loading
Loading
Loading
Loading
+37 −4
Original line number Diff line number Diff line
@@ -354,6 +354,22 @@ static bool is_dual_main_active(struct qaf_module* qaf_mod)
   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 @@ static int qaf_module_write_input_buffer(struct stream_out *out, const void *buf
        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 @@ static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t typ
{
    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 @@ static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t typ
                    (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 @@ static void notify_event_callback(audio_session_handle_t session_handle /*__unus
    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 @@ static void notify_event_callback(audio_session_handle_t session_handle /*__unus
               || 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 @@ static void notify_event_callback(audio_session_handle_t session_handle /*__unus
            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 @@ static int qaf_stream_close(struct stream_out *out)
        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 @@ static int qaf_stream_close(struct stream_out *out)
    //If all streams are closed then close the session.
    qaf_session_close(qaf_mod);

    pthread_mutex_unlock(&p_qaf->lock);

    DEBUG_MSG();
    return ret;
}
+7 −3
Original line number Diff line number Diff line
@@ -322,6 +322,7 @@ int async_callback(qahw_stream_callback_event_t event, void *param,
    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(&params->drain_lock);
        params->drain_received = true;
        pthread_cond_signal(&params->drain_cond);
        pthread_mutex_unlock(&params->drain_lock);
        break;
@@ -780,12 +781,15 @@ void *start_stream_playback (void* stream_data)
            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(&params->drain_lock);
                    params->drain_received = false;
                    qahw_out_drain(params->out_handle, QAHW_DRAIN_ALL);
                    if(!params->drain_received) {
                        pthread_mutex_lock(&params->drain_lock);
                        pthread_cond_wait(&params->drain_cond, &params->drain_lock);
                    fprintf(log_file, "stream %d: out of compress drain\n", params->stream_index);
                        pthread_mutex_unlock(&params->drain_lock);
                    }
                    fprintf(log_file, "stream %d: out of compress drain\n", params->stream_index);
                }
                /*
                 * Caution: Below ADL log shouldnt be altered without notifying
                 * automation APT since it used for automation testing
+1 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ typedef struct {
    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;