objective-ciosopenalaudio

open al sounds don't play after the incoming call, until app restart


I'm playing game sounds using OpenAL, and bg music using standard AV. Recently i've found that after the incoming call all openal sounds don't work while bg music is still playing. If I force stop app and start again sounds appear again. Do smbd happen to know what's happening to openal during/after the incoming call?


Solution

  • Ok, it seems I've found a solution. I'm using obj-c sound manager, so I just added beginInterruption and endInterruption delegate methods of AVAudioSession (and AVAudioPlayer) to my class.

    beginInterruption looks like:

    alcMakeContextCurrent(NULL);
    

    and endInterruption looks something like:

        NSError * audioSessionError = NULL;
        [audioSession setCategory:soundCategory error:&audioSessionError];
        if (audioSessionError)
        {
            Log(@"ERROR - SoundManager: Unable to set the audio session category");
            return;
        }
    
        // Set the audio session state to true and report any errors
        audioSessionError = NULL;
        [audioSession setActive:YES error:&audioSessionError];
        if (audioSessionError)
        {
            Log(@"ERROR - SoundManager: Unable to set the audio session state to YES with error %d.", (int) result);
            return;
        }
    
            //music players handling
        bool plays = false;
        if (musicPlayer[currentPlayer] != nil)
            plays = [musicPlayer[currentPlayer] isPlaying];
        if (musicPlayer[currentPlayer] != nil && !plays)
            [musicPlayer[currentPlayer] play];
    
        alcMakeContextCurrent(context);
    

    Yes, this works if you're using only openAL sounds. But to play long tracks you should use AVAudioPlayer. But here's the Apple magic again! If you play music along with OpenAL sounds something odd happens. Cancel the incoming call and AVAudioSessionDelegate::endInterruption with AVAudioPlayerDelegate::audioPlayerEndInterruption will never called. Only beginInterruption, not the end. Even AppDelegate::applicationWillEnterForeground will not be called, and app just don't know that we've returned.

    But the good news is that you can call your endInterruption in AppDelegate::applicationDidBecomeActive method, and openAL context will be restored. And this works!

    - (void)applicationDidBecomeActive:(UIApplication *)application
    {
        if (MySoundMngr != nil)
        {
            [MySoundMngr endInterruption];
        }
    
        // Restart any tasks that were paused and so on....
    }