The way you manage your application's Audio Session has had some significant changes since iOS 6.0, and deserves a brief mention first. Before iOS 6.0 you would make use of AVAudioSession and AudioSessionServices classes, incorporating delegation and property listening respectively. From iOS 6.0 onwards use AVAudioSession class and incorporate notifications.
The following is for iOS 6.0 onwards.
To tell if other audio outside your applications sandbox is playing use -
// query if other audio is playing
BOOL isPlayingWithOthers = [[AVAudioSession sharedInstance] isOtherAudioPlaying];
// test it with...
(isPlayingWithOthers) ? NSLog(@"other audio is playing") : NSLog(@"no other audio is playing");
As for interruption handling you'll need to observe AVAudioSessionInterruptionNotification
and AVAudioSessionRouteChangeNotification
. So in the class that manages your audio session you could put something like the following - this should be called once at the start of the application lifecycle and don't forget to remove observer in the dealloc method of the same class.
// ensure we already have a singleton object
[AVAudioSession sharedInstance];
// register for notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(interruption:)
name:AVAudioSessionInterruptionNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(routeChange:)
name:AVAudioSessionRouteChangeNotification
object:nil];
And finally add the following selectors interruption:
and routeChange:
- these will receive a NSNotification
object that has a property called userInfo of type NSDictionary
that you read to assist any conditionals your application has.
- (void)interruption:(NSNotification*)notification {
// get the user info dictionary
NSDictionary *interuptionDict = notification.userInfo;
// get the AVAudioSessionInterruptionTypeKey enum from the dictionary
NSInteger interuptionType = [[interuptionDict valueForKey:AVAudioSessionInterruptionTypeKey] integerValue];
// decide what to do based on interruption type here...
switch (interuptionType) {
case AVAudioSessionInterruptionTypeBegan:
NSLog(@"Audio Session Interruption case started.");
// fork to handling method here...
// EG:[self handleInterruptionStarted];
break;
case AVAudioSessionInterruptionTypeEnded:
NSLog(@"Audio Session Interruption case ended.");
// fork to handling method here...
// EG:[self handleInterruptionEnded];
break;
default:
NSLog(@"Audio Session Interruption Notification case default.");
break;
} }
And similarly...
- (void)routeChange:(NSNotification*)notification {
NSDictionary *interuptionDict = notification.userInfo;
NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
switch (routeChangeReason) {
case AVAudioSessionRouteChangeReasonUnknown:
NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonUnknown");
break;
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
// a headset was added or removed
NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonNewDeviceAvailable");
break;
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
// a headset was added or removed
NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
break;
case AVAudioSessionRouteChangeReasonCategoryChange:
// called at start - also when other audio wants to play
NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonCategoryChange");//AVAudioSessionRouteChangeReasonCategoryChange
break;
case AVAudioSessionRouteChangeReasonOverride:
NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonOverride");
break;
case AVAudioSessionRouteChangeReasonWakeFromSleep:
NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonWakeFromSleep");
break;
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory");
break;
default:
break;
} }
There is no need to poll anything as long as you check the state of your applications audio session say for example in the viewDidLoad
of your root view controller, at the start of you apps lifecycle. Any changes from there onwards to your applications audio session will be known via these two main notifications. Replace the NSLog
statements with what ever your code needs to do based on the cases contained in the switch.
You can find more information about AVAudioSessionInterruptionTypeKey
and AVAudioSessionRouteChangeReasonKey
in the AVAudioSession
class reference documentation.
My apologies for the long answer but I think Audio Session management in iOS is rather fiddly and Apple's Audio Session Programming Guide, at the time of writing this, does not include code examples using notifications for interruption handling.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…