为 AVAudioEngine 设置音频输入节点会导致外部音频停止

问题描述 投票:0回答:1

我正在构建一个允许用户录制语音笔记的应用程序。所有功能都运行良好;我现在正在尝试对 AudioSession 进行更改,以管理来自其他应用程序的可能的音频流。我希望这样,如果有来自不同应用程序的音频播放,并且用户打开我的应用程序;音频继续播放。当我们开始录制时,任何第三方应用程序音频都应该停止,然后当我们停止录制时可以再次恢复。

这是我的主要音频设置代码:

    private var audioEngine: AVAudioEngine!
    private var inputNode: AVAudioInputNode!

    func setupAudioEngine() {
        audioEngine = AVAudioEngine()
        inputNode = audioEngine.inputNode
        audioPlayerNode = AVAudioPlayerNode()
        audioEngine.attach(audioPlayerNode)

        let format = AVAudioFormat(standardFormatWithSampleRate: AUDIO_SESSION_SAMPLE_RATE, channels: 1)
        audioEngine.connect(audioPlayerNode, to: audioEngine.mainMixerNode, format: format)
    }

    private func setupAudioSession() {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth])
            try audioSession.setPreferredSampleRate(AUDIO_SESSION_SAMPLE_RATE)
            try audioSession.setPreferredIOBufferDuration(0.005) // 5ms buffer for lower latency
            try audioSession.setActive(true)
            
            // Add observers
            setupInterruptionObserver()
        } catch {
            audioErrorMessage = "Failed to set up audio session: \(error)"
        }
    }

这一切都是在应用程序启动时调用的,因此我们准备好在用户按下录制按钮时进行录制。

但是,目前发生这种情况时,任何外部音频都会停止播放。

我将问题隔离到这一行:

inputNode = audioEngine.inputNode

当它被注释掉时,音频将会播放——但我显然需要它来实现录音功能。

这是一个错误吗?预期的行为?

ios swift avfoundation avaudiosession avaudioengine
1个回答
0
投票

所以,你遇到的事情实际上是 iOS 在处理音频会话时故意做的事情,尤其是 playAndRecord 类别。当您的应用程序开始使用带有

AVAudioSessionCategoryPlayAndRecord
的麦克风时,iOS 往往会暂停或降低其他应用程序的音频音量,以便它可以专注于录音。

如果您希望您的应用程序能够在不停止其他应用程序中的音乐或播客的情况下录制音频,直到您真正开始录制,然后在完成后继续录制,您可以在设置时使用

mixWithOthers
选项音频会话。但请记住,一旦您点击录制,您将需要更改会话以停止其他音频。

以下是更详细的细分:

首先,设置音频会话以允许与其他人混合:

private func setupInitialAudioSession() {
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth, .mixWithOthers])
        try audioSession.setPreferredSampleRate(AUDIO_SESSION_SAMPLE_RATE)
        try audioSession.setPreferredIOBufferDuration(0.005) // 5ms buffer for lower latency
        try audioSession.setActive(true)
        
        // Add obsevers
        setupInterruptionObserver()
    } catch {
        audioErrorMessage = "Failed to set up initial audio session: \(error)"
    }
}

接下来,在开始录制时更改音频会话类别:

private func startRecording() {
    let audioSession = AVAudioSession.sharedInstance()
    do {
        // Update the audio session to not mix with others during recording
        try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth])
        try audioSession.setActive(true)
        
        // Start your audio engine and recording process
        audioEngine.prepare()
        try audioEngine.start()
    } catch {
        audioErrorMessage = "Failed to start recording: \(error)"
    }
}

然后在停止录制时将其改回来:

private func stopRecording() {
    let audioSession = AVAudioSession.sharedInstance()
    do {
        // Stop the audio engine and recording process
        audioEngine.stop()
        
        // Update the audio session to allow mixing with others again
        try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth, .mixWithOthers])
        try audioSession.setActive(true)
    } catch {
        audioErrorMessage = "Failed to stop recording: \(error)"
    }
}

因此,通过最初设置 mixWithOthers 选项,您可以让其他应用程序音频在您的应用程序运行时播放。当您开始录制时,您会切换到更严格的类别,从而暂停其他音频。录制完成后,您可以返回原始设置。

确保处理可能出现的任何错误并顺利管理这些状态转换,以便为用户提供良好的体验。并在实际设备上进行明确的测试,以确保音频行为符合您的预期。

希望这有帮助! 卡尔

© www.soinside.com 2019 - 2024. All rights reserved.