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.
I found the answer.
Just we have to Import the followings
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVAudioPlayer.h>
and write this code
//Play the Event in Background
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryErr];
[[AVAudioSession sharedInstance] setActive: YES error: &activationErr];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
Now its continuously playing even I plugged in&out the Ear phone.
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!
NSNotification.Name.AVAudioSessionRouteChange
–
Lunseth 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()
}
}
}
}
rawValue
instead of hashValue
? –
Snowball rawValue
worked for me instead of hashValue
, don't know if hashValue
is working in Swift 3. –
Snowball 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)")
}
}
}
@Martin is almost right except when we get AVAudioSessionRouteChangeNotification
notification, the audio may still play, you must check player's rate
property. If it is zero, play it, otherwise you should observe rate
, when it change to zero, play it. Check the link
Another note is that AVAudioSessionRouteChangeNotification
is posted on a background thread (not main thread), you should dispatch it to the main thread if needed.
thanks to @budidino Swift 5 and above
let audioSession = AVAudioSession.sharedInstance()
_ = try? audioSession.setCategory(AVAudioSession.Category.playback, options: .duckOthers)
_ = try? audioSession.setActive(true)
NotificationCenter.default.addObserver(self, selector: #selector(audioRouteChanged), name: AVAudioSession.routeChangeNotification, object: nil)
@objc func audioRouteChanged(note: Notification) {
if let userInfo = note.userInfo {
if let reason = userInfo[AVAudioSessionRouteChangeReasonKey] as? Int {
if reason == AVAudioSession.RouteChangeReason.oldDeviceUnavailable.rawValue {
// headphones plugged out
self.avPlayer?.play()
}
}
}
}
This is the best tutorial dealing this issue: (working well also on iOS7)
I found the answer.
Just we have to Import the followings
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVAudioPlayer.h>
and write this code
//Play the Event in Background
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryErr];
[[AVAudioSession sharedInstance] setActive: YES error: &activationErr];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
Now its continuously playing even I plugged in&out the Ear phone.
© 2022 - 2024 — McMap. All rights reserved.