kstenerud / ObjectAL-for-iPhone

Mac and iOS Audio development, minus the headache. ObjectAL is the easy Objective-C interface to OpenAL, AVAudioPlayer, and audio session management.
http://kstenerud.github.com/ObjectAL-for-iPhone
885 stars 171 forks source link

Phone call interruption makes unsuccessful session activation #87

Open Wh1rlw1nd opened 9 years ago

Wh1rlw1nd commented 9 years ago

I've been playing with phone calls while game running in order to test interruptions. I am using example from ObjectAL documentation called : "Using the OpenAL Objects and OALAudioTrack" So, I let the library to handle this automatically...

[OALAudioSession sharedInstance ]. handleInterruptions = YES

And it works but partially. For example, with simple setup with 3 sounds I get next error message :

OALAudioSession activateAudioSession]: Could not activate audio session after 2 tries: Error Domain=NSOSStatusErrorDomain Code=561015905 "The operation couldn’t be completed. (OSStatus error 561015905.)"

I've noticed that if I add more sounds (lets say 20) , I will get same messages:

Could not activate audio session after 20 tries:

After that, the session is activated.

- (void) activateAudioSession
{
    NSError* error;
    for(int try = 1; try <= kMaxSessionActivationRetries; try++)
    {
        if([[AVAudioSession sharedInstance] setActive:YES error:&error])
        {

            NSLog(@"Session activated after %d", try);

            audioSessionActive = YES;
            return;
        }
        OAL_LOG_ERROR(@"Could not activate audio session after %d tries: %@", try, error);
        [NSThread sleepForTimeInterval:0.2];
    }
    OAL_LOG_ERROR(@"Failed to activate the audio session");
}  

So, finally, after unsuccessful tries, I get message which says : "Session activated after 21 tries"

But because kMaxSessionActivationRetries is set to 40, eventually sound playing will "break" because number of tries can easily reach more than 40 attempts. I am aware that I can change this value, but that doesn't actually solve the problem.

Am I missing something important here ? I thought that when handleInterruptions property is set to YES , we don't have to do any manual interruptions/session handling ? I am testing on iPhone 6 & iOS8 if that matters. Could anyone shed some light on this ? @kstenerud Any ideas ?

kstenerud commented 9 years ago

It's really tricky to get this right. I've made so many fixes to broken Apple code over the years, and yet they still manage to break things in new and interesting ways with each release.

I've tried hooking session management into the application foreground/background hook methods, which worked in some iOS releases but not others. I've also let the OS do its thing, which is flaky at best. I can take a look further into this, but no guarantees. If you find out more info, please post it!

Wh1rlw1nd commented 9 years ago

@kstenerud Thanks for quick response Karl... Yeah :) I get the point... I asked same question on StackOveflow as well, so I will update accordingly if I somehow came up with solution. In the mean while, can you direct me where to look or what to try ?

kstenerud commented 9 years ago

The essential parts are in OALAudioSession and OALSuspendHandler. The suspend handler is just a chained callback mechanism so that a suspend/resume event can be propagated through ALContext to ALDevice (for OpenAL), and OALAudioTrack and OALAudioTracks (for AVAudioPlayer).

The method you're experiencing troubles with is activateAudioSession in OALAudioSession. It's basically calling [[AVAudioSession sharedInstance] setActive], which technically is supposed to just work, but actually rarely does (thus the loop). There's also a forceEndInterrupt method, which I've used in various iOS versions as a last-ditch effort to kick the audio system on should the operating system's automatic session suspend/resume fail to work.

Wh1rlw1nd commented 9 years ago

I just noticed if I set allowIpod = NO and honorSilentSwitch = NO I get no errors. But this is not solution, at least not in my case..