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

Commit 643059a9 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "a2dp: fix race condition during a2dp suspend and reconfig"

parents 617e19b1 280ea745
Loading
Loading
Loading
Loading
+113 −116
Original line number Original line Diff line number Diff line
@@ -255,7 +255,7 @@ typedef enum {


// --- external function dependency ---
// --- external function dependency ---
fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
fp_check_a2dp_restore_t fp_check_a2dp_restore;
fp_check_a2dp_restore_t fp_check_a2dp_restore_l;


/* PCM config for ABR Feedback hostless front end */
/* PCM config for ABR Feedback hostless front end */
static struct pcm_config pcm_config_abr = {
static struct pcm_config pcm_config_abr = {
@@ -2872,7 +2872,9 @@ int a2dp_set_parameters(struct str_parms *parms, bool *reconfig)
#endif
#endif
    ret = str_parms_get_str(parms, "A2dpSuspended", value, sizeof(value));
    ret = str_parms_get_str(parms, "A2dpSuspended", value, sizeof(value));
    if (ret >= 0) {
    if (ret >= 0) {
         if (a2dp.bt_lib_source_handle) {
        if (a2dp.bt_lib_source_handle == NULL)
            goto param_handled;

        if ((!strncmp(value, "true", sizeof(value)))) {
        if ((!strncmp(value, "true", sizeof(value)))) {
            if (a2dp.a2dp_source_suspended) {
            if (a2dp.a2dp_source_suspended) {
                ALOGD("%s: A2DP is already suspended", __func__);
                ALOGD("%s: A2DP is already suspended", __func__);
@@ -2888,9 +2890,7 @@ int a2dp_set_parameters(struct str_parms *parms, bool *reconfig)
                    (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP ||
                    (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP ||
                     uc_info->out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
                     uc_info->out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
                     uc_info->out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)) {
                     uc_info->out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)) {
                        pthread_mutex_unlock(&a2dp.adev->lock);
                    fp_check_a2dp_restore_l(a2dp.adev, uc_info->stream.out, false);
                        fp_check_a2dp_restore(a2dp.adev, uc_info->stream.out, false);
                        pthread_mutex_lock(&a2dp.adev->lock);
                }
                }
            }
            }
            if (!a2dp.swb_configured)
            if (!a2dp.swb_configured)
@@ -2929,10 +2929,7 @@ int a2dp_set_parameters(struct str_parms *parms, bool *reconfig)
                uc_info = node_to_item(node, struct audio_usecase, list);
                uc_info = node_to_item(node, struct audio_usecase, list);
                if (uc_info->stream.out && uc_info->type == PCM_PLAYBACK &&
                if (uc_info->stream.out && uc_info->type == PCM_PLAYBACK &&
                    is_a2dp_out_device_type(&uc_info->stream.out->device_list)) {
                    is_a2dp_out_device_type(&uc_info->stream.out->device_list)) {
                        pthread_mutex_unlock(&a2dp.adev->lock);
                    fp_check_a2dp_restore_l(a2dp.adev, uc_info->stream.out, true);
                        fp_check_a2dp_restore(a2dp.adev, uc_info->stream.out, true);
                        pthread_mutex_lock(&a2dp.adev->lock);
                    }
                }
                }
            }
            }
        }
        }
@@ -3022,7 +3019,7 @@ void a2dp_init(void *adev,
  // init function pointers
  // init function pointers
  fp_platform_get_pcm_device_id =
  fp_platform_get_pcm_device_id =
              init_config.fp_platform_get_pcm_device_id;
              init_config.fp_platform_get_pcm_device_id;
  fp_check_a2dp_restore = init_config.fp_check_a2dp_restore;
  fp_check_a2dp_restore_l = init_config.fp_check_a2dp_restore_l;


  reset_a2dp_enc_config_params();
  reset_a2dp_enc_config_params();
  reset_a2dp_source_dec_config_params();
  reset_a2dp_source_dec_config_params();
+1 −1
Original line number Original line Diff line number Diff line
@@ -4750,7 +4750,7 @@ void audio_extn_a2dp_init(void *adev)
    if (a2dp_init) {
    if (a2dp_init) {
        a2dp_offload_init_config_t a2dp_init_config;
        a2dp_offload_init_config_t a2dp_init_config;
        a2dp_init_config.fp_platform_get_pcm_device_id = platform_get_pcm_device_id;
        a2dp_init_config.fp_platform_get_pcm_device_id = platform_get_pcm_device_id;
        a2dp_init_config.fp_check_a2dp_restore = check_a2dp_restore;
        a2dp_init_config.fp_check_a2dp_restore_l = check_a2dp_restore_l;


        a2dp_init(adev, a2dp_init_config);
        a2dp_init(adev, a2dp_init_config);
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -337,7 +337,7 @@ typedef int (*fp_check_a2dp_restore_t)(struct audio_device *,
                                       struct stream_out *, bool);
                                       struct stream_out *, bool);
struct a2dp_offload_init_config {
struct a2dp_offload_init_config {
    fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
    fp_platform_get_pcm_device_id_t fp_platform_get_pcm_device_id;
    fp_check_a2dp_restore_t fp_check_a2dp_restore;
    fp_check_a2dp_restore_t fp_check_a2dp_restore_l;
};
};
typedef struct a2dp_offload_init_config a2dp_offload_init_config_t;
typedef struct a2dp_offload_init_config a2dp_offload_init_config_t;
// END: A2DP_OFFLOAD FEATURE ====================================================
// END: A2DP_OFFLOAD FEATURE ====================================================
+79 −56
Original line number Original line Diff line number Diff line
@@ -516,7 +516,6 @@ static unsigned int audio_device_ref_count;
//cache last MBDRC cal step level
//cache last MBDRC cal step level
static int last_known_cal_step = -1 ;
static int last_known_cal_step = -1 ;


static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore);
static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_mmap_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_mmap_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_voip_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_voip_volume(struct audio_stream_out *stream, float left, float right);
@@ -3383,7 +3382,7 @@ static int send_offload_cmd_l(struct stream_out* out, int command)
    return 0;
    return 0;
}
}


