avoid Headset plugout stops AVAudioPlayer in iOS

ぃ、小莉子 提交于 2019-12-12 08:10:13

问题


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.


回答1:


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!




回答2:


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()
      }
    }
  }
}



回答3:


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)")
        }
    }
}



回答4:


This is the best tutorial dealing this issue: (working well also on iOS7)

http://www.techotopia.com/index.php/Detecting_when_an_iPhone_Headphone_or_Docking_Connector_is_Unplugged_(iOS_4)




回答5:


@Martin is almost right except when we get AVAudioSessionRouteChangeNotification notification, the audio may still playing, 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 AVAudioSessionRouteChangeNotification is posted on a secondary thread (not main thread), you should dispatch it to main thread if needed.




回答6:


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.



来源:https://stackoverflow.com/questions/17103148/avoid-headset-plugout-stops-avaudioplayer-in-ios

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!