[英]AVAudioSession error: Deactivating an audio session that has running I/O
2017-02-24 14:56:44.280 PropertyManager[10172:5336578] 14:56:44.280 ERROR: [0x1a0a24000] AVAudioSession.mm:692: -[AVAudioSession setActive:withOptions:error:]: Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
2017-02-24 14:56:44.281 PropertyManager[10172:5336578] error === Error Domain=NSOSStatusErrorDomain Code=560030580 "(null)"
PropertyManager was compiled with optimization - stepping may behave oddly; variables may not be available.
您的错误日志非常简洁地自我表达:
Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session
它会告诉您问题以及解决方案。
现在你正在做这样的事情:
[[AVAudioSession sharedInstance] setActive:NO
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:nil];
但是,您应该首先停止音频播放器实例,然后将激活状态设置为是或否。
[yourAudioPlayer stop];
[[AVAudioSession sharedInstance] setActive:NO
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:nil];
请参阅 Apple 文档以查看enum AudioSessionSetActiveOption 的值。
另请参阅:关于setActive:withOptions方法的 Apple 文档
至于你的第二个错误
PropertyManager was compiled with optimization - stepping may behave oddly; variables may not be available.
看到这个优秀的答案。
让音频播放器在录制会话假之前停止..如果你想让音频播放器为零..删除那条线..它对我有用..
@NSNoob是 100% 正确的。 播放器(或其他东西)仍处于活动状态。
这就是我使用dani-mp的解决方案做到的。 他说:
我会说暂停播放器不是同步操作,因此我们不应该在知道播放器已暂停之前停用会话(请参阅此线程中的响应)。
此问题的解决方案可能是我们监听 timeControlStatus 的更改并在播放器真正暂停后停用音频会话。
线程中的答案说
此错误表示在调用 AVAudioSession setActive:NO 时,您的应用程序中的某些内容仍在使用音频 I/O。 在没有更多信息的情况下无法说出哪个对象,但有时这是对某种播放器调用异步停止方法的结果,而不是在停用音频会话之前等待播放器已停止的通知。
要在后台播放音频并使用MPRemoteCommandCenter
我必须从.mixWithOthers
切换到.playback
阅读注释掉的代码中的 10 个步骤。
var player: AVPlayer?
var playerTimeControlStatusObserver: NSKeyValueObservation?
var wasPlayerPlayingBeforeItWentToTheBackground = false // 0. this is needed in steps 2 and 6
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
}
func checkIfPlayerWasPlayingWhenAppEntersBackground() { // 1. this gets called in the UIApplication.didEnterBackgroundNotification selector method
if let player = player, player.isPlaying {
wasPlayerPlayingBeforeItWentToTheBackground = true // 2. this is needed in step 6
player.pause() // 3. once the player is paused the `.timeControlStatus` will fire when it's 100% stopped
}
}
playerTimeControlStatusObserver = player?.observe(\.timeControlStatus, options: [.new, .old]) { [weak self](player, change) in
switch (player.timeControlStatus) {
// ... other cases
case .paused: // 4. read the very long function name to see what happens next. Once this .paused case runs the player is Definitely stopped.
DispatchQueue.main.async { [weak self] in
self?.checkTimeStatusAndApplicationStateToMakeSureThePlayerIsDefinitelyStoppedAndInTheBackground()
}
// ... other cases
}
}
func checkTimeStatusAndApplicationStateToMakeSureThePlayerIsDefinitelyStoppedAndInTheBackground() {
let state = UIApplication.shared.applicationState
if state == .background { // 5. this code only runs if it's in the background
if wasPlayerPlayingBeforeItWentToTheBackground { // 6. this has to be true
wasPlayerPlayingBeforeItWentToTheBackground = false // 7. set it back to false
do { // 8. deactivate the AVAudioSession
try AVAudioSession.sharedInstance().setActive(false)
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player?.play() // 9. resume play
} catch let err as NSError {
print(err.localizedDescription)
}
}
}
}
@objc func appDidEnterBackground() {
checkIfPlayerWasPlayingWhenAppEntersBackground() // 10. when the app is backgrounded run the code from step 1.
}
当然,当应用程序返回前台以暂停播放器时,我必须做同样的检查,检查.timeControlStatus
观察器,然后切换回.mixWithOthers
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.