/* must be called iwth out->lock locked */
/* must be called with out->lock and latch lock */
static void stop_compressed_output_l(struct stream_out *out)
static void stop_compressed_output_l(struct stream_out *out)
{
{
    out->offload_state = OFFLOAD_STATE_IDLE;
    out->offload_state = OFFLOAD_STATE_IDLE;
@@ -3644,9 +3643,11 @@ static int create_offload_callback_thread(struct stream_out *out)
static int destroy_offload_callback_thread(struct stream_out *out)
static int destroy_offload_callback_thread(struct stream_out *out)
{
{
    lock_output_stream(out);
    lock_output_stream(out);
    pthread_mutex_lock(&out->latch_lock);
    stop_compressed_output_l(out);
    stop_compressed_output_l(out);
    send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
    send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);


    pthread_mutex_unlock(&out->latch_lock);
    pthread_mutex_unlock(&out->lock);
    pthread_mutex_unlock(&out->lock);
    pthread_join(out->offload_thread, (void **) NULL);
    pthread_join(out->offload_thread, (void **) NULL);
    pthread_cond_destroy(&out->offload_cond);
    pthread_cond_destroy(&out->offload_cond);
@@ -3721,6 +3722,9 @@ static int stop_output_stream(struct stream_out *out)


    list_remove(&uc_info->list);
    list_remove(&uc_info->list);
    out->started = 0;
    out->started = 0;
    pthread_mutex_lock(&out->latch_lock);
    out->muted = false;
    pthread_mutex_unlock(&out->latch_lock);
    if (is_offload_usecase(out->usecase) &&
    if (is_offload_usecase(out->usecase) &&
        (audio_extn_passthru_is_passthrough_stream(out))) {
        (audio_extn_passthru_is_passthrough_stream(out))) {
        ALOGV("Disable passthrough , reset mixer to pcm");
        ALOGV("Disable passthrough , reset mixer to pcm");
@@ -4541,8 +4545,11 @@ static int out_standby(struct audio_stream *stream)
        if (adev->adm_deregister_stream)
        if (adev->adm_deregister_stream)
            adev->adm_deregister_stream(adev->adm_data, out->handle);
            adev->adm_deregister_stream(adev->adm_data, out->handle);


        if (is_offload_usecase(out->usecase))
        if (is_offload_usecase(out->usecase)) {
            pthread_mutex_lock(&out->latch_lock);
            stop_compressed_output_l(out);
            stop_compressed_output_l(out);
            pthread_mutex_unlock(&out->latch_lock);
        }


        pthread_mutex_lock(&adev->lock);
        pthread_mutex_lock(&adev->lock);
        out->standby = true;
        out->standby = true;
@@ -4616,7 +4623,9 @@ static int out_on_error(struct audio_stream *stream)
    // is needed e.g. when SSR happens within compress_open
    // is needed e.g. when SSR happens within compress_open
    // since the stream is active, offload_callback_thread is also active.
    // since the stream is active, offload_callback_thread is also active.
    if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
    if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
        pthread_mutex_lock(&out->latch_lock);
        stop_compressed_output_l(out);
        stop_compressed_output_l(out);
        pthread_mutex_unlock(&out->latch_lock);
    }
    }
    pthread_mutex_unlock(&out->lock);
    pthread_mutex_unlock(&out->lock);


@@ -4654,8 +4663,11 @@ int out_standby_l(struct audio_stream *stream)
        if (adev->adm_deregister_stream)
        if (adev->adm_deregister_stream)
            adev->adm_deregister_stream(adev->adm_data, out->handle);
            adev->adm_deregister_stream(adev->adm_data, out->handle);


        if (is_offload_usecase(out->usecase))
        if (is_offload_usecase(out->usecase)) {
            pthread_mutex_lock(&out->latch_lock);
            stop_compressed_output_l(out);
            stop_compressed_output_l(out);
            pthread_mutex_unlock(&out->latch_lock);
        }


        out->standby = true;
        out->standby = true;
        if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
        if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
@@ -5002,12 +5014,13 @@ int route_output_stream(struct stream_out *out,
                audio_extn_perf_lock_release(&adev->perf_lock_handle);
                audio_extn_perf_lock_release(&adev->perf_lock_handle);
            }
            }
            if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
            if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
                 out->a2dp_compress_mute &&
                 (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready())) {
                 (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready())) {
                pthread_mutex_lock(&out->compr_mute_lock);
                pthread_mutex_lock(&out->latch_lock);
                if (out->a2dp_compress_mute) {
                    out->a2dp_compress_mute = false;
                    out->a2dp_compress_mute = false;
                    out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
                    out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
                pthread_mutex_unlock(&out->compr_mute_lock);
                }
                pthread_mutex_unlock(&out->latch_lock);
            } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
            } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
                out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
                out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
            }
            }
