AVAudioSession Audio Dimming Error: Deactivating an audio session that has running I/O

AVAudioSession Audio Dimming Error: Deactivating an audio session that has running I/O

我正在播放多种声音,每种声音都会使背景音频变暗。完成后,我恢复背景音频。每次播放其中一个音频文件时,背景都会变暗(根据需要)。当最后一个音频完成播放时,背景音频将恢复(也是需要的)。然而,大约 5 秒后,它抛出此错误并再次调暗音频(这不是我想要的,因为所有声音现在都已结束)。

ERROR: [0x19c9af310] AVAudioSession.mm:646: -[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.

据我所知,我正在停止并删除所有音频。

我在这里找到了 1 个 post:

iOS8 AVAudioSession setActive error

但是这个解决方案对我不起作用。这是我的音频播放器 class。如果您能提出建议,我将不胜感激。

import Foundation
import AVFoundation

private var _singleton:O_Audio? = O_Audio()
private var _avAudioPlayers:Array<AVAudioPlayer> = []

//Manages dimming and resuming background audio
class O_Audio:NSObject, AVAudioPlayerDelegate
{
    class var SINGLETON:O_Audio
    {
        if(_singleton == nil)
        {
            _singleton = O_Audio()
        }
        return _singleton!
    }

    class func dimBackgroundAudio()
    {
        AVAudioSession.sharedInstance().setActive(true, error: nil)
    }

    class func restoreBackgroundAudio()
    {
        AVAudioSession.sharedInstance().setActive(false, error: nil)
    }

    class func playSound(path:String)
    {
        var sound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(path, ofType: "m4a")!)
        var audioPlayer = AVAudioPlayer(contentsOfURL: sound, error: nil)
        _avAudioPlayers.append(audioPlayer)
        audioPlayer.delegate = O_Audio.SINGLETON
        audioPlayer.prepareToPlay()
        audioPlayer.play()
    }

    func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool)
    {
        //this was from the 1 stack post I found but these
        //two lines do not solve my problem
        player.stop()
        player.prepareToPlay()

        var index:Int!
        for i in 0..._avAudioPlayers.count - 1
        {
            if(_avAudioPlayers[i] == player)
            {
                index = i
                break
            }
        }

        _avAudioPlayers.removeAtIndex(index)

        if(_avAudioPlayers.count == 0)
        {
            O_Audio.restoreBackgroundAudio()
        }
    }

    func audioPlayerDecodeErrorDidOccur(player: AVAudioPlayer!, error: NSError!)
    {
        println("error")
    }
}

重要更新

所以我发现我认为是问题的大致原因。我们的应用程序是基于 Cordova 构建的。所以我们有很多 Safari(浏览器)调用。每当我们播放视频(通过 Safari 播放)时,就会出现此错误。似乎 Safari 正在以某种方式调暗音频并保持 运行 I/O 线程。

问题在于 MPMoviePlayerController 对象正在播放。事实上 Any AVPlayerItem 导致了这个。如果您播放电影并尝试调暗音频,您将收到此错误。

目前,在 iOS 上播放的任何电影都具有不可改变的音轨(即使电影文件中没有音频)。这会永久导致鸭子问题(它是源代码中的错误)。我尝试了很多解决方法,但没有任何效果。我确定这是一个 Xcode 源错误。

@Aggressor:您可以将音频类别更改为多路由,以便同时通过扬声器和耳机(如果插入)播放音频。

通过这种方式,您将不会获得变暗的音频。

我有同样的问题。 您必须调用 AVAudioSession.sharedInstance().setActive(true, error: nil);在 AVAudioSession.sharedInstance().setActive(false, error: nil);

之前

而且是成对出现

我遇到了同样的问题。我的应用程序使用 AVPlayer 播放视频(无声),偶尔在视频仍在播放时使用 AVQueuePlayer 播放简短的语音音频。现在,如果我在后台播放音乐(即通过 Spotify),音乐会在 AVQueuePlayer 播放时闪避,un-ducked 播放完后会短暂闪避,然后再次闪避。

我创建了一个示例应用程序来调试我的问题,发现我的 AVAudioSession 设置没有得到正确处理。最终对我有用的是:

在应用程序启动时将 AVAudioSession.CategoryOptions 设置为 .ambient,如下所示:

try AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers)

这将防止视频播放器中断音乐。

如果我 play/pause 我的 AVQueuePlayer 我使用这个函数再次更改我的类别:

func setAudioSession(to category: Category, activate: Bool = true) {
        switch category {
        case .default:
            // .ambient and .mixWithOthers so silent video won't interrupt background music
            setCategory(.ambient, options: .mixWithOthers, activate: activate)
        case .voiceOver:
            // .playback with .duckOthers will duck the music momentarily while short lasting audio is output, spoken audio will be interrupted by setting . interruptSpokenAudioAndMixWithOthers
            setCategory(.playback, options: [.duckOthers, .interruptSpokenAudioAndMixWithOthers], activate: activate)
        case .standalone:
            // For standalone audio use .playback without options so it will interrupt other background music, if you don't want the sound to play while the phone is on mute use .ambient instead
            setCategory(.playback, activate: activate)
        }
    }
    
    private func setCategory(_ category: AVAudioSession.Category, options: AVAudioSession.CategoryOptions = [], activate: Bool) {
        let session = AVAudioSession.sharedInstance()
        // Only set if needed
        guard session.category != category || session.categoryOptions != options else { return }
        // To change category, first setActive(false) -> change -> setActive(true)
        try? AVAudioSession.sharedInstance().setActive(false)
        try? AVAudioSession.sharedInstance().setCategory(category, options: options)
        if activate {
            try? AVAudioSession.sharedInstance().setActive(true)
        }
    }

enum Category {
        case `default`, voiceOver, standalone
    }

所以基本上是为了开始音频画外音

   @IBAction func playAudio(_ sender: UIButton) {
        self.setAudioSession(to: .voiceOver)
        audioPlayer.load(url: Bundle.main.url(forResource: "audio", withExtension: "mp3")!)
        audioPlayer.play()
    }

然后暂停(或队列结束后):

@IBAction func pauseAudio(_ sender: UIButton) {
    audioPlayer.pause()
    self.setAudioSession(to: .default)
}

⚠️ 免责声明:请注意我是如何 try? 而不是 do try catch 块,这是因为我仍然得到 Deactivating an audio session that has running I/O.错误。因此,如果我发现错误,它就不会再激活正确的会话。它仍然不理想,因为它总是会输出错误,但至少现在回避就像一个魅力。