使用Swift允许后台音频不起作用。

4

我希望在应用程序不在焦点时允许后台音频播放。目前我有这段代码,应该可以实现这一点:

do {
    try AKSettings.setSession(category: .playback, with: .mixWithOthers)
} catch {
    print("error")
}
AKSettings.playbackWhileMuted = true

我还在能力设置中启用了“音频,Airplay和画中画”选项。然而,当我按下设备上的主页按钮时,音频不会继续播放。我做错了什么?如果有影响,我正在使用AudioKit来产生声音。
我正在使用单例来存储所有的AudioKit组件,我将其命名为AudioPlayer.swift。以下是我在AudioPlayer.swift单例文件中的内容:
class AudioPlayer: NSObject {
    var currentFrequency = String()
    var soundIsPlaying = false

    var leftOscillator = AKOscillator()
    var rightOscillator = AKOscillator()

    var rain = try! AKAudioFile()
    var rainPlayer: AKAudioPlayer!

    var envelope = AKAmplitudeEnvelope()

    override init() {
        super.init()

        do {
            try AKSettings.setSession(category: .playback, with: .mixWithOthers)
        } catch {
            print("error")
        }
        AKSettings.playbackWhileMuted = true

        AudioKit.output = envelope
        AudioKit.start()
    }

    func setupFrequency(left: AKOscillator, right: AKOscillator, frequency: String) {
        currentFrequency = frequency

        leftOscillator = left
        rightOscillator = right

        let leftPanner = AKPanner(leftOscillator)
        leftPanner.pan = -1

        let rightPanner = AKPanner(rightOscillator)
        rightPanner.pan = 1

        //Set up rain and rainPlayer
        do { 
            rain = try AKAudioFile(readFileName: "rain.wav")
            rainPlayer = try AKAudioPlayer(file: rain, looping: true, deferBuffering: false, completionHandler: nil)
        } catch { print(error) }

        let mixer = AKMixer(leftPanner, rightPanner, rainPlayer)

        //Put mixer in sound envelope
        envelope = AKAmplitudeEnvelope(mixer)
        envelope.attackDuration = 2.0
        envelope.decayDuration = 0
        envelope.sustainLevel = 1
        envelope.releaseDuration = 0.2

        //Start AudioKit stuff
        AudioKit.output = envelope
        AudioKit.start()
        leftOscillator.start()
        rightOscillator.start()
        rainPlayer.start()
        envelope.start()
        soundIsPlaying = true
    }
}

这是我的一个音效视图控制器的示例,它引用了AudioKit单例来发送特定的频率(我有大约十几个这样的视图控制器,每个都有自己的频率设置):
class CalmView: UIViewController {
    let leftOscillator = AKOscillator()
    let rightOscillator = AKOscillator()

    override func viewDidLoad() {
        super.viewDidLoad()

        leftOscillator.amplitude = 0.3
        leftOscillator.frequency = 220

        rightOscillator.amplitude = 0.3
        rightOscillator.frequency = 230
    }

    @IBAction func playSound(_ sender: Any) {
        if shared.soundIsPlaying == false {
            AudioKit.stop()
            shared.setupFrequency(left: leftOscillator, right: rightOscillator, frequency: "Calm")
        } else if shared.soundIsPlaying == true && shared.currentFrequency != "Calm" {
            AudioKit.stop()
            shared.leftOscillator.stop()
            shared.rightOscillator.stop()
            shared.rainPlayer.stop()
            shared.envelope.stop()
            shared.setupFrequency(left: leftOscillator, right: rightOscillator, frequency: "Calm")
        } else {
            shared.soundIsPlaying = false
            shared.envelope.stop()
        }
    }
}

我在ViewController.swift文件中实例化了AudioPlayer单例。

1
在编程中,有一个微妙的界限,即拥有足够的代码和过多的代码之间。你提出的问题已经在下面得到了回答。你似乎已经正确设置了一切。测试一下AudioKit示例SongProcessor,看看它是否按照预期运行,然后将你的代码与之进行比较。有时候并没有捷径和简单的解决方案。 - Aurelius Prochazka
1个回答

3
这取决于你的配置是在何时与AudioKit启动相关。如果你正在使用AudioKit,应该使用它的AKSettings来管理你的会话类别。基本上不仅包括播放类别,还包括mixWithOthers。默认情况下,如下所示:
/// Set the audio session type
@objc open static func setSession(category: SessionCategory,
                            with options: AVAudioSessionCategoryOptions = [.mixWithOthers]) throws {

那么在你的ViewController中,你可以这样做:

    do {
        if #available(iOS 10.0, *) {
            try AKSettings.setSession(category: .playAndRecord, with: [.defaultToSpeaker, .allowBluetooth, .allowBluetoothA2DP])
        } else {
            // Fallback on earlier versions
        }
    } catch {
        print("Errored setting category.")
    }

所以我认为问题出在这里。设置互操作音频可能会有所帮助。如果您仍然遇到问题并提供更多信息,我可以提供更多帮助,但这是我根据您目前提供的信息所能给出的最好答案。


我应该在这些设置完成后启动AudioKit还是在之前启动?现在我在ViewController.swift中有这段代码,但我在另一个视图控制器中启动了AudioKit。这可能会导致问题吗? - 5AMWE5T
1
如果您首先进行设置,AudioKit可能会覆盖它们。我不建议在视图控制器中处理任何音频。相反,为您的音频创建一个单例类 - 有时我们将其称为引擎或指挥者,并从所有视图控制器引用它。您不希望视图控制器生命周期对音频引擎的状态产生任何影响。 - Aurelius Prochazka
我将我的音频播放器放在单例中,并将代码从原始帖子中移入其中,但问题仍然存在。 - 5AMWE5T
我刚刚直接使用了你更新后的问题中的代码,证明了AudioKit的SongProcessor示例可以在后台播放,因此我的回答对你的问题是有效的。也许你做错了其他什么事情。https://github.com/AudioKit/AudioKit/commit/0dcde9b4865133f61a6fd70c2e921c75aeb9b8e4 - Aurelius Prochazka
我需要把这段代码放在特定的位置吗?我从你的链接中复制了高亮部分并将其放入我的AudioPlayer.swift单例中,但它仍然无法工作。 - 5AMWE5T
是的,这就是正确的地方。由于你没有提供代码,所以无法回答你的问题。我已经给你提供了一个带有SongProcessor的工作示例。这应该足够了。 - Aurelius Prochazka

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