@@ -5562,7 +5575,9 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
    ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
    ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
    if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
    if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
        /* only take left channel into account: the API is for stereo anyway */
        /* only take left channel into account: the API is for stereo anyway */
        pthread_mutex_lock(&out->latch_lock);
        out->muted = (left == 0.0f);
        out->muted = (left == 0.0f);
        pthread_mutex_unlock(&out->latch_lock);
        return 0;
        return 0;
    } else if (is_offload_usecase(out->usecase)) {
    } else if (is_offload_usecase(out->usecase)) {
        if (audio_extn_passthru_is_passthrough_stream(out)) {
        if (audio_extn_passthru_is_passthrough_stream(out)) {
@@ -5599,18 +5614,20 @@ static int out_set_volume(struct audio_stream_out *stream, float left,
                    out->volume_r = out_ctxt->output->volume_r;
                    out->volume_r = out_ctxt->output->volume_r;
                }
                }
            }
            }
            pthread_mutex_lock(&out->latch_lock);
            if (!out->a2dp_compress_mute) {
            if (!out->a2dp_compress_mute) {
                ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
                ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
            }
            }
            pthread_mutex_unlock(&out->latch_lock);
            return ret;
            return ret;
        } else {
        } else {
            pthread_mutex_lock(&out->compr_mute_lock);
            pthread_mutex_lock(&out->latch_lock);
            ALOGV("%s: compress mute %d", __func__, out->a2dp_compress_mute);
            ALOGV("%s: compress mute %d", __func__, out->a2dp_compress_mute);
            if (!out->a2dp_compress_mute)
            if (!out->a2dp_compress_mute)
                ret = out_set_compr_volume(stream, left, right);
                ret = out_set_compr_volume(stream, left, right);
            out->volume_l = left;
            out->volume_l = left;
            out->volume_r = right;
            out->volume_r = right;
            pthread_mutex_unlock(&out->compr_mute_lock);
            pthread_mutex_unlock(&out->latch_lock);
            return ret;
            return ret;
        }
        }
    } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
    } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
