AVAudioSession .defaultToSpeaker更改麦克风输入

Spr*_*ing 7 avfoundation avaudioplayer ios swift audiokit

我有一个应用程序可以点击麦克风,还可以根据麦克风输入播放声音(不必同时通过tho)。下面的代码有效。但是一个问题是输出在小型顶部扬声器而不是底部真实扬声器上播放。我可以通过在播放器开始播放之前将3行放在下面来奇怪地解决此问题,然后我可以听到扬声器上的声音。但随后麦克风停止收听!即使在播放器停止播放之后。基本上麦克风不喜欢

.defaultToSpeaker

任何的想法?

这里也记录了我想做的是正确的:

https://developer.apple.com/documentation/avfoundation/avaudiosession/categoryoptions/1616462-defaulttospeaker

更新: 我最小化了问题。没有球员只是麦克风。下面的代码是“ .defaultToSpeaker”时,mic无法“工作”。经过一些调试后,我意识到defaultToSpeaker将麦克风从“底部”切换到“前部”。和

 try preferredPort.setPreferredDataSource(source)
Run Code Online (Sandbox Code Playgroud)

似乎无法再次将其更改为底部。(我可以为此提供代码)并且当category为defaultToSpeaker时,tap缓冲区的帧长显然是4800而不是4410。这种差异似乎在我的代码中造成了麻烦,因为我需要44100。所以mic实际上正在工作,但是稍后在代码中失败了由于SR不同而无法胜任。下面的代码可以解释更多。

 func tapMicrophone() {
    try? AVAudioSession.sharedInstance().setActive(false)
    try? AVAudioSession.sharedInstance().setCategory(.playAndRecord,  options: [.defaultToSpeaker])
    //setBottomMic()
    try? AVAudioSession.sharedInstance().setActive(true)

    //tracker.start()
    let input = engine.inputNode
    let inputFormat = input.outputFormat(forBus: 0)
    let sampleRate = Double(11025)
    let outputFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: sampleRate, channels: 1, interleaved: true)!
    let converter = AVAudioConverter(from: inputFormat, to: outputFormat)!
    let inputBufferSize = 44100 //  100ms of 44.1K = 4410 samples.
    let sampleRateRatio = 44100 / sampleRate

    input.installTap(onBus: 0, bufferSize: AVAudioFrameCount(inputBufferSize), format: inputFormat) {
        buffer, time in
        var error: NSError? = nil
        let capacity = Int(Double(buffer.frameCapacity) / sampleRateRatio)
        let bufferPCM16 = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(capacity))!
        converter.convert(to: bufferPCM16, error: &error) { inNumPackets, outStatus in
            outStatus.pointee = AVAudioConverterInputStatus.haveData
            return buffer
        }
    }

    engine.prepare()
    try! engine.start()

}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我似乎有2个选择。可以在麦克风级别解决问题,如果可能的话,请使此代码与“ .defaultToSpeaker”一起使用。或不要使用.playandrecord类别,而是在不需要麦克风时在.playback和.record之间切换。这似乎也不容易,因为它需要大量启动/停止所有音频,这对于激活和停用AVAudioSession是必需的。但是,如果这样做,我可以提供更多代码。

Spr*_*ing 7

Thanks to everyone who took the time to comment. I learned new things from each comment. Seems like I found a solution. Which is actually very simple. When AVAudioSession category is .defaultToSpeaker (Or overrideOutputAudioPort) apparently the tap input buffer framelength changes to 4800 from 4410.

无论使用哪种麦克风,都会发生这种奇怪的情况。所以用

AVAudioSession.sharedInstance().setInputDataSource(datasource);
Run Code Online (Sandbox Code Playgroud)

没有帮助。

这种差异似乎在稍后的代码中引起问题。因此mic实际上可以正常工作,但是在后来的代码中,由于帧长不同,它无法完成工作。

解决方案/解决方法是我基本上将水龙头的帧长硬编码。由于我使用转换器,所以我认为这不会成为问题。这意味着我可以设置“ .defaultToSpeaker”,并且麦克风仍按预期运行。

容量= 4410(DUH!)

也许有不同/更好的方法来解决此问题。因此,请随意添加答案。