diff options
author | Eric Laurent <elaurent@google.com> | 2014-08-04 20:29:17 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2014-08-06 14:18:26 -0700 |
commit | 05333d458d1c946a17c127372d3ff82558f38ee6 (patch) | |
tree | 6024386d213882a6b7b5cf149d740a120bdbee7d /modules | |
parent | ba3c1a972e113f3bdf1c76a26e89505c39c981d3 (diff) | |
download | hardware_libhardware-05333d458d1c946a17c127372d3ff82558f38ee6.zip hardware_libhardware-05333d458d1c946a17c127372d3ff82558f38ee6.tar.gz hardware_libhardware-05333d458d1c946a17c127372d3ff82558f38ee6.tar.bz2 |
usb audio: fix set_parameters read/write concurrency
Do not read the ALSA PCM device configuration when playback
or capture is active.
Do not force ALSA profile update if card and device passed
to out/in_set_parameters() do not change.
Hold the main HAL lock when closing or opening the
ALSA PCM device.
Bug: 15520724.
Change-Id: I2b6087ed46ce7433de0b6dd8b24ec10de2e55d21
Diffstat (limited to 'modules')
-rw-r--r-- | modules/usbaudio/audio_hw.c | 82 |
1 files changed, 52 insertions, 30 deletions
diff --git a/modules/usbaudio/audio_hw.c b/modules/usbaudio/audio_hw.c index 3a39fea..22d5e0f 100644 --- a/modules/usbaudio/audio_hw.c +++ b/modules/usbaudio/audio_hw.c @@ -313,28 +313,38 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) int param_val; int routing = 0; int ret_value = 0; + int card = -1; + int device = -1; struct str_parms * parms = str_parms_create_str(kvpairs); pthread_mutex_lock(&out->dev->lock); pthread_mutex_lock(&out->lock); - bool recache_device_params = false; param_val = str_parms_get_str(parms, "card", value, sizeof(value)); - if (param_val >= 0) { - out->profile->card = atoi(value); - recache_device_params = true; - } + if (param_val >= 0) + card = atoi(value); param_val = str_parms_get_str(parms, "device", value, sizeof(value)); - if (param_val >= 0) { - out->profile->device = atoi(value); - recache_device_params = true; - } - - if (recache_device_params && out->profile->card >= 0 && out->profile->device >= 0) { - ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL; + if (param_val >= 0) + device = atoi(value); + + if ((card >= 0) && (card != out->profile->card) && + (device >= 0) && (device != out->profile->device)) { + /* cannot read pcm device info if playback is active */ + if (!out->standby) + ret_value = -ENOSYS; + else { + int saved_card = out->profile->card; + int saved_device = out->profile->device; + out->profile->card = card; + out->profile->device = device; + ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL; + if (ret_value != 0) { + out->profile->card = saved_card; + out->profile->device = saved_device; + } + } } - pthread_mutex_unlock(&out->lock); pthread_mutex_unlock(&out->dev->lock); str_parms_destroy(parms); @@ -383,15 +393,16 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, si pthread_mutex_lock(&out->dev->lock); pthread_mutex_lock(&out->lock); - pthread_mutex_unlock(&out->dev->lock); - if (out->standby) { ret = start_output_stream(out); if (ret != 0) { + pthread_mutex_unlock(&out->dev->lock); goto err; } out->standby = false; } + pthread_mutex_unlock(&out->dev->lock); + alsa_device_proxy* proxy = &out->proxy; const void * write_buff = buffer; @@ -687,29 +698,39 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) int param_val; int routing = 0; int ret_value = 0; + int card = -1; + int device = -1; struct str_parms * parms = str_parms_create_str(kvpairs); pthread_mutex_lock(&in->dev->lock); pthread_mutex_lock(&in->lock); - bool recache_device_params = false; - /* Card/Device */ param_val = str_parms_get_str(parms, "card", value, sizeof(value)); - if (param_val >= 0) { - in->profile->card = atoi(value); - recache_device_params = true; - } + if (param_val >= 0) + card = atoi(value); param_val = str_parms_get_str(parms, "device", value, sizeof(value)); - if (param_val >= 0) { - in->profile->device = atoi(value); - recache_device_params = true; - } - - if (recache_device_params && in->profile->card >= 0 && in->profile->device >= 0) { - ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL; + if (param_val >= 0) + device = atoi(value); + + if ((card >= 0) && (card != in->profile->card) && + (device >= 0) && (device != in->profile->device)) { + /* cannot read pcm device info if playback is active */ + if (!in->standby) + ret_value = -ENOSYS; + else { + int saved_card = in->profile->card; + int saved_device = in->profile->device; + in->profile->card = card; + in->profile->device = device; + ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL; + if (ret_value != 0) { + in->profile->card = saved_card; + in->profile->device = saved_device; + } + } } pthread_mutex_unlock(&in->lock); @@ -770,14 +791,15 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t byte pthread_mutex_lock(&in->dev->lock); pthread_mutex_lock(&in->lock); - pthread_mutex_unlock(&in->dev->lock); - if (in->standby) { if (start_input_stream(in) != 0) { + pthread_mutex_unlock(&in->dev->lock); goto err; } in->standby = false; } + pthread_mutex_unlock(&in->dev->lock); + alsa_device_profile * profile = in->profile; |