mattgallagher / AudioStreamer

A streaming audio player class (AudioStreamer) for Mac OS X and iPhone.
http://cocoawithlove.com
1.93k stars 553 forks source link

audio interrupt handler may cause crash #6

Open zliuva opened 14 years ago

zliuva commented 14 years ago

the audio session handler is set as:

AudioSessionInitialize ( NULL, // 'NULL' to use the default (main) run loop NULL, // 'NULL' to use the default run loop mode MyAudioSessionInterruptionListener, // a reference to your interruption callback self // data to pass to your interruption listener callback );

however for an application the audio session will only be initialized once (despite multiple calls to AudioSessionInitialize). thus if the user app creates a new AudioStreamer, the old reference to "self" will become invalid and likely to cause a crash in MyAudioSessionInterruptionListener

one possible solution is to use a global pointer instead of relying on *inClientData

priyankranka commented 14 years ago

Can give me a sample code what needs to be written inside the listener. I am facing the same problem

zliuva commented 14 years ago

a walkaround I used


diff --git a/Classes/AudioStreamer.m b/Classes/AudioStreamer.m
index 6804833..fce0877 100644
--- a/Classes/AudioStreamer.m
+++ b/Classes/AudioStreamer.m
@@ -45,6 +45,8 @@
 NSString * const AS_NETWORK_CONNECTION_FAILED_STRING = @"Network connection failed";
 NSString * const AS_AUDIO_BUFFER_TOO_SMALL_STRING = @"Audio packets are larger than kAQDefaultBufSize.";

+static AudioStreamer *__streamer == nil;
+
 @interface AudioStreamer ()
 @property (readwrite) AudioStreamerState state;

@@ -182,8 +184,7 @@ void MyAudioQueueIsRunningCallback(void *inUserData, AudioQueueRef inAQ, AudioQu
 //
 void MyAudioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState)
 {
-       AudioStreamer* streamer = (AudioStreamer *)inClientData;
-       [streamer handleInterruptionChangeToState:inInterruptionState];
+       [__streamer handleInterruptionChangeToState:inInterruptionState];
 }
 #endif

@@ -761,6 +762,7 @@ - (void)startInternal
                        &sessionCategory
                );
                AudioSessionSetActive(true);
+               __streamer = self;
        #endif

                // initialize a mutex and condition so that we can block on buffers in use.

zliuva commented 14 years ago

and obviously using this method you should only keep one active AudioStreamer instance

loretoparisi commented 13 years ago

I had the same problem, since I was sharing the streamer object to handle ASStatusChangedNotification in different views. Using the static instance solved this issue. Thanks!

mattla93 commented 12 years ago

Same problem here. The crash happen when doing the following actions:

Solved it with the static object, I think when destroing the Streamer, the Session reports the Interription twice, because the old streamer isn't cleared from the interupption handlers

Phlibbo commented 11 years ago

My app crashed for the same reason, the static object did the trick. Thanks!