vlc | branch: master | Thomas Guillem <[email protected]> | Fri Feb 24 17:40:33 2017 +0100| [61686a07d128fbba5c676d7cbc371113cd07a881] | committer: Thomas Guillem
coreaudio: fix unlikely but possible deadlock on pause The pause state need to be known by ca_Play in order to don't wait indefinitely when the RenderCallback is paused. A deadlock could happen with asynchronous audio decoders. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=61686a07d128fbba5c676d7cbc371113cd07a881 --- modules/audio_output/audiounit_ios.m | 7 +++++- modules/audio_output/auhal.c | 40 +++++---------------------------- modules/audio_output/coreaudio_common.c | 23 +++++++++++++++++++ modules/audio_output/coreaudio_common.h | 3 +++ 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/modules/audio_output/audiounit_ios.m b/modules/audio_output/audiounit_ios.m index 74c2590..451d3c1 100644 --- a/modules/audio_output/audiounit_ios.m +++ b/modules/audio_output/audiounit_ios.m @@ -103,7 +103,6 @@ avas_SetActive(audio_output_t *p_aout, bool active, NSUInteger options) static void Pause (audio_output_t *p_aout, bool pause, mtime_t date) { - VLC_UNUSED(date); struct aout_sys_t * p_sys = p_aout->sys; /* We need to start / stop the audio unit here because otherwise the OS @@ -127,10 +126,16 @@ Pause (audio_output_t *p_aout, bool pause, mtime_t date) { err = AudioOutputUnitStart(p_sys->au_unit); if (err != noErr) + { msg_Err(p_aout, "AudioOutputUnitStart failed [%4.4s]", (const char *) &err); + /* Do not un-pause, the Render Callback won't run, and next call + * of ca_Play will deadlock */ + return; + } } } + ca_Pause(p_aout, pause, date); } static int diff --git a/modules/audio_output/auhal.c b/modules/audio_output/auhal.c index cb2a9d6..256a94a 100644 --- a/modules/audio_output/auhal.c +++ b/modules/audio_output/auhal.c @@ -121,7 +121,6 @@ struct aout_sys_t float f_volume; bool b_mute; - atomic_bool b_paused; bool b_ignore_streams_changed_callback; }; @@ -928,15 +927,8 @@ RenderCallbackAnalog(void *p_data, AudioUnitRenderActionFlags *ioActionFlags, VLC_UNUSED(inBusNumber); VLC_UNUSED(inNumberFrames); - audio_output_t * p_aout = p_data; - aout_sys_t *p_sys = p_aout->sys; - uint8_t *p_output = ioData->mBuffers[0].mData; - size_t i_size = ioData->mBuffers[0].mDataByteSize; - - if (!atomic_load(&p_sys->b_paused)) - ca_Render(p_aout, p_output, i_size); - else - memset(p_output, 0, i_size); + ca_Render(p_data, ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize); return noErr; } @@ -962,10 +954,7 @@ RenderCallbackSPDIF(AudioDeviceID inDevice, const AudioTimeStamp * inNow, uint8_t *p_output = outOutputData->mBuffers[p_sys->i_stream_index].mData; size_t i_size = outOutputData->mBuffers[p_sys->i_stream_index].mDataByteSize; - if (!atomic_load(&p_sys->b_paused)) - ca_Render(p_data, p_output, i_size); - else - memset(p_output, 0, i_size); + ca_Render(p_aout, p_output, i_size); return noErr; } @@ -973,15 +962,6 @@ RenderCallbackSPDIF(AudioDeviceID inDevice, const AudioTimeStamp * inNow, #pragma mark - #pragma mark initialization -static void -Pause(audio_output_t *p_aout, bool pause, mtime_t date) -{ - struct aout_sys_t * p_sys = p_aout->sys; - VLC_UNUSED(date); - - atomic_store(&p_sys->b_paused, pause); -} - /* * StartAnalog: open and setup a HAL AudioUnit to do PCM audio output */ @@ -1811,7 +1791,6 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt) p_sys->i_stream_index = -1; p_sys->b_revert = false; p_sys->b_changed_mixing = false; - p_sys->b_paused = false; p_sys->c.i_device_latency = 0; vlc_mutex_lock(&p_sys->selected_device_lock); @@ -1928,15 +1907,13 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt) p_sys->c.i_device_latency = 0; } - bool b_success = false; - /* Check for Digital mode or Analog output mode */ if (AOUT_FMT_SPDIF (fmt) && b_start_digital) { if (StartSPDIF (p_aout, fmt) == VLC_SUCCESS) { msg_Dbg(p_aout, "digital output successfully opened"); - b_success = true; + return VLC_SUCCESS; } } else @@ -1944,16 +1921,10 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt) if (StartAnalog(p_aout, fmt) == VLC_SUCCESS) { msg_Dbg(p_aout, "analog output successfully opened"); - b_success = true; + return VLC_SUCCESS; } } - if (b_success) - { - p_aout->pause = Pause; - return VLC_SUCCESS; - } - error: /* If we reach this, this aout has failed */ msg_Err(p_aout, "opening auhal output failed"); @@ -2031,7 +2002,6 @@ static int Open(vlc_object_t *obj) p_sys->b_selected_dev_is_default = false; memset(&p_sys->sfmt_revert, 0, sizeof(p_sys->sfmt_revert)); p_sys->i_stream_id = 0; - atomic_init(&p_sys->b_paused, false); p_aout->sys = p_sys; p_aout->start = Start; diff --git a/modules/audio_output/coreaudio_common.c b/modules/audio_output/coreaudio_common.c index 910546a..0ca4986 100644 --- a/modules/audio_output/coreaudio_common.c +++ b/modules/audio_output/coreaudio_common.c @@ -42,6 +42,12 @@ ca_Render(audio_output_t *p_aout, uint8_t *p_output, size_t i_requested) { struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys; + if (atomic_load_explicit(&p_sys->b_paused, memory_order_relaxed)) + { + memset(p_output, 0, i_requested); + return; + } + /* Pull audio from buffer */ int32_t i_available; void *p_data = TPCircularBufferTail(&p_sys->circular_buffer, @@ -107,6 +113,15 @@ ca_Flush(audio_output_t *p_aout, bool wait) } void +ca_Pause(audio_output_t * p_aout, bool pause, mtime_t date) +{ + struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys; + VLC_UNUSED(date); + + atomic_store_explicit(&p_sys->b_paused, pause, memory_order_relaxed); +} + +void ca_Play(audio_output_t * p_aout, block_t * p_block) { struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys; @@ -128,6 +143,12 @@ ca_Play(audio_output_t * p_aout, block_t * p_block) assert(false); break; } + if (atomic_load_explicit(&p_sys->b_paused, memory_order_relaxed)) + { + msg_Warn(p_aout, "dropping block because the circular buffer is " + "full and paused"); + break; + } /* Wait for the render buffer to play the remaining data */ int32_t i_avalaible_bytes; @@ -162,12 +183,14 @@ ca_Init(audio_output_t *p_aout, const audio_sample_format_t *fmt, return VLC_EGENERIC; atomic_init(&p_sys->i_underrun_size, 0); + atomic_init(&p_sys->b_paused, false); p_sys->i_rate = fmt->i_rate; p_sys->i_bytes_per_frame = fmt->i_bytes_per_frame; p_sys->i_frame_length = fmt->i_frame_length; p_aout->play = ca_Play; + p_aout->pause = ca_Pause; p_aout->flush = ca_Flush; p_aout->time_get = ca_TimeGet; return VLC_SUCCESS; diff --git a/modules/audio_output/coreaudio_common.h b/modules/audio_output/coreaudio_common.h index 1b6f908..f6a532a 100644 --- a/modules/audio_output/coreaudio_common.h +++ b/modules/audio_output/coreaudio_common.h @@ -49,6 +49,7 @@ struct aout_sys_common /* circular buffer to swap the audio data */ TPCircularBuffer circular_buffer; atomic_uint i_underrun_size; + atomic_bool b_paused; int i_rate; unsigned int i_bytes_per_frame; unsigned int i_frame_length; @@ -67,6 +68,8 @@ int ca_TimeGet(audio_output_t *p_aout, mtime_t *delay); void ca_Flush(audio_output_t *p_aout, bool wait); +void ca_Pause(audio_output_t * p_aout, bool pause, mtime_t date); + void ca_Play(audio_output_t * p_aout, block_t * p_block); int ca_Init(audio_output_t *p_aout, const audio_sample_format_t *fmt, _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
