AVAudioSession在混合和非混合模式之间切换

6
我有一个可以播放视频的应用程序,并希望实现以下功能。
  • 当视频首次出现在屏幕上并开始播放时,其音频应与其他可能已经在播放的应用程序的音频混合。例如,如果用户正在听Spotify,则应同时听到Spotify和播放视频的音频。

  • 如果用户点击特定按钮,则应静音其他应用程序的音频,只播放视频的音频。

  • 如果用户再次点击按钮,则其他应用程序的音频应恢复,视频的音频和其他应用程序的音频应再次混合。

基本上,我想能够在我的应用程序中切换音频模式,分别为“混合”和“非混合”。

以下是一些代码,展示了我如何修改AVAudioSession以尝试获得此功能。

打开混合模式

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryAmbient
         withOptions:AVAudioSessionCategoryOptionMixWithOthers
               error:nil];
[session setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];

关闭混合模式

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback
         withOptions:0
               error:nil];
[session setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];

我遇到的问题是,在关闭音频混合后再打开,不会通知其他应用程序可以恢复播放音频。我真的非常希望有这种行为。这是否有可能呢?
似乎唯一通知其他应用可以恢复的方法是将我的应用程序的音频会话设置为“非活动”。不幸的是,当视频正在播放时这样做会在控制台上输出一个警告,说我应该在停止播放声音之前停用音频会话。这也导致了基本上破坏了AVPlayer的效果,因为它无法再播放任何音频。
有人知道如何解决这些问题吗?任何解决方案都将受到欢迎,包括那些相当复杂或使用私有API的解决方案。
3个回答

2

正如其他答案所指出的那样,您可以“暂停”另一个应用程序的音频。但是,您可以使用.duckWithOthers将其降低。一旦您的音频完成,您可以将该选项重置回.mixWithOthers并通知其他应用程序,它们的音量可以恢复到完整水平。

假设您的音频在视图控制器出现时开始播放,并在视图控制器消失时停止播放。然后,您可以使用以下代码:

override func viewWillAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Use duckOthers so the audio in your VC is slightly louder than the background audio such as Spotify
    updateAVAudioSessionOptions(to: .duckOthers)
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    // Reset to mixWithOthers since we are no longer playing audio
    updateAVAudioSessionOptions(to: .mixWithOthers)

    // probably a good idea to stop the audio as well
    player.pause() 
  }

  private func updateAVAudioSessionOptions(to options: AVAudioSession.CategoryOptions) {
    do {
      try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: options)

      if options == .mixWithOthers {
        // Notify other apps that they volume can be restored to the full level
        try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
      }

    } catch let error {
      print("Error: \(error)")
    }
  }

1
我认为你运气不佳。即使是听起来似乎适合你使用情况的AVAudioSessionCategoryOptionDuckOthers,也需要你停用会话以将其他应用程序的音量恢复正常,但正如你所看到的,这会导致错误。

是的,我担心就是这种情况。那如果有什么办法可以欺骗iOS向其他进程发送“从中断恢复”通知呢? - Antonio
你认为扩展会有自己的音频会话吗? - Rhythmic Fistman

0
也许你应该在“关闭混合模式”块中将“YES”改为“NO”。
[session setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];

问题在于,当视频正在播放时,我无法将音频会话设置为非活动状态。AVPlayer不支持这样做,之后它将无法播放声音。您需要暂停并重新播放视频才能从中恢复。 - Antonio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接