一尘不染

AVAudioSession .defaultToSpeaker更改麦克风输入

swift

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

.defaultToSpeaker

任何想法?

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

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

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

 try preferredPort.setPreferredDataSource(source)

似乎无法再次将其更改为底部。(我可以为此提供代码)并且当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()

}

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


阅读 412

收藏
2020-07-07

共1个答案

一尘不染

感谢所有花时间发表评论的人。我从每条评论中学到了新东西。好像我找到了解决方案。这实际上很简单。当AVAudioSession类别显然是.defaultToSpeaker(或overrideOutputAudioPort)时,抽头输入缓冲区的帧长将从4410更改为4800。

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

AVAudioSession.sharedInstance().setInputDataSource(datasource);

没有 帮助。

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

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

容量= 4410(DUH!)

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

2020-07-07