Commit 4793c4ff authored by Carola Nitz's avatar Carola Nitz Committed by Thomas Guillem

audiounit_ios: fix deadlock on interruption

Add ca_setAliveState() that sets the b_paused to true and unblock ca_Play() or
ca_Flush() that could wait for ca_Render().

(cherry picked from commit 7e4c7f35)
Signed-off-by: Thomas Guillem's avatarThomas Guillem <thomas@gllm.fr>
parent 06fb276a
......@@ -127,6 +127,23 @@ enum port_type
aout_RestartRequest(p_aout, AOUT_RESTART_OUTPUT);
}
- (void)handleInterruption:(NSNotification *)notification
{
audio_output_t *p_aout = [self aout];
NSDictionary *userInfo = notification.userInfo;
if (!userInfo || !userInfo[AVAudioSessionInterruptionTypeKey]) {
return;
}
NSUInteger interruptionType = [userInfo[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
if (interruptionType == AVAudioSessionInterruptionTypeBegan) {
ca_SetAliveState(p_aout, false);
} else if (interruptionType == AVAudioSessionInterruptionTypeEnded
&& [userInfo[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue] == AVAudioSessionInterruptionOptionShouldResume) {
ca_SetAliveState(p_aout, true);
}
}
@end
static void
......@@ -467,8 +484,13 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
Pause(p_aout, true, 0);
[[NSNotificationCenter defaultCenter] addObserver:p_sys->aoutWrapper
selector:@selector(audioSessionRouteChange:)
name:AVAudioSessionRouteChangeNotification object:nil];
selector:@selector(audioSessionRouteChange:)
name:AVAudioSessionRouteChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:p_sys->aoutWrapper
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:nil];
free(layout);
fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
......
......@@ -51,6 +51,7 @@ ca_Open(audio_output_t *p_aout)
atomic_init(&p_sys->b_paused, false);
atomic_init(&p_sys->b_do_flush, false);
vlc_sem_init(&p_sys->flush_sem, 0);
vlc_mutex_init(&p_sys->lock);
p_aout->play = ca_Play;
p_aout->pause = ca_Pause;
......@@ -64,6 +65,7 @@ ca_Close(audio_output_t *p_aout)
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
vlc_sem_destroy(&p_sys->flush_sem);
vlc_mutex_destroy(&p_sys->lock);
}
/* Called from render callbacks. No lock, wait, and IO here */
......@@ -134,6 +136,12 @@ ca_Flush(audio_output_t *p_aout, bool wait)
while (TPCircularBufferTail(&p_sys->circular_buffer, &i_bytes) != NULL)
{
if (atomic_load(&p_sys->b_paused))
{
TPCircularBufferClear(&p_sys->circular_buffer);
return;
}
/* Calculate the duration of the circular buffer, in order to wait
* for the render thread to play it all */
const mtime_t i_frame_us =
......@@ -144,9 +152,23 @@ ca_Flush(audio_output_t *p_aout, bool wait)
}
else
{
/* Request the renderer to flush, and wait for an ACK */
/* Request the renderer to flush, and wait for an ACK.
* b_do_flush and b_paused need to be locked together in order to not
* get stuck here when b_paused is being set after reading. This can
* happen when setAliveState() is called from any thread through an
* interrupt notification */
vlc_mutex_lock(&p_sys->lock);
assert(!atomic_load(&p_sys->b_do_flush));
if (atomic_load(&p_sys->b_paused))
{
vlc_mutex_unlock(&p_sys->lock);
TPCircularBufferClear(&p_sys->circular_buffer);
return;
}
atomic_store_explicit(&p_sys->b_do_flush, true, memory_order_release);
vlc_mutex_unlock(&p_sys->lock);
vlc_sem_wait(&p_sys->flush_sem);
}
}
......@@ -259,11 +281,28 @@ void
ca_Uninitialize(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
/* clean-up circular buffer */
TPCircularBufferCleanup(&p_sys->circular_buffer);
}
void
ca_SetAliveState(audio_output_t *p_aout, bool alive)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
vlc_mutex_lock(&p_sys->lock);
atomic_store(&p_sys->b_paused, !alive);
bool expected = true;
if (!alive && atomic_compare_exchange_strong(&p_sys->b_do_flush, &expected, false))
{
TPCircularBufferClear(&p_sys->circular_buffer);
/* Signal that the renderer is flushed */
vlc_sem_post(&p_sys->flush_sem);
}
vlc_mutex_unlock(&p_sys->lock);
}
AudioUnit
au_NewOutputInstance(audio_output_t *p_aout, OSType comp_sub_type)
{
......
......@@ -56,6 +56,7 @@ struct aout_sys_common
atomic_bool b_paused;
atomic_bool b_do_flush;
vlc_sem_t flush_sem;
vlc_mutex_t lock;
int i_rate;
unsigned int i_bytes_per_frame;
unsigned int i_frame_length;
......@@ -84,6 +85,8 @@ int ca_Initialize(audio_output_t *p_aout, const audio_sample_format_t *fmt,
void ca_Uninitialize(audio_output_t *p_aout);
void ca_SetAliveState(audio_output_t *p_aout, bool alive);
AudioUnit au_NewOutputInstance(audio_output_t *p_aout, OSType comp_sub_type);
int au_Initialize(audio_output_t *p_aout, AudioUnit au,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment