如何在使用 AVPlayer 播放视频之前检测 AirPlay 是否处于活动状态?

How to detect if AirPlay is active before playing a video with AVPlayer?

我使用下面的代码来检测 AirPlay 是否是当前选择的路由:

let airPlayActive = AVAudioSession
  .sharedInstance()
  .currentRoute
  .outputs
  .first?
  .portType == .airPlay
print("AirPlay active: \(airPlayActive)")

但是,这在非常特定的情况下不起作用。我的用例是知道在播放视频之前选择了空中播放。我有两个视图控制器,比如 AB。出于测试目的,我在 A 上设置了一个计时器,它会使用上面的代码每秒打印一次 AirPlay 是否处于活动状态。

A,我呈现模态视图控制器 B,它基本上使用 AVPlayer 播放视频并控制当前使用 MPVolumeView 选择的路线。如果我显示 B,等待视频播放,然后将路由更改为 AirPlay,我可以看到该更改反映在 A(它将开始打印 true)。然后,如果我关闭 B 然后重新打开它,就可以在播放视频之前判断 AirPlay 是否处于活动状态,这正是我想要的。

但在某些情况下这不起作用。

场景是(看起来很奇怪),如果我使用 MPRemoteCommandCenter 将目标添加到远程命令,我上面描述的行为就会发生变化!这是我添加目标的方式(在视图控制器 B 中):

let center = MPRemoteCommandCenter.shared()
let pauseCommand = center.pauseCommand
pauseCommand.isEnabled = true
pauseCommand.addTarget(handler: { _ -> MPMPRemoteCommandHandlerStatus in
  // ... doing some business logic
  return .success
})

我也在 Bdeinit:

中删除了那个目标
let center = MPRemoteCommandCenter.shared()
let pauseCommand = center.pauseCommand
pauseCommand.isEnabled = false
pauseCommand.addTarget(nil)

好吧,这完全混淆了所有与 AirPlay 相关的东西:

  1. 如果我在视图控制器 B 上激活 AirPlay 然后关闭它,AirPlay 将被停用。现在当前 portType 再次变为 .builtInSpeaker。因此,在重新打开 B(播放视频)之前,我无法判断 AirPlay 是否处于活动状态。

  2. 即使 portType 在关闭 B 后是 .builtInSpeaker,如果我调用 MPVolumeView().isWirelessRouteActive,它告诉我无线路由处于活动状态,但这不一定是 AirPlay(例如,它可能是蓝牙耳机)。

  3. 如果我重新打开 BportType 会在视频开始播放后从 .builtInSpeaker 变为 .airPlay

  4. 音频路由更改通知也停止正常工作。观察AVAudioSession.routeChangeNotification时,有时不触发,触发时,AVAudioSessionRouteChangeReasonKey的用户信息大部分时间是.unknown.

对我来说,这显然是 Apple 方面的一个错误,但是你们中有人碰巧知道替代方案吗?在播放视频之前,我基本上需要知道 AirPlay 是否处于活动状态。

谢谢!

好吧,我找到了解决方法。它和问题本身一样奇怪,但它正在工作...

我刚刚在视图控制器上播放视频之前向远程命令添加了一个目标 B。然后我只是等待音频路由更改通知(或者在不活动的情况下超时)。这表明 "safe" 可以播放视频。