AVAudioSession 类别变为 nil 并且 mediaServicesWereReset,avplayer 播放一直失败

Posted

技术标签:

【中文标题】AVAudioSession 类别变为 nil 并且 mediaServicesWereReset,avplayer 播放一直失败【英文标题】:AVAudioSession category becomes nil and mediaServicesWereReset, avplayer playback keeps failing 【发布时间】:2020-01-26 06:32:08 【问题描述】:

我们的团队有一个应用程序可以使用 avplayer 在线播放 m4a 资源。最近有用户抱怨播放一直失败,不知道是什么原因。

我们检查了用户日志,avplayer错误日志如下(针对多个失败实例):

avPlayer.currentItem.error = Error Domain=AVFoundationErrorDomain Code=-11800 "操作无法完成" UserInfo=NSLocalizedFailureReason=发生未知错误(-16155),NSLocalizedDescription=操作无法完成,NSUnderlyingError= 0x280e6ef10 Error Domain=NSOSStatusErrorDomain Code=-16155 "(null)" avPlayer.currentItem.error = Error Domain=AVFoundationErrorDomain Code=-11800 "操作无法完成" UserInfo=NSLocalizedFailureReason=发生未知错误 (606068440),NSLocalizedDescription=操作无法完成,NSUnderlyingError=0x280e9f8d0 错误域=NSOSStatusErrorDomain 代码=606068440 "(null)" avPlayer.currentItem.error = 错误域=AVFoundationErrorDomain 代码=-11800 "操作无法完成" UserInfo=NSLocalizedFailureReason=发生未知错误 (1705376704),NSLocalizedDescription=操作无法完成,NSUnderlyingError=0x281ec60d0 错误域=NSOSStatusErrorDomain 代码=1705376704 "(null)"

我们开始玩的正常流程:(按大多数用户的预期工作)

    [[AVAudiosession sharedInstance] setActive:YES error:&activationError]; 调用 [avplayer play] 音频开始播放成功

失败场景:(对于某些用户,这种场景不断发生)

    激活错误返回 Error Domain=NSOSStatusErrorDomain Code=2003329396 "(null)" 我们记录了 [AVAudioSession sharedInstance].category 为空 收到 mediaServicesWereReset 通知 avplayer 播放失败,观察到上述 avplayer item 错误之一

当用户失败一次,他无法在我们的应用中播放任何音频资源,并且场景不断重复。

我们想知道:

    为什么会在某些用户设备上出现这种情况? 如何防止问题发生? 有没有办法从丢失的 mediaService 中恢复?这样即使出现一次错误,用户仍然可以在我们的应用中播放其他资源。

即使我们尝试了开发者菜单中的重置媒体服务,我们也无法自己产生失败的场景,行为并不完全相同。期待社区的任何帮助,谢谢。

【问题讨论】:

你解决了这个问题吗? 【参考方案1】:

我不能肯定地回答你的前两个问题,但苹果对你最后一个问题的回答如下:

收到AVAudioSessionMediaServicesWereResetNotification 通知,应用程序应该:

释放孤立的音频对象并创建新的音频对象 重置任何被跟踪的内部音频状态,包括所有属性 AVAudioSession 在适当的时候,重新激活AVAudioSession 使用 setActive:error: 方法

有关更多信息,请参阅https://developer.apple.com/library/archive/qa/qa1749/_index.html

至于我对你前两个问题的猜测:

    此问题可能并非特定于某些用户设备,而可能是随机的。我在 Apple 中看到了一个类似的、非常罕见的问题,它提供了来自客户设备的崩溃日志,直到今天我才能重现。现在,我终于能够通过在自动测试中简单地重复应用程序的正常操作数千次来重现该问题。在极少数情况下,iOS 会重置音频会话媒体服务,并导致会话激活或停用失败。在这种情况下,延迟一段时间后重新启动音频会话似乎可以解决问题。 (不过我仍在测试,因为每次测试都需要几个小时才能重现问题)。 考虑到我上面链接的 Apple 技术说明并没有提供任何可以避免重置音频会话媒体服务的迹象,我猜可能没有办法可靠地防止它发生。您激活/停用音频会话的频率越低(或次数越少),发生此问题的可能性就越小,但最终对于某些任意用户仍可能发生。这就是为什么正确的做法是假设 AVAudioSessionMediaServicesWereResetNotification 有时是不可避免的,因此按上述方式处理它。

【讨论】:

【参考方案2】:

在我的情况下@Arda's answer 是 100% 正确的。我的错误是:

AVError(_nsError: Error) 的相关 decl 'e' Domain=AVFoundationErrorDomain Code=-11800 "操作不能 已完成" UserInfo=NSLocalizedFailureReason=未知错误 发生 (-10851), NSLocalizedDescription=操作不能 完成,NSUnderlyingError=0x280e96310 错误 Domain=NSOSStatusErrorDomain Code=-10851 "(null)")

捕获会话的.AVCaptureSessionRuntimeError 通知是捕获错误的原因:

NotificationCenter.default.addObserver(self, selector: #selector(sessionRuntimeError),
                                           name: .AVCaptureSessionRuntimeError,
                                           object: nil)


@objc func sessionRuntimeError(notification: NSNotification) 
    guard let error = notification.userInfo?[AVCaptureSessionErrorKey] as? AVError else  return 
    print("Capture session runtime error: \(error)")

    if error.code == .mediaServicesWereReset 
        // ...        
     else 

       // ERROR WAS HERE because the AVAudioSession was no longer active
       // 1. restart AVAudioSession
       // 2. restart capture session
    

在我的情况下,我在推送到另一个 vc 时停止了 captureSession,在弹回时我重新启动了捕获会话。出于某种原因,我的AVAudioSession.sharedInstance().setCategory 失败了,这就是错误的原因。

要修复它,我必须再次重新启动AVAudioSession然后重新启动我的捕获会话。

【讨论】:

以上是关于AVAudioSession 类别变为 nil 并且 mediaServicesWereReset,avplayer 播放一直失败的主要内容,如果未能解决你的问题,请参考以下文章

带有路由变化的 AVAudioSession 红色状态栏

Swift:设置 AVAudioSession 输出音量

变量在完成处理程序之外变为 nil [重复]

在 Swift 3 中使用 prepareForSegue 分配对象变为 nil

AVAudioSession - 捕获 setMode 和 setCategory 错误

如何取消 AVAudioSession