[PATCH] coreaudio: fix deadlock on interruption

Carola Nitz nitz.carola at googlemail.com
Tue Dec 12 13:06:50 CET 2017


Add ca_setAlive call that sets the b_paused to true in order to interrupt ca_Play or ca_Flush.
---
 modules/audio_output/audiounit_ios.m    | 26 ++++++++++++++++++++++++--
 modules/audio_output/coreaudio_common.c | 30 +++++++++++++++++++++++++++++-
 modules/audio_output/coreaudio_common.h |  3 +++
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/modules/audio_output/audiounit_ios.m b/modules/audio_output/audiounit_ios.m
index a53a15f93d..c87f3572b9 100644
--- a/modules/audio_output/audiounit_ios.m
+++ b/modules/audio_output/audiounit_ios.m
@@ -127,6 +127,23 @@ - (void)audioSessionRouteChange:(NSNotification *)notification
         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 @@ - (void)audioSessionRouteChange:(NSNotification *)notification
         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;
diff --git a/modules/audio_output/coreaudio_common.c b/modules/audio_output/coreaudio_common.c
index d2e846587a..9255ec90e2 100644
--- a/modules/audio_output/coreaudio_common.c
+++ b/modules/audio_output/coreaudio_common.c
@@ -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 */
@@ -140,13 +142,23 @@ ca_Flush(audio_output_t *p_aout, bool wait)
                 FramesToUs(p_sys, BytesToFrames(p_sys, i_bytes)) + 10000;
 
             msleep(i_frame_us / 2);
+            if (atomic_load(&p_sys->b_paused))
+                return;
         }
     }
     else
     {
         /* Request the renderer to flush, and wait for an ACK */
+        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);
+            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 +271,27 @@ 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))
+    {
+        /* 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)
 {
diff --git a/modules/audio_output/coreaudio_common.h b/modules/audio_output/coreaudio_common.h
index 6719db6580..75b50a53d0 100644
--- a/modules/audio_output/coreaudio_common.h
+++ b/modules/audio_output/coreaudio_common.h
@@ -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,
-- 
2.14.3 (Apple Git-98)



More information about the vlc-devel mailing list