Hi,
I'm very confused by changes in audio interruption brought in by the newest version of iOS.
Audio Interruption Began/Ended callbacks used to be called by events like alarming notification and incoming phone call.
Since iOS 11, interruptions will also be triggered when suspending/resuming the app,
and occasionally the InterruptionBegan event comes after the DidBecomeActive event, without a proper InterruptionEnded following.
This really bugs me since I use the audio interruption event to handle the BGM's play/pause in my app,
and such behaviour leads to a resumed app without the BGM playing.
I understand that the InterruptionEnded is not guaranteed to happen,
but what is the purpose to trigger an interruption when resuming an app?
Is there a proper way to handle the play/pause behaviour, or to resolve my problem?
Here is the code to reproduce the problem.
by turning the phone to sleep/awake mode repeatedly,
Sometimes the debug output will stop at
----
...
[DEBUG] applicationDidBecomeActive
[DEBUG] audioSessionInterruption - Began
----
when the app is resumed, with the music been stopped.
#import "AppDelegate.h"
#import <AudioToolbox/AudioServices.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
@interface AppDelegate ()
@end
@implementation AppDelegate {
NSString *soundFilePath;
NSURL *soundFileUrl;
AVAudioPlayer *player;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
/* register interruption event callback */
[notificationCenter addObserver:self
selector:@selector(audioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:nil
];
[notificationCenter addObserver:self
selector:@selector(audioSessionMediaServicesWereReset:)
name:AVAudioSessionMediaServicesWereResetNotification
object:nil
];
/* init the player */
soundFilePath=[NSString stringWithFormat:@"%@/some_music.mp3", [[NSBundle mainBundle] resourcePath]];
soundFileUrl = [NSURL fileURLWithPath:soundFilePath];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileUrl fileTypeHint:nil error:nil];
player.numberOfLoops = -1;
return YES;
}
- (void)audioSessionInterruption:(NSNotification*)notification
{
NSNumber* number;
NSDictionary* userInfo = notification.userInfo;
bool wasSuspended = false;
if (@available(iOS 10.3, *)) {
number = [userInfo objectForKey:AVAudioSessionInterruptionWasSuspendedKey];
}
if (number && ([number boolValue] == TRUE)) {
wasSuspended = true;
}
switch ([userInfo[AVAudioSessionInterruptionTypeKey] intValue]) {
case AVAudioSessionInterruptionTypeBegan:
if (wasSuspended) {
NSLog(@"[DEBUG] audioSessionInterruption - WasSuspended");
[player play];
} else {
NSLog(@"[DEBUG] audioSessionInterruption - Began");
[player pause];
}
break;
case AVAudioSessionInterruptionTypeEnded:
NSLog(@"[DEBUG] audioSessionInterruption - Ended");
[player play];
break;
default:
NSLog(@"[DEBUG] audioSessionInterruption - not supposed to happen");
break;
}
}
- (void)audioSessionMediaServicesWereReset:(NSNotification*)notification
{
NSLog(@"[DEBUG] audioSessionMediaServicesWereReset");
[player play];
}
- (void)applicationWillResignActive:(UIApplication *)application {
NSLog(@"[DEBUG] applicationWillResignActive");
[player pause];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(@"[DEBUG] applicationDidBecomeActive");
[player play];
}
- (void)applicationWillTerminate:(UIApplication *)application {
[player stop];
}
@end