From 3660b5ae8d6bcd134072aae742b5682f40a96573 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 31 Oct 2012 15:21:04 +0100 Subject: Use mutexes to make audio thread-proof Signed-off-by: Paul Kocialkowski --- audio_hw.c | 31 ++++++++++++++++++++++--- audio_hw.h | 6 +++++ audio_in.c | 59 ++++++++++++++++++++++++++++++++++++++++++----- audio_out.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++----- audio_ril_interface.c | 41 +++++++++++++++++++++++++++------ audio_ril_interface.h | 2 ++ 6 files changed, 181 insertions(+), 22 deletions(-) diff --git a/audio_hw.c b/audio_hw.c index cfe4058..63a9303 100644 --- a/audio_hw.c +++ b/audio_hw.c @@ -90,6 +90,8 @@ static int audio_hw_set_voice_volume(struct audio_hw_device *dev, float volume) return -1; if(volume != device->voice_volume) { + pthread_mutex_lock(&device->lock); + if(device->mode == AUDIO_MODE_IN_CALL) { if(device->ril_interface != NULL) device_modem = device->ril_interface->device_current; @@ -106,6 +108,8 @@ static int audio_hw_set_voice_volume(struct audio_hw_device *dev, float volume) } device->voice_volume = volume; + + pthread_mutex_unlock(&device->lock); } return 0; @@ -125,7 +129,9 @@ static int audio_hw_set_master_volume(struct audio_hw_device *dev, float volume) if(device->mixer == NULL) return -1; + pthread_mutex_lock(&device->lock); tinyalsa_mixer_set_master_volume(device->mixer, volume); + pthread_mutex_unlock(&device->lock); return 0; } @@ -145,6 +151,8 @@ static int audio_hw_set_mode(struct audio_hw_device *dev, int mode) device = (struct tinyalsa_audio_device *) dev; if(mode != device->mode) { + pthread_mutex_lock(&device->lock); + if(mode == AUDIO_MODE_IN_CALL) { tinyalsa_mixer_set_modem_state(device->mixer, 1); @@ -187,6 +195,8 @@ static int audio_hw_set_mode(struct audio_hw_device *dev, int mode) } device->mode = mode; + + pthread_mutex_unlock(&device->lock); } return 0; @@ -208,6 +218,8 @@ static int audio_hw_set_mic_mute(struct audio_hw_device *dev, bool state) return -1; if(device->mic_mute != state) { + pthread_mutex_lock(&device->lock); + if(device->mode == AUDIO_MODE_IN_CALL) { if(device->ril_interface != NULL) device_modem = device->ril_interface->device_current; @@ -229,6 +241,8 @@ static int audio_hw_set_mic_mute(struct audio_hw_device *dev, bool state) } device->mic_mute = state; + + pthread_mutex_unlock(&device->lock); } return 0; @@ -279,16 +293,27 @@ static int audio_hw_set_parameters(struct audio_hw_device *dev, value = atoi(value_string); + pthread_mutex_lock(&device->lock); + if(audio_is_output_device((audio_devices_t) value)) { - if(device->stream_out != NULL && device->stream_out->device_current != (audio_devices_t) value) + if(device->stream_out != NULL && device->stream_out->device_current != (audio_devices_t) value) { + pthread_mutex_lock(&device->stream_out->lock); audio_out_set_route(device->stream_out, (audio_devices_t) value); - if(device->ril_interface != NULL && device->ril_interface->device_current != (audio_devices_t) value) + pthread_mutex_unlock(&device->stream_out->lock); + } + if(device->ril_interface != NULL && device->ril_interface->device_current != (audio_devices_t) value) { audio_ril_interface_set_route(device->ril_interface, (audio_devices_t) value); + } } else if(audio_is_input_device((audio_devices_t) value)) { - if(device->stream_in != NULL && device->stream_in->device_current != (audio_devices_t) value) + if(device->stream_in != NULL && device->stream_in->device_current != (audio_devices_t) value) { + pthread_mutex_lock(&device->stream_in->lock); audio_in_set_route(device->stream_in, (audio_devices_t) value); + pthread_mutex_unlock(&device->stream_in->lock); + } } + pthread_mutex_unlock(&device->lock); + str_parms_destroy(parms); return 0; diff --git a/audio_hw.h b/audio_hw.h index a06ef9b..d0be2a1 100644 --- a/audio_hw.h +++ b/audio_hw.h @@ -47,6 +47,8 @@ struct tinyalsa_audio_stream_out { struct pcm *pcm; int standby; + + pthread_mutex_t lock; }; struct tinyalsa_audio_stream_in { @@ -67,6 +69,8 @@ struct tinyalsa_audio_stream_in { struct pcm *pcm; int standby; + + pthread_mutex_t lock; }; struct tinyalsa_audio_device { @@ -85,6 +89,8 @@ struct tinyalsa_audio_device { float voice_volume; int mic_mute; + + pthread_mutex_t lock; }; int audio_out_set_route(struct tinyalsa_audio_stream_out *stream_out, diff --git a/audio_in.c b/audio_in.c index 3933bbf..618daf1 100644 --- a/audio_in.c +++ b/audio_in.c @@ -99,9 +99,10 @@ int audio_in_set_route(struct tinyalsa_audio_stream_in *stream_in, stream_in->device_current = device; - if(device == 0) + if(device == 0) { + pthread_mutex_unlock(&stream_in->lock); return stream_in->stream.common.standby((struct audio_stream *) stream_in); - + } tinyalsa_mixer_set_device(stream_in->device->mixer, stream_in->device_current); @@ -363,6 +364,8 @@ static int audio_in_set_sample_rate(struct audio_stream *stream, uint32_t rate) stream_in = (struct tinyalsa_audio_stream_in *) stream; if(stream_in->rate != (int) rate) { + pthread_mutex_lock(&stream_in->lock); + stream_in->rate = rate; if(stream_in->rate != stream_in->mixer_props->rate) { @@ -371,6 +374,8 @@ static int audio_in_set_sample_rate(struct audio_stream *stream, uint32_t rate) stream_in->standby = 1; } + + pthread_mutex_unlock(&stream_in->lock); } return 0; @@ -430,10 +435,14 @@ static int audio_in_set_format(struct audio_stream *stream, int format) stream_in = (struct tinyalsa_audio_stream_in *) stream; if(stream_in->format != (audio_format_t) format) { + pthread_mutex_lock(&stream_in->lock); + stream_in->format = format; if(stream_in->format != stream_in->mixer_props->format) stream_in->standby = 1; + + pthread_mutex_unlock(&stream_in->lock); } return 0; @@ -451,6 +460,8 @@ static int audio_in_standby(struct audio_stream *stream) stream_in = (struct tinyalsa_audio_stream_in *) stream; + pthread_mutex_lock(&stream_in->lock); + if(stream_in->pcm != NULL) audio_in_pcm_close(stream_in); @@ -465,6 +476,8 @@ static int audio_in_standby(struct audio_stream *stream) stream_in->standby = 1; + pthread_mutex_unlock(&stream_in->lock); + return 0; } @@ -503,8 +516,15 @@ static int audio_in_set_parameters(struct audio_stream *stream, const char *kvpa value = atoi(value_string); - if(stream_in->device_current != (audio_devices_t) value) + pthread_mutex_lock(&stream_in->device->lock); + + if(stream_in->device_current != (audio_devices_t) value) { + pthread_mutex_lock(&stream_in->lock); audio_in_set_route(stream_in, (audio_devices_t) value); + pthread_mutex_unlock(&stream_in->lock); + } + + pthread_mutex_unlock(&stream_in->device->lock); str_parms_destroy(parms); @@ -538,8 +558,10 @@ static int audio_in_set_gain(struct audio_stream_in *stream, float gain) if(stream_in->device == NULL || stream_in->device->mixer == NULL) return -1; + pthread_mutex_lock(&stream_in->device->lock); tinyalsa_mixer_set_input_gain(stream_in->device->mixer, stream_in->device_current, gain); + pthread_mutex_unlock(&stream_in->device->lock); return 0; } @@ -555,6 +577,11 @@ static ssize_t audio_in_read(struct audio_stream_in *stream, stream_in = (struct tinyalsa_audio_stream_in *) stream; + if(stream_in->device == NULL) + return -1; + + pthread_mutex_lock(&stream_in->lock); + if(stream_in->standby) { #ifdef YAMAHA_MC1N2_AUDIO rc = yamaha_mc1n2_audio_input_start(stream_in->device->mc1n2_pdata); @@ -566,7 +593,7 @@ static ssize_t audio_in_read(struct audio_stream_in *stream, rc = audio_in_pcm_open(stream_in); if(rc < 0) { LOGE("Unable to open pcm device"); - return -1; + goto error; } stream_in->standby = 0; @@ -575,13 +602,20 @@ static ssize_t audio_in_read(struct audio_stream_in *stream, rc = audio_in_read_process(stream_in, buffer, (int) bytes); if(rc < 0) { LOGE("Read and process failed!"); - return -1; + goto error; } if(stream_in->device != NULL && stream_in->device->mic_mute) memset(buffer, 0, bytes); + pthread_mutex_unlock(&stream_in->lock); + return bytes; + +error: + pthread_mutex_unlock(&stream_in->lock); + + return -1; } static uint32_t audio_in_get_input_frames_lost(struct audio_stream_in *stream) @@ -633,9 +667,12 @@ void audio_hw_close_input_stream(struct audio_hw_device *dev, tinyalsa_audio_device = (struct tinyalsa_audio_device *) dev; - tinyalsa_mixer_set_input_state(tinyalsa_audio_device->mixer, 0); + pthread_mutex_lock(&tinyalsa_audio_device->lock); + tinyalsa_mixer_set_input_state(tinyalsa_audio_device->mixer, 0); tinyalsa_audio_device->stream_in = NULL; + + pthread_mutex_unlock(&tinyalsa_audio_device->lock); } int audio_hw_open_input_stream(struct audio_hw_device *dev, @@ -729,17 +766,25 @@ int audio_hw_open_input_stream(struct audio_hw_device *dev, *channels = (uint32_t) tinyalsa_audio_stream_in->channels; *format = (uint32_t) tinyalsa_audio_stream_in->format; + pthread_mutex_lock(&tinyalsa_audio_device->lock); + rc = tinyalsa_mixer_set_input_state(tinyalsa_audio_device->mixer, 1); if(rc < 0) { LOGE("Unable to set input state"); + pthread_mutex_unlock(&tinyalsa_audio_device->lock); goto error_stream; } + pthread_mutex_lock(&tinyalsa_audio_stream_in->lock); + audio_in_set_route(tinyalsa_audio_stream_in, devices); + pthread_mutex_unlock(&tinyalsa_audio_device->lock); + rc = audio_in_pcm_open(tinyalsa_audio_stream_in); if(rc < 0) { LOGE("Unable to open pcm device"); + pthread_mutex_unlock(&tinyalsa_audio_stream_in->lock); goto error_stream; } @@ -747,6 +792,8 @@ int audio_hw_open_input_stream(struct audio_hw_device *dev, tinyalsa_audio_stream_in->standby = 1; + pthread_mutex_unlock(&tinyalsa_audio_stream_in->lock); + *stream_in = stream; return 0; diff --git a/audio_out.c b/audio_out.c index 3438f53..8a8814c 100644 --- a/audio_out.c +++ b/audio_out.c @@ -103,8 +103,10 @@ int audio_out_set_route(struct tinyalsa_audio_stream_out *stream_out, stream_out->device_current = device; - if(device == 0) + if(device == 0) { + pthread_mutex_unlock(&stream_out->lock); return stream_out->stream.common.standby((struct audio_stream *) stream_out); + } tinyalsa_mixer_set_device(stream_out->device->mixer, stream_out->device_current); @@ -278,6 +280,8 @@ static int audio_out_set_sample_rate(struct audio_stream *stream, uint32_t rate) stream_out = (struct tinyalsa_audio_stream_out *) stream; if(stream_out->rate != (int) rate) { + pthread_mutex_lock(&stream_out->lock); + stream_out->rate = rate; if(stream_out->rate != stream_out->mixer_props->rate) { @@ -286,6 +290,8 @@ static int audio_out_set_sample_rate(struct audio_stream *stream, uint32_t rate) stream_out->standby = 1; } + + pthread_mutex_unlock(&stream_out->lock); } return 0; @@ -345,10 +351,14 @@ static int audio_out_set_format(struct audio_stream *stream, int format) stream_out = (struct tinyalsa_audio_stream_out *) stream; if(stream_out->format != (audio_format_t) format) { + pthread_mutex_lock(&stream_out->lock); + stream_out->format = format; if(stream_out->format != stream_out->mixer_props->format) stream_out->standby = 1; + + pthread_mutex_unlock(&stream_out->lock); } return 0; @@ -366,6 +376,8 @@ static int audio_out_standby(struct audio_stream *stream) stream_out = (struct tinyalsa_audio_stream_out *) stream; + pthread_mutex_lock(&stream_out->lock); + if(stream_out->pcm != NULL) audio_out_pcm_close(stream_out); @@ -380,6 +392,8 @@ static int audio_out_standby(struct audio_stream *stream) stream_out->standby = 1; + pthread_mutex_unlock(&stream_out->lock); + return 0; } @@ -418,10 +432,18 @@ static int audio_out_set_parameters(struct audio_stream *stream, const char *kvp value = atoi(value_string); - if(stream_out->device_current != (audio_devices_t) value) + pthread_mutex_lock(&stream_out->device->lock); + + if(stream_out->device_current != (audio_devices_t) value) { + pthread_mutex_lock(&stream_out->lock); audio_out_set_route(stream_out, (audio_devices_t) value); - if(stream_out->device->ril_interface != NULL && stream_out->device->ril_interface->device_current != (audio_devices_t) value) + pthread_mutex_unlock(&stream_out->lock); + } + if(stream_out->device->ril_interface != NULL && stream_out->device->ril_interface->device_current != (audio_devices_t) value) { audio_ril_interface_set_route(stream_out->device->ril_interface, (audio_devices_t) value); + } + + pthread_mutex_unlock(&stream_out->device->lock); str_parms_destroy(parms); @@ -477,8 +499,10 @@ static int audio_out_set_volume(struct audio_stream_out *stream, float left, volume = (left + right) / 2; + pthread_mutex_lock(&stream_out->device->lock); tinyalsa_mixer_set_output_volume(stream_out->device->mixer, stream_out->device_current, volume); + pthread_mutex_unlock(&stream_out->device->lock); return 0; } @@ -494,6 +518,11 @@ static ssize_t audio_out_write(struct audio_stream_out *stream, stream_out = (struct tinyalsa_audio_stream_out *) stream; + if(stream_out->device == NULL) + return -1; + + pthread_mutex_lock(&stream_out->lock); + if(stream_out->standby) { #ifdef YAMAHA_MC1N2_AUDIO rc = yamaha_mc1n2_audio_output_start(stream_out->device->mc1n2_pdata); @@ -505,7 +534,7 @@ static ssize_t audio_out_write(struct audio_stream_out *stream, rc = audio_out_pcm_open(stream_out); if(rc < 0) { LOGE("Unable to open pcm device"); - return -1; + goto error; } stream_out->standby = 0; @@ -514,10 +543,17 @@ static ssize_t audio_out_write(struct audio_stream_out *stream, rc = audio_out_write_process(stream_out, (void *) buffer, (int) bytes); if(rc < 0) { LOGE("Process and write failed!"); - return -1; + goto error; } + pthread_mutex_unlock(&stream_out->lock); + return bytes; + +error: + pthread_mutex_unlock(&stream_out->lock); + + return -1; } static int audio_out_get_render_position(const struct audio_stream_out *stream, @@ -556,6 +592,9 @@ void audio_hw_close_output_stream(struct audio_hw_device *dev, stream_out = (struct tinyalsa_audio_stream_out *) stream; + if(stream_out != NULL && stream_out->resampler != NULL) + audio_out_resampler_close(stream_out); + #ifdef YAMAHA_MC1N2_AUDIO if(stream_out != NULL && !stream_out->standby) yamaha_mc1n2_audio_output_stop(stream_out->device->mc1n2_pdata); @@ -569,9 +608,12 @@ void audio_hw_close_output_stream(struct audio_hw_device *dev, tinyalsa_audio_device = (struct tinyalsa_audio_device *) dev; - tinyalsa_mixer_set_output_state(tinyalsa_audio_device->mixer, 0); + pthread_mutex_lock(&tinyalsa_audio_device->lock); + tinyalsa_mixer_set_output_state(tinyalsa_audio_device->mixer, 0); tinyalsa_audio_device->stream_out = NULL; + + pthread_mutex_unlock(&tinyalsa_audio_device->lock); } int audio_hw_open_output_stream(struct audio_hw_device *dev, @@ -659,17 +701,25 @@ int audio_hw_open_output_stream(struct audio_hw_device *dev, *channels = (uint32_t) tinyalsa_audio_stream_out->channels; *format = (uint32_t) tinyalsa_audio_stream_out->format; + pthread_mutex_lock(&tinyalsa_audio_device->lock); + rc = tinyalsa_mixer_set_output_state(tinyalsa_audio_device->mixer, 1); if(rc < 0) { LOGE("Unable to set output state"); + pthread_mutex_unlock(&tinyalsa_audio_device->lock); goto error_stream; } + pthread_mutex_lock(&tinyalsa_audio_stream_out->lock); + audio_out_set_route(tinyalsa_audio_stream_out, devices); + pthread_mutex_unlock(&tinyalsa_audio_device->lock); + rc = audio_out_pcm_open(tinyalsa_audio_stream_out); if(rc < 0) { LOGE("Unable to open pcm device"); + pthread_mutex_unlock(&tinyalsa_audio_stream_out->lock); goto error_stream; } @@ -677,6 +727,8 @@ int audio_hw_open_output_stream(struct audio_hw_device *dev, tinyalsa_audio_stream_out->standby = 1; + pthread_mutex_unlock(&tinyalsa_audio_stream_out->lock); + *stream_out = stream; return 0; diff --git a/audio_ril_interface.c b/audio_ril_interface.c index d3a8658..0b4383d 100644 --- a/audio_ril_interface.c +++ b/audio_ril_interface.c @@ -42,16 +42,25 @@ int audio_ril_interface_set_mic_mute(struct tinyalsa_audio_ril_interface *ril_in LOGD("%s(%d)", __func__, state); + pthread_mutex_lock(&ril_interface->lock); + if(ril_interface->interface->mic_mute == NULL) - return -1; + goto error; rc = ril_interface->interface->mic_mute(ril_interface->interface->pdata, (int) state); if(rc < 0) { LOGE("Failed to set RIL interface mic mute"); - return -1; + goto error; } + pthread_mutex_unlock(&ril_interface->lock); + return 0; + +error: + pthread_mutex_unlock(&ril_interface->lock); + + return -1; } int audio_ril_interface_set_voice_volume(struct tinyalsa_audio_ril_interface *ril_interface, @@ -64,39 +73,57 @@ int audio_ril_interface_set_voice_volume(struct tinyalsa_audio_ril_interface *ri LOGD("%s(%d, %f)", __func__, device, volume); + pthread_mutex_lock(&ril_interface->lock); + if(ril_interface->interface->voice_volume == NULL) - return -1; + goto error; rc = ril_interface->interface->voice_volume(ril_interface->interface->pdata, device, volume); if(rc < 0) { LOGE("Failed to set RIL interface voice volume"); - return -1; + goto error; } + pthread_mutex_unlock(&ril_interface->lock); + return 0; + +error: + pthread_mutex_unlock(&ril_interface->lock); + + return -1; } int audio_ril_interface_set_route(struct tinyalsa_audio_ril_interface *ril_interface, audio_devices_t device) { int rc; + LOGD("%s(%d)", __func__, device); + if(ril_interface == NULL) return -1; - LOGD("%s(%d)", __func__, device); + pthread_mutex_lock(&ril_interface->lock); ril_interface->device_current = device; if(ril_interface->interface->route == NULL) - return -1; + goto error; rc = ril_interface->interface->route(ril_interface->interface->pdata, device); if(rc < 0) { LOGE("Failed to set RIL interface route"); - return -1; + goto error; } + pthread_mutex_unlock(&ril_interface->lock); + return 0; + +error: + pthread_mutex_unlock(&ril_interface->lock); + + return -1; } /* diff --git a/audio_ril_interface.h b/audio_ril_interface.h index c1befae..3d7e3f1 100644 --- a/audio_ril_interface.h +++ b/audio_ril_interface.h @@ -28,6 +28,8 @@ struct tinyalsa_audio_ril_interface { void *dl_handle; audio_devices_t device_current; + + pthread_mutex_t lock; }; int audio_ril_interface_set_mic_mute(struct tinyalsa_audio_ril_interface *ril_interface, bool state); -- cgit v1.1