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

时间:2015-10-28 08:44:50

标签: ios video avfoundation avplayer avaudiosession

我有一个可以显示视频的应用,我希望以下行为。

  • 当视频首次出现在屏幕上并开始播放时,它的音频应与其他可能正在播放的应用的音频混合。例如,如果用户正在收听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 个答案:

答案 0 :(得分:1)

我觉得你运气不好。即使AVAudioSessionCategoryOptionDuckOthers,听起来应该适合您的使用案例,也要求您停用会话以将其他应用的音量恢复正常,但正如您所见,这会导致错误。

答案 1 :(得分:0)

也许您应该在“关闭混音模式”块中将“是”更改为“否”。

didReceiveMemoryWarning

答案 2 :(得分:0)

因此,正如其他答案所指出的那样,您可以“暂停”另一个应用程序的音频。但是,您可以使用.duckWithOthers将其关闭。音频播放完毕后,您可以将该选项重设为.mixWithOthers,并通知其他应用,它们的音量可以恢复到完整水平。

让我们假设您的音频在ViewController出现时开始播放,并在ViewController消失时停止播放。然后,您可以使用以下代码:

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)")
    }
  }