In my iPhone app I am using AVAudioPlayer to play the songs...But when I plug out or plugin the headset during song playing, It automatically stops the AVAudioPlayer... I need to run audio player even though these changes occur.. any ideas will be appreciated.Thanks in advance.
First, you have to tell AVAudioSession
the audio behaviour of your app. Apple name this the audio session category, an can be set by
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
For example, AVAudioSessionCategoryPlayback
:
When using this category, your app audio continues with the Silent switch set to silent or when the screen locks. (The switch is called the Ring/Silent switch on iPhone.)
This category normally prevents audio from other apps from mixing with your app's audio. To allow mixing for this category, use the kAudioSessionProperty_OverrideCategoryMixWithOthers property.
Then, once the audio session set, the app will respond to some audio notifications, like AVAudioSessionInterruptionNotification
or AVAudioSessionRouteChangeNotification
To answer, the original question, AVAudioSessionRouteChangeNotification
is called when the audio route has been changed (ex: headset plug-out/plug-in, but also bluetooth device turning off, ...). With a bit of code, we can find the route change reason. And, in our case, start the player again il the headset has been unplugged.
- (void)viewDidLoad {
[super viewDidLoad];
NSError *setCategoryErr;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
// Detects when the audio route changes (ex: jack unplugged)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioHardwareRouteChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
// Don't forget to remove notification in dealloc method!!
}
- (void)audioHardwareRouteChanged:(NSNotification *)notification {
NSInteger routeChangeReason = [notification.userInfo[AVAudioSessionRouteChangeReasonKey] integerValue];
if (routeChangeReason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
// if we're here, the player has been stopped, so play again!
[self.player play];
}
}
To conclude, also think about a user, in a boring meeting, who accidentaly plug-out his headset. He would not have this kind of behaviour, whose would make the device suddently scream in the room!
Swift 3
Setup your player - play audio (even on silent mode) and silence other music / podcasts:
let audioSession = AVAudioSession.sharedInstance()
_ = try? audioSession.setCategory(AVAudioSessionCategoryPlayback, with: .duckOthers)
_ = try? audioSession.setActive(true)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(audioRouteChanged), name: .AVAudioSessionRouteChange, object: nil)
Route change observer (fix for unplugging headphones during playback):
func audioRouteChanged(note: Notification) {
if let userInfo = note.userInfo {
if let reason = userInfo[AVAudioSessionRouteChangeReasonKey] as? Int {
if reason == AVAudioSessionRouteChangeReason.oldDeviceUnavailable.rawValue {
// headphones plugged out
player.play()
}
}
}
}
Swift 2
let audioSession = AVAudioSession.sharedInstance()
_ = try? audioSession.setCategory(AVAudioSessionCategoryPlayback, withOptions: .DuckOthers)
_ = try? audioSession.setActive(true)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(audioRouteChanged), name: AVAudioSessionRouteChangeNotification, object: nil)
Route change observer:
func audioRouteChanged(note: NSNotification) {
if let userInfo = note.userInfo {
if let reason = userInfo[AVAudioSessionRouteChangeReasonKey] as? Int {
if reason == AVAudioSessionRouteChangeReason.OldDeviceUnavailable.rawValue {
// headphones plugged out -> continue playback
player.play()
}
}
}
}
I know this is old post but i did some research about this. @Martin answer was correct and i am using NSNotificationCenter but i am using Swift3 so these are things you can get from notification.userInfo
case AVAudioSessionInterruptionNotificationKey
/* value is an NSNumber representing an AVAudioSessionInterruptionType */
case AVAudioSessionInterruptionOptionsKey */
/* Only present for end interruption events. Value is of type AVAudioSessionInterruptionOptions.*/
case AVAudioSessionRouteChangeReasonKey */
/* value is an NSNumber representing an AVAudioSessionRouteChangeReason */
case unknown
case newDeviceAvailable
case oldDeviceUnavailable
case categoryChange
case override
case wakeFromSleep
case noSuitableRouteForCategory
case routeConfigurationChange
case AVAudioSessionRouteChangePreviousRouteKey * */
/* value is AVAudioSessionRouteDescription * */
case input
case output
case AVAudioSessionSilenceSecondaryAudioHintTypeKey */
/* value is an NSNumber representing an AVAudioSessionSilenceSecondaryAudioHintType */
Here is method in swift3
func audioSessionRouteChange(notification: NSNotification) {
if let userInfo = notification.userInfo {
print("Notification: AVAudioSessionInterruptionTypeKey = \(userInfo[AVAudioSessionInterruptionTypeKey])")
print("Notification: AVAudioSessionInterruptionOptionKey = \(userInfo[AVAudioSessionInterruptionOptionKey])")
print("Notification: AVAudioSessionSilenceSecondaryAudioHintTypeKey = \(userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey])")
if let reason = userInfo[AVAudioSessionRouteChangeReasonKey] as? Int {
print("Notification: AVAudioSessionRouteChangeReasonOldDeviceUnavailable")
if reason == AVAudioSessionRouteChangeReason.oldDeviceUnavailable.hashValue {
print("Notification: Headphones out")
}
if reason == AVAudioSessionRouteChangeReason.newDeviceAvailable.hashValue {
print("Notification: Headphones in")
}
}
if let description = userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription {
// here you can check previous input and output
// po description.outputs[0].portType == AVAudioSessionPortBuiltInSpeaker
print("Notification: AVAudioSessionRouteChangePreviousRouteKey Inputs: \(description.inputs)")
print("Notification: AVAudioSessionRouteChangePreviousRouteKey Outputs: \(description.outputs)")
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With