diff options
-rw-r--r-- | audio/hal/audio_hw.c | 103 | ||||
-rw-r--r-- | audio/hal/audio_hw.h | 8 |
2 files changed, 76 insertions, 35 deletions
diff --git a/audio/hal/audio_hw.c b/audio/hal/audio_hw.c index edca595..bacfcac 100644 --- a/audio/hal/audio_hw.c +++ b/audio/hal/audio_hw.c @@ -895,10 +895,6 @@ static int select_devices(struct audio_device *adev, } -/** - * NOTE: when multiple mutexes have to be acquired, always respect the following order: - * hw device > in stream > out stream - */ static ssize_t read_frames(struct stream_in *in, void *buffer, ssize_t frames); static int do_in_standby_l(struct stream_in *in); @@ -2482,6 +2478,7 @@ static int stop_voice_call(struct audio_device *adev) return 0; } +/* always called with adev lock held */ static int start_voice_call(struct audio_device *adev) { struct audio_usecase *uc_info; @@ -2648,13 +2645,13 @@ static int out_standby(struct audio_stream *stream) ALOGV("%s: enter: usecase(%d: %s)", __func__, out->usecase, use_case_table[out->usecase]); - pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&out->lock); if (!out->standby) { + pthread_mutex_lock(&adev->lock); do_out_standby_l(out); + pthread_mutex_unlock(&adev->lock); } pthread_mutex_unlock(&out->lock); - pthread_mutex_unlock(&adev->lock); ALOGV("%s: exit", __func__); return 0; } @@ -2714,7 +2711,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) struct pcm_device *pcm_device; struct pcm_device_profile *pcm_profile; #ifdef PREPROCESSING_ENABLED - bool force_input_standby = false; + struct stream_in *in = NULL; /* if non-NULL, then force input to standby */ #endif ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s out->devices(%d) adev->mode(%d)", @@ -2723,8 +2720,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); if (ret >= 0) { val = atoi(value); - pthread_mutex_lock(&adev->lock); + pthread_mutex_lock(&adev->lock_inputs); pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&adev->lock); #ifdef PREPROCESSING_ENABLED if (((int)out->devices != val) && (val != 0) && (!out->standby) && (out->usecase == USECASE_AUDIO_PLAYBACK)) { @@ -2733,7 +2731,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) * - because a change in output device may change mic settings */ if (adev->active_input && (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION || adev->active_input->source == AUDIO_SOURCE_MIC)) { - force_input_standby = true; + in = adev->active_input; } } #endif @@ -2774,16 +2772,20 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) (out == adev->primary_output)) { stop_voice_call(adev); } + pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&out->lock); #ifdef PREPROCESSING_ENABLED - if (force_input_standby) { - struct stream_in *in = adev->active_input; + if (in) { + /* The lock on adev->lock_inputs prevents input stream from being closed */ pthread_mutex_lock(&in->lock); + pthread_mutex_lock(&adev->lock); + LOG_ALWAYS_FATAL_IF(in != adev->active_input); do_in_standby_l(in); + pthread_mutex_unlock(&adev->lock); pthread_mutex_unlock(&in->lock); } #endif - pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&adev->lock_inputs); } if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { @@ -2895,16 +2897,29 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, #ifdef PREPROCESSING_ENABLED size_t in_frames = bytes / frame_size; size_t out_frames = in_frames; - bool force_input_standby = false; + struct stream_in *in = NULL; #endif - pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&out->lock); if (out->standby) { +#ifdef PREPROCESSING_ENABLED + pthread_mutex_unlock(&out->lock); + /* Prevent input stream from being closed */ + pthread_mutex_lock(&adev->lock_inputs); + pthread_mutex_lock(&out->lock); + if (!out->standby) { + pthread_mutex_unlock(&adev->lock_inputs); + goto false_alarm; + } +#endif + pthread_mutex_lock(&adev->lock); ret = start_output_stream(out); /* ToDo: If use case is compress offload should return 0 */ if (ret != 0) { pthread_mutex_unlock(&adev->lock); +#ifdef PREPROCESSING_ENABLED + pthread_mutex_unlock(&adev->lock_inputs); +#endif goto exit; } out->standby = false; @@ -2914,12 +2929,19 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, if (adev->active_input && (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION || adev->active_input->source == AUDIO_SOURCE_MIC)) { - force_input_standby = true; + in = adev->active_input; ALOGV("%s: enter:) force_input_standby true", __func__); } #endif + pthread_mutex_unlock(&adev->lock); +#ifdef PREPROCESSING_ENABLED + if (!in) { + /* Leave mutex locked iff in != NULL */ + pthread_mutex_unlock(&adev->lock_inputs); + } +#endif } - pthread_mutex_unlock(&adev->lock); +false_alarm: if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) { ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes); @@ -2940,6 +2962,12 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, out->offload_state = OFFLOAD_STATE_PLAYING; } pthread_mutex_unlock(&out->lock); +#ifdef PREPROCESSING_ENABLED + if (in) { + /* This mutex was left locked iff in != NULL */ + pthread_mutex_unlock(&adev->lock_inputs); + } +#endif return ret; } else { if (out->muted) @@ -3018,15 +3046,16 @@ exit: } #ifdef PREPROCESSING_ENABLED - if (force_input_standby) { + if (in) { + /* The lock on adev->lock_inputs prevents input stream from being closed */ + pthread_mutex_lock(&in->lock); pthread_mutex_lock(&adev->lock); - if (adev->active_input) { - struct stream_in *in = adev->active_input; - pthread_mutex_lock(&in->lock); - do_in_standby_l(in); - pthread_mutex_unlock(&in->lock); - } + LOG_ALWAYS_FATAL_IF(in != adev->active_input); + do_in_standby_l(in); pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&in->lock); + /* This mutex was left locked iff in != NULL */ + pthread_mutex_unlock(&adev->lock_inputs); } #endif @@ -3265,6 +3294,7 @@ static int in_close_pcm_devices(struct stream_in *in) } +/* must be called with stream and hw device mutex locked */ static int do_in_standby_l(struct stream_in *in) { int status = 0; @@ -3312,13 +3342,13 @@ static int in_standby(struct audio_stream *stream) struct audio_device *adev = in->dev; int status = 0; ALOGV("%s: enter", __func__); - pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&in->lock); if (!in->standby) { + pthread_mutex_lock(&adev->lock); status = do_in_standby_l(in); + pthread_mutex_unlock(&adev->lock); } pthread_mutex_unlock(&in->lock); - pthread_mutex_unlock(&adev->lock); ALOGV("%s: exit: status(%d)", __func__, status); return status; } @@ -3350,8 +3380,8 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value)); - pthread_mutex_lock(&adev->lock); pthread_mutex_lock(&in->lock); + pthread_mutex_lock(&adev->lock); if (ret >= 0) { val = atoi(value); /* no audio source uses val == 0 */ @@ -3389,8 +3419,8 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) } } } - pthread_mutex_unlock(&in->lock); pthread_mutex_unlock(&adev->lock); + pthread_mutex_unlock(&in->lock); str_parms_destroy(parms); ALOGV("%s: exit: status(%d)", __func__, ret); return ret; @@ -3439,17 +3469,18 @@ static ssize_t in_read(struct audio_stream_in *stream, void *buffer, size_t frames_rq = bytes / audio_stream_in_frame_size(stream); - pthread_mutex_lock(&adev->lock); + /* no need to acquire adev->lock_inputs because API contract prevents a close */ pthread_mutex_lock(&in->lock); if (in->standby) { + pthread_mutex_lock(&adev->lock); ret = start_input_stream(in); if (ret != 0) { pthread_mutex_unlock(&adev->lock); goto exit; } in->standby = 0; + pthread_mutex_unlock(&adev->lock); } - pthread_mutex_unlock(&adev->lock); if (!list_empty(&in->pcm_dev_list)) { if (in->usecase == USECASE_AUDIO_CAPTURE_HOTWORD) { @@ -3511,8 +3542,8 @@ static int add_remove_audio_effect(const struct audio_stream *stream, ALOGI("add_remove_audio_effect(), effect type: %08x, enable: %d ", desc.type.timeLow, enable); - pthread_mutex_lock(&in->dev->lock); pthread_mutex_lock(&in->lock); + pthread_mutex_lock(&in->dev->lock); #ifndef PREPROCESSING_ENABLED if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) && in->enable_aec != enable && @@ -3582,8 +3613,8 @@ static int add_remove_audio_effect(const struct audio_stream *stream, exit: #endif ALOGW_IF(status != 0, "add_remove_audio_effect() error %d", status); - pthread_mutex_unlock(&in->lock); pthread_mutex_unlock(&in->dev->lock); + pthread_mutex_unlock(&in->lock); return status; } @@ -4065,8 +4096,12 @@ static int adev_open_input_stream(struct audio_hw_device *dev, static void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) { - (void)dev; + struct audio_device *adev = (struct audio_device *)dev; ALOGV("%s", __func__); + + /* prevent concurrent out_set_parameters, or out_write from standby */ + pthread_mutex_lock(&adev->lock_inputs); + #ifdef PREPROCESSING_ENABLED struct stream_in *in = (struct stream_in*)stream; int i; @@ -4104,6 +4139,8 @@ static void adev_close_input_stream(struct audio_hw_device *dev, in_standby(&stream->common); free(stream); + pthread_mutex_unlock(&adev->lock_inputs); + return; } @@ -4301,7 +4338,6 @@ static int adev_open(const hw_module_t *module, const char *name, adev->device.dump = adev_dump; /* Set the default route before the PCM stream is opened */ - pthread_mutex_lock(&adev->lock); adev->mode = AUDIO_MODE_NORMAL; adev->active_input = NULL; adev->primary_output = NULL; @@ -4316,7 +4352,6 @@ static int adev_open(const hw_module_t *module, const char *name, adev->ns_in_voice_rec = false; list_init(&adev->usecase_list); - pthread_mutex_unlock(&adev->lock); if (mixer_init(adev) != 0) { free(adev->snd_dev_ref_cnt); diff --git a/audio/hal/audio_hw.h b/audio/hal/audio_hw.h index f2b4d5e..36767c8 100644 --- a/audio/hal/audio_hw.h +++ b/audio/hal/audio_hw.h @@ -420,11 +420,17 @@ struct audio_device { audio_devices_t dummybuf_thread_devices; pthread_mutex_t dummybuf_thread_lock; pthread_t dummybuf_thread; + + pthread_mutex_t lock_inputs; /* see note below on mutex acquisition order */ }; /* * NOTE: when multiple mutexes have to be acquired, always take the - * stream_in or stream_out mutex first, followed by the audio_device mutex. + * lock_inputs, stream_in, stream_out, audio_device, then tfa9895 mutex. + * stream_in mutex must always be before stream_out mutex + * if both have to be taken (see get_echo_reference(), put_echo_reference()...) + * dummybuf_thread mutex is not related to the other mutexes with respect to order. + * lock_inputs must be held in order to either close the input stream, or prevent closure. */ #endif // NVIDIA_AUDIO_HW_H |