在我的 iPhone 应用程序中,我正在使用 AVAudioPlayer 播放歌曲...但是当我在播放歌曲期间拔出或插入耳机时,它会自动停止 AVAudioPlayer...即使发生这些更改,我也需要运行音频播放器......任何想法将不胜感激。在此先感谢。
7 回答
首先,你必须告诉AVAudioSession
你的应用程序的音频行为。Apple 将其命名为音频会话类别,可以通过以下方式设置
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
例如AVAudioSessionCategoryPlayback
:
使用此类别时,您的应用程序音频会在静音开关设置为静音或屏幕锁定时继续播放。(该开关在 iPhone 上称为响铃/静音开关。)
此类别通常会阻止来自其他应用的音频与您应用的音频混合。要允许此类别的混音,请使用 kAudioSessionProperty_OverrideCategoryMixWithOthers 属性。
然后,一旦音频会话设置,应用程序将响应一些音频通知,如AVAudioSessionInterruptionNotification
或AVAudioSessionRouteChangeNotification
要回答,原始问题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];
}
}
最后,还要考虑一个用户,在一次无聊的会议中,他不小心拔掉了他的耳机。他不会有这种让设备突然在房间里尖叫的行为!
斯威夫特 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()
}
}
}
}
我知道这是旧帖子,但我对此进行了一些研究。@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)")
}
}
}
这是处理此问题的最佳教程:(在 iOS7 上也运行良好)
@Martin 几乎是对的,除了当我们收到AVAudioSessionRouteChangeNotification
通知时,音频可能仍在播放,您必须检查播放器的rate
属性。如果为零,则播放它,否则您应该观察rate
,当它变为零时,播放它。检查链接
另一个注意事项是AVAudioSessionRouteChangeNotification
发布在辅助线程(不是主线程)上,如果需要,您应该将其分派到主线程。
感谢@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()
}
}
}
}
我找到了答案。
只是我们必须导入以下内容
#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];
现在即使我插入和拔出耳机,它也会持续播放。