AVAudioSession .defaultToSpeaker更改麦克风输入 [英] AVAudioSession .defaultToSpeaker changes mic input

查看:154
本文介绍了AVAudioSession .defaultToSpeaker更改麦克风输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an app taps the microphone and also play sounds depending on mic input(don't have to be simultaneously tho) This code below works. But one problem is the output plays on the small top speaker and not the bottom real loud speakers. I could solve this problem strangely by putting the 3 lines below just before the player starts, Then I can hear the sound on speakers. But then the microphone stops listening! Even after the player stops playing. Basically mic does not like when it is

.defaultToSpeaker

.defaultToSpeaker

有什么主意吗?

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

Here also documented what I am trying to do is correct:

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

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

UPDATE: I minimized the problem. No Player just mic. Code below, mic does not "work" when it is ".defaultToSpeaker". After some debugging I realized that defaultToSpeaker switches the mic from "bottom" to "front". And

 try preferredPort.setPreferredDataSource(source)

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

Cant seem to change it to bottom again. (I can provide code for this) And when category is defaultToSpeaker apperantly the tap buffer framelength is 4800 and not 4410. This difference seem causes trouble in my code because I need exactly 44100. So mic is actually working, but later in code it fails to do its job due to different SR. Below code can explain more.

 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是必需的.但是,如果这样做,我可以提供更多代码.

In this case I seem to have 2 options. Either solve problem on mic level, if possible make this code work with ".defaultToSpeaker". Or don't use category .playandrecord But switch between .playback and .record when mic is not needed. This didn't seem to be easy too, since it requires a lot of starting/stopping of all audio, which is necessary for activate and deactive AVAudioSession. But if this is the way to go I can provide more code.

推荐答案

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

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);

没有没有帮助.

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

This difference seems to cause problems later in my code. So mic was actually working, but later in code it was failing to do its job due to a different framelength.

解决方案/解决方法是我基本上在水龙头中对帧长进行了硬编码.因为我使用转换器,所以我不希望这是一个问题.这意味着我可以设置".defaultToSpeaker",并且麦克风仍按预期工作.

Solution/workaround was I basically hardcoded the framelength in the tap. Since I use a converter I don't expect this to be a problem. This means I can set ".defaultToSpeaker" And mic is still working as expected.

容量= 4410(DUH!)

capacity = 4410 (DUH!)

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

Maybe there are different/better ways to approach this problem. So feel free to add your answer if so.

这篇关于AVAudioSession .defaultToSpeaker更改麦克风输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