@@ -6021,7 +6038,9 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
            }
            }
            audio_extn_dts_eagle_fade(adev, true, out);
            audio_extn_dts_eagle_fade(adev, true, out);
            out->playback_started = 1;
            out->playback_started = 1;
            pthread_mutex_lock(&out->latch_lock);
            out->offload_state = OFFLOAD_STATE_PLAYING;
            out->offload_state = OFFLOAD_STATE_PLAYING;
            pthread_mutex_unlock(&out->latch_lock);


            audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
            audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
                                                     popcount(out->channel_mask),
                                                     popcount(out->channel_mask),
@@ -6033,8 +6052,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
    } else {
    } else {
        if (out->pcm) {
        if (out->pcm) {
            size_t bytes_to_write = bytes;
            size_t bytes_to_write = bytes;
            pthread_mutex_lock(&out->latch_lock);
            if (out->muted)
            if (out->muted)
                memset((void *)buffer, 0, bytes);
                memset((void *)buffer, 0, bytes);
            pthread_mutex_unlock(&out->latch_lock);
            ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
            ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
                     __func__, frames, frame_size, bytes_to_write);
                     __func__, frames, frame_size, bytes_to_write);


@@ -6408,6 +6429,7 @@ static int out_pause(struct audio_stream_out* stream)
        ALOGD("copl(%p):pause compress driver", out);
        ALOGD("copl(%p):pause compress driver", out);
        status = -ENODATA;
        status = -ENODATA;
        lock_output_stream(out);
        lock_output_stream(out);
        pthread_mutex_lock(&out->latch_lock);
        if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
        if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
            if (out->card_status != CARD_STATUS_OFFLINE)
            if (out->card_status != CARD_STATUS_OFFLINE)
                status = compress_pause(out->compr);
                status = compress_pause(out->compr);
@@ -6424,6 +6446,7 @@ static int out_pause(struct audio_stream_out* stream)
                                                 out->sample_rate, popcount(out->channel_mask),
                                                 out->sample_rate, popcount(out->channel_mask),
                                                 0);
                                                 0);
        }
        }
        pthread_mutex_unlock(&out->latch_lock);
        pthread_mutex_unlock(&out->lock);
        pthread_mutex_unlock(&out->lock);
    }
    }
    return status;
    return status;
@@ -6438,6 +6461,7 @@ static int out_resume(struct audio_stream_out* stream)
        ALOGD("copl(%p):resume compress driver", out);
        ALOGD("copl(%p):resume compress driver", out);
        status = -ENODATA;
        status = -ENODATA;
        lock_output_stream(out);
        lock_output_stream(out);
        pthread_mutex_lock(&out->latch_lock);
        if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
        if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
            if (out->card_status != CARD_STATUS_OFFLINE) {
            if (out->card_status != CARD_STATUS_OFFLINE) {
                status = compress_resume(out->compr);
                status = compress_resume(out->compr);
@@ -6449,6 +6473,7 @@ static int out_resume(struct audio_stream_out* stream)
            audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
            audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
                                                     popcount(out->channel_mask), 1);
                                                     popcount(out->channel_mask), 1);
        }
        }
        pthread_mutex_unlock(&out->latch_lock);
        pthread_mutex_unlock(&out->lock);
        pthread_mutex_unlock(&out->lock);
    }
    }
    return status;
    return status;
@@ -6477,12 +6502,14 @@ static int out_flush(struct audio_stream_out* stream)
    if (is_offload_usecase(out->usecase)) {
    if (is_offload_usecase(out->usecase)) {
        ALOGD("copl(%p):calling compress flush", out);
        ALOGD("copl(%p):calling compress flush", out);
        lock_output_stream(out);
        lock_output_stream(out);
        pthread_mutex_lock(&out->latch_lock);
        if (out->offload_state == OFFLOAD_STATE_PAUSED) {
        if (out->offload_state == OFFLOAD_STATE_PAUSED) {
            stop_compressed_output_l(out);
            stop_compressed_output_l(out);
        } else {
        } else {
            ALOGW("%s called in invalid state %d", __func__, out->offload_state);
            ALOGW("%s called in invalid state %d", __func__, out->offload_state);
        }
        }
        out->written = 0;
        out->written = 0;
        pthread_mutex_unlock(&out->latch_lock);
        pthread_mutex_unlock(&out->lock);
        pthread_mutex_unlock(&out->lock);
        ALOGD("copl(%p):out of compress flush", out);
        ALOGD("copl(%p):out of compress flush", out);
        return 0;
        return 0;
@@ -7757,7 +7784,7 @@ int adev_open_output_stream(struct audio_hw_device *dev,


    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&out->compr_mute_lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&out->latch_lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&out->position_query_lock, (const pthread_mutexattr_t *) NULL);
    pthread_mutex_init(&out->position_query_lock, (const pthread_mutexattr_t *) NULL);
    pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
    pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);


@@ -8672,6 +8699,9 @@ void adev_close_output_stream(struct audio_hw_device *dev __unused,


    pthread_cond_destroy(&out->cond);
    pthread_cond_destroy(&out->cond);
    pthread_mutex_destroy(&out->lock);
    pthread_mutex_destroy(&out->lock);
    pthread_mutex_destroy(&out->pre_lock);
    pthread_mutex_destroy(&out->latch_lock);
    pthread_mutex_destroy(&out->position_query_lock);


    pthread_mutex_lock(&adev->lock);
    pthread_mutex_lock(&adev->lock);
    streams_output_ctxt_t *out_ctxt = out_get_stream(adev, out->handle);
    streams_output_ctxt_t *out_ctxt = out_get_stream(adev, out->handle);
@@ -8895,31 +8925,31 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)


            if (is_a2dp_out_device_type(&usecase->device_list)) {
            if (is_a2dp_out_device_type(&usecase->device_list)) {
                ALOGD("reconfigure a2dp... forcing device switch");
                ALOGD("reconfigure a2dp... forcing device switch");
                pthread_mutex_unlock(&adev->lock);
                lock_output_stream(usecase->stream.out);
                pthread_mutex_lock(&adev->lock);
                audio_extn_a2dp_set_handoff_mode(true);
                audio_extn_a2dp_set_handoff_mode(true);
                ALOGD("Switching to speaker and muting the stream before select_devices");
                ALOGD("Switching to speaker and muting the stream before select_devices");
                check_a2dp_restore_l(adev, usecase->stream.out, false);
                check_a2dp_restore_l(adev, usecase->stream.out, false);
                //force device switch to re configure encoder
                //force device switch to re configure encoder
                select_devices(adev, usecase->id);
                select_devices(adev, usecase->id);
                ALOGD("Unmuting the stream after select_devices");
                ALOGD("Unmuting the stream after select_devices");
                pthread_mutex_lock(&usecase->stream.out->latch_lock);
                usecase->stream.out->a2dp_compress_mute = false;
                usecase->stream.out->a2dp_compress_mute = false;
                out_set_compr_volume(&usecase->stream.out->stream, usecase->stream.out->volume_l, usecase->stream.out->volume_r);
                out_set_compr_volume(&usecase->stream.out->stream,
                                     usecase->stream.out->volume_l,
                                     usecase->stream.out->volume_r);
                pthread_mutex_unlock(&usecase->stream.out->latch_lock);
                audio_extn_a2dp_set_handoff_mode(false);
                audio_extn_a2dp_set_handoff_mode(false);
                pthread_mutex_unlock(&usecase->stream.out->lock);
                break;
                break;
            } else if ((usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
            } else if (usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                        usecase->stream.out->a2dp_compress_mute) {
                pthread_mutex_lock(&usecase->stream.out->latch_lock);
                pthread_mutex_unlock(&adev->lock);
                if (usecase->stream.out->a2dp_compress_mute) {
                lock_output_stream(usecase->stream.out);
                    pthread_mutex_unlock(&usecase->stream.out->latch_lock);
                pthread_mutex_lock(&adev->lock);
                    reassign_device_list(&usecase->stream.out->device_list,
                    reassign_device_list(&usecase->stream.out->device_list,
                                         AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
                                         AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
                    check_a2dp_restore_l(adev, usecase->stream.out, true);
                    check_a2dp_restore_l(adev, usecase->stream.out, true);
                pthread_mutex_unlock(&usecase->stream.out->lock);
                    break;
                    break;
                }
                }
                pthread_mutex_unlock(&usecase->stream.out->latch_lock);
            }
        }
        }
    }
    }


