6

在我的 iPhone 应用程序中,我正在使用 AVAudioPlayer 播放歌曲...但是当我在播放歌曲期间拔出或插入耳机时,它会自动停止 AVAudioPlayer...即使发生这些更改,我也需要运行音频播放器......任何想法将不胜感激。在此先感谢。

4

7 回答 7

10

首先,你必须告诉AVAudioSession你的应用程序的音频行为。Apple 将其命名为音频会话类别,可以通过以下方式设置

[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];

例如AVAudioSessionCategoryPlayback

使用此类别时,您的应用程序音频会在静音开关设置为静音或屏幕锁定时继续播放。(该开关在 iPhone 上称为响铃/静音开关。)

此类别通常会阻止来自其他应用的音频与您应用的音频混合。要允许此类别的混音,请使用 kAudioSessionProperty_OverrideCategoryMixWithOthers 属性。

然后,一旦音频会话设置,应用程序将响应一些音频通知,如AVAudioSessionInterruptionNotificationAVAudioSessionRouteChangeNotification

要回答,原始问题AVAudioSessionRouteChangeNotification是在更改音频路由时调用的(例如:耳机插入/插入,还有蓝牙设备关闭,...)。通过一些代码,我们可以找到路由改变的原因。并且,在我们的例子中,在耳机被拔下时再次启动播放器。

- (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];
    }
}

最后,还要考虑一个用户,在一次无聊的会议中,他不小心拔掉了他的耳机。他不会有这种让设备突然在房间里尖叫的行为!

于 2016-05-04T07:24:03.367 回答
4

斯威夫特 3

设置您的播放器 - 播放音频(即使在静音模式下)并使其他音乐/播客静音:

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)

路线变化观察者(修复播放期间拔掉耳机):

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

斯威夫特 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)

路线变更观察者:

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()
      }
    }
  }
}
于 2017-03-11T03:20:17.663 回答
2

我知道这是旧帖子,但我对此进行了一些研究。@Martin 的回答是正确的,我使用的是 NSNotificationCenter 但我使用的是 Swift3,所以这些是你可以从 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 */

这是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)")
        }
    }
}
于 2016-12-14T11:55:14.943 回答
0

这是处理此问题的最佳教程:(在 iOS7 上也运行良好)

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

于 2014-08-18T09:21:35.277 回答
0

@Martin 几乎是对的,除了当我们收到AVAudioSessionRouteChangeNotification通知时,音频可能仍在播放,您必须检查播放器的rate属性。如果为零,则播放它,否则您应该观察rate,当它变为零时,播放它。检查链接

另一个注意事项是AVAudioSessionRouteChangeNotification发布在辅助线程(不是主线程)上,如果需要,您应该将其分派到主线程。

于 2018-08-30T06:47:09.833 回答
0

感谢@budidino Swift 5 及更高版本

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()
          }
        }
      }
    }
于 2020-11-17T18:28:05.803 回答
-1

我找到了答案。

只是我们必须导入以下内容

#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVAudioPlayer.h>

并写下这段代码

//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];

现在即使我插入和拔出耳机,它也会持续播放。

于 2013-09-26T07:52:14.253 回答