简体   繁体   English

AVAudioSession .defaultToSpeaker更改麦克风输入

[英]AVAudioSession .defaultToSpeaker changes mic input

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. 我有一个应用程序轻拍麦克风,并根据麦克风输入播放声音(不必同时tho)下面的代码工作。 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. 我可以通过在播放器启动之前放下3行来奇怪地解决这个问题,然后我可以听到扬声器上的声音。 But then the microphone stops listening ! 但麦克风停止听 Even after the player stops playing. 即使在玩家停止播放之后。 Basically mic does not like when it is 基本上麦克风不喜欢它

.defaultToSpeaker .defaultToSpeaker

Any idea? 任何想法?

Here also documented what I am trying to do is correct: 这里还记录了我想要做的是正确的:

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

UPDATE: I minimized the problem. 更新:我最小化了问题。 No Player just mic. 没有玩家只是麦克风。 Code below, mic does not "work" when it is ".defaultToSpeaker". 下面的代码,当它是“.defaultToSpeaker”时,麦克风“不起作用”。 After some debugging I realized that defaultToSpeaker switches the mic from "bottom" to "front". 经过一些调试后,我意识到defaultToSpeaker将麦克风从“底部”切换到“前部”。 And

  try preferredPort.setPreferredDataSource(source) 

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. (我可以为此提供代码)当类别为defaultToSpeaker时,浮点缓冲区帧长度为4800而不是4410.这种差异似乎导致我的代码出现问题,因为我需要的确是44100.所以mic实际上正在工作,但后来在代码中失败了由于不同的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()

}

In this case I seem to have 2 options. 在这种情况下,我似乎有两个选择。 Either solve problem on mic level, if possible make this code work with ".defaultToSpeaker". 要么解决麦克风级别的问题,请尽可能使此代码与“.defaultToSpeaker”一起使用。 Or don't use category .playandrecord But switch between .playback and .record when mic is not needed. 或者不要使用类别.playandrecord但是当不需要麦克风时,在.playback和.record之间切换。 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. 这似乎也不容易,因为它需要大量启动/停止所有音频,这对于激活和停用AVAudioSession是必需的。 But if this is the way to go I can provide more code. 但如果这是要走的路,我可以提供更多的代码。

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类别为.defaultToSpeaker (或overrideOutputAudioPort )时,显然抽头输入缓冲区帧长度从4410变为4800。

This strangely happens regardless of which microphone is used . 无论使用哪种麦克风,都会发生奇怪的情况 So using 所以使用

AVAudioSession.sharedInstance().setInputDataSource(datasource);

Does not help. 没有帮助。

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. 因此,麦克风实际上正在工作,但后来在代码中,由于帧长不同,它无法完成工作。

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. 这意味着我可以设置“.defaultToSpeaker”并且麦克风仍然按预期工作。

capacity = 4410 (DUH!) 容量= 4410(DUH!)

Maybe there are different/better ways to approach this problem. 也许有不同/更好的方法来解决这个问题。 So feel free to add your answer if so. 如果是这样,请随时添加您的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM