Practical test
This was working as of October 2014:
- Launch the Youtube app on an iPhone
- Plug headphones
- Launch a video that has a preroll ad (depending on capping, it should be quite easy to find one that has it)
- While the ad is playing, unplug your headphones
The ad should have paused and you have no way of unpausing it or accessing the video you wanted to see. You might try to plug the headphones back but it won’t work. Now, when you do the same thing on an actual video, you get the expected behavior:
- While playing a video, unplugging headphones pauses the video and lets you unpause it
- While playing a video, plugging headphones doesn’t interrupt the video
This is explained in Apple’s documentation in a pretty straight-forward way:
You might think: “well if the player (here the Ad uses AVPlayer) paused, it should have sent a notification telling my code that its state changed. Fixing this issue is just a matter of getting this state change and acting according to it.”
Well, if that was the case I wouldn’t have to write an article about it, would I!
The thing is, Apple’s documentation (See Audio Session Programming Guide: Responding To Route Changes) is pretty clear about the matter but nobody ever wrote a practical example on how to use Audio Output notifications to check if headphones have been plugged while playing a video.
So after digging the web, and especially Stack Overflow for a practical solution that does not exist, here is my take at it! Hope it will help!
Audio Output Route Changed Notification
Here is what iOS gives us to listen and act upon audio output route changes:
AVAudioSessionRouteChangeNotification
So, we just have to subscribe to it and we will know every time the audio output route changes. Add yourself as an observer:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioHardwareRouteChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
Then implement the method you passed as a selector:
- (void)audioHardwareRouteChanged:(NSNotification *)notification {
// Your tests on the Audio Output changes will go here
}
Using the notification’s user info to understand what happened
The AVAudioSessionRouteChangeNotification provides two important objects:
-
An
AVAudioSessionRouteDescription
object containing the previous route’s description. Accessible via the keyAVAudioSessionRouteChangePreviousRouteKey
-
An
NSNumber
object containing anunsigned integer
that identifies the reason why the route changed. Accessible via the keyAVAudioSessionRouteChangeReasonKey
If you just want to know when the headphones were unplugged, you should use this code:
NSInteger routeChangeReason = [notification.userInfo[AVAudioSessionRouteChangeReasonKey] integerValue];
if (routeChangeReason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
// The old device is unavailable == headphones have been unplugged
}
Here, you don’t need to check if the previous route were the headphones or not, because the only thing you want to know (and the logic behind iOS pausing the video when the headphones are unplugged) is this: When the device used for output becomes unavailable, pause.
This is great because that means your code will also work in other cases, like if you use bluetooth headphones and you walk out of range of the app, or their batteries die. Also, it won’t pause when you plug headphones back, because this is considered by the OS as a new device becoming available, sending the reason AVAudioSessionRouteChangeReasonNewDeviceAvailable
To go further
The AVAudioSessionRouteChangeNotification
‘s associated user info is full of interesting data on what happened to the audio output route, and the different routes available and recognized by iOS. Be sure to check Apple’s documentation and especially:
- Audio Session Programming Guide: Responding to Route Changes
- AVAudioSessionRouteChangeNotification Documentation
From there, you should be able to access all the documentation you need to, for example, detect when the device is connected to a docking station, etc.
Hope this will help,
Right here is the perfect website for anybody who would like to understand this topic. You understand so much its almost tough to argue with you (not that I really would want to…HaHa). You certainly put a brand new spin on a subject that’s been discussed for ages. Great stuff, just excellent!