@@ -9745,6 +9775,9 @@ static void adev_close_input_stream(struct audio_hw_device *dev,
    } else
    } else
        in_standby(&stream->common);
        in_standby(&stream->common);


    pthread_mutex_destroy(&in->lock);
    pthread_mutex_destroy(&in->pre_lock);

    pthread_mutex_lock(&adev->lock);
    pthread_mutex_lock(&adev->lock);
    if (in->usecase == USECASE_AUDIO_RECORD) {
    if (in->usecase == USECASE_AUDIO_RECORD) {
        adev->pcm_record_uc_state = 0;
        adev->pcm_record_uc_state = 0;
@@ -10349,8 +10382,8 @@ static void adev_snd_mon_cb(void *cookie, struct str_parms *parms)
    return;
    return;
}
}


/* out and adev lock held */
/* adev lock held */
static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore)
int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore)
{
{
    struct audio_usecase *uc_info;
    struct audio_usecase *uc_info;
    float left_p;
    float left_p;
@@ -10369,23 +10402,26 @@ static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *ou
          out->usecase, use_case_table[out->usecase]);
          out->usecase, use_case_table[out->usecase]);


    if (restore) {
    if (restore) {
        pthread_mutex_lock(&out->latch_lock);
        // restore A2DP device for active usecases and unmute if required
        // restore A2DP device for active usecases and unmute if required
        if (is_a2dp_out_device_type(&out->device_list)) {
        if (is_a2dp_out_device_type(&out->device_list)) {
            ALOGD("%s: restoring A2dp and unmuting stream", __func__);
            ALOGD("%s: restoring A2dp and unmuting stream", __func__);
            if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
            if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
                select_devices(adev, uc_info->id);
                select_devices(adev, uc_info->id);
            pthread_mutex_lock(&out->compr_mute_lock);
            if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
            if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
                (out->a2dp_compress_mute) && (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
                (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
                if (out->a2dp_compress_mute) {
                    out->a2dp_compress_mute = false;
                    out->a2dp_compress_mute = false;
                    out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
                    out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
                }
                }
            pthread_mutex_unlock(&out->compr_mute_lock);
            }
            }
        }
        out->muted = false;
        pthread_mutex_unlock(&out->latch_lock);
    } else {
    } else {
        pthread_mutex_lock(&out->latch_lock);
        if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
        if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
            // mute compress stream if suspended
            // mute compress stream if suspended
            pthread_mutex_lock(&out->compr_mute_lock);
            if (!out->a2dp_compress_mute && !out->standby) {
            if (!out->a2dp_compress_mute && !out->standby) {
                ALOGD("%s: selecting speaker and muting stream", __func__);
                ALOGD("%s: selecting speaker and muting stream", __func__);
                assign_devices(&devices, &out->device_list);
                assign_devices(&devices, &out->device_list);
@@ -10403,31 +10439,18 @@ static int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *ou
                out->volume_l = left_p;
                out->volume_l = left_p;
                out->volume_r = right_p;
                out->volume_r = right_p;
            }
            }
            pthread_mutex_unlock(&out->compr_mute_lock);
        } else {
        } else {
            // tear down a2dp path for non offloaded streams
            // mute for non offloaded streams
            if (audio_extn_a2dp_source_is_suspended())
            if (audio_extn_a2dp_source_is_suspended()) {
                out_standby_l(&out->stream.common);
                out->muted = true;
            }
        }
        }
        pthread_mutex_unlock(&out->latch_lock);
    }
    }
    ALOGV("%s: exit", __func__);
    ALOGV("%s: exit", __func__);
    return 0;
    return 0;
}
}


int check_a2dp_restore(struct audio_device *adev, struct stream_out *out, bool restore)
{
    int ret = 0;

    lock_output_stream(out);
    pthread_mutex_lock(&adev->lock);

    ret = check_a2dp_restore_l(adev, out, restore);

    pthread_mutex_unlock(&adev->lock);
    pthread_mutex_unlock(&out->lock);
    return ret;
}

void adev_on_battery_status_changed(bool charging)
void adev_on_battery_status_changed(bool charging)
{
{
    pthread_mutex_lock(&adev->lock);
    pthread_mutex_lock(&adev->lock);
+8 −3
Original line number Original line Diff line number Diff line
@@ -364,13 +364,18 @@ struct stream_inout {
    stream_callback_t client_callback;
    stream_callback_t client_callback;
    void *client_cookie;
    void *client_cookie;
};
};

struct stream_out {
struct stream_out {
    struct audio_stream_out stream;
    struct audio_stream_out stream;
    pthread_mutex_t lock; /* see note below on mutex acquisition order */
    pthread_mutex_t lock; /* see note below on mutex acquisition order */
    pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by playback thread */
    pthread_mutex_t pre_lock; /* acquire before lock to avoid DOS by playback thread */
    pthread_mutex_t compr_mute_lock; /* acquire before setting compress volume */
    pthread_mutex_t position_query_lock; /* acquire before updating/getting position of track offload*/
    pthread_cond_t  cond;
    pthread_cond_t  cond;
    /* stream_out->lock is of large granularity, and can only be held before device lock
     * latch is a supplemetary lock to protect certain fields of out stream and
     * it can be held after device lock
     */
    pthread_mutex_t latch_lock;
    pthread_mutex_t position_query_lock; /* sychronize frame written */
    struct pcm_config config;
    struct pcm_config config;
    struct compr_config compr_config;
    struct compr_config compr_config;
    struct pcm *pcm;
    struct pcm *pcm;
@@ -780,7 +785,7 @@ int pcm_ioctl(struct pcm *pcm, int request, ...);
audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
                                                 usecase_type_t type);
                                                 usecase_type_t type);


int check_a2dp_restore(struct audio_device *adev, struct stream_out *out, bool restore);
int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore);


int adev_open_output_stream(struct audio_hw_device *dev,
int adev_open_output_stream(struct audio_hw_device *dev,
                            audio_io_handle_t handle,
                            audio_io_handle_t handle,