AVAudioSession .defaultToSpeaker меняет микрофонный вход - PullRequest
7 голосов
/ 29 апреля 2019

У меня есть приложение, которое касается микрофона, а также воспроизводит звуки в зависимости от микрофонного входа (не обязательно одновременно). Этот код ниже работает.Но одна проблема заключается в том, что выход воспроизводится на маленьком верхнем динамике, а не на нижних реальных громких динамиках.Я мог бы решить эту проблему странным образом, поместив 3 строки ниже непосредственно перед запуском проигрывателя , затем я могу услышать звук на динамиках. Но тогда микрофон перестает слушать !Даже после того, как игрок перестает играть.В основном микрофон не любит, когда он

.defaultToSpeaker

Любая идея?

Здесь также задокументировано, что я пытаюсь сделать правильно:

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

ОБНОВЛЕНИЕ: Я минимизировал проблему.Нет игрока, просто микрофон.Код ниже, микрофон не «работает», когда он «.defaultToSpeaker».После некоторой отладки я понял, что defaultToSpeaker переключает микрофон с «нижнего» на «передний».И

 try preferredPort.setPreferredDataSource(source)

Кажется, не могу снова изменить его на дно.(Я могу предоставить код для этого) А когда категория defaultToSpeaker, по-видимому, имеет длину кадра буфера крана 4800, а не 4410. Эта разница, кажется, вызывает проблемы в моем коде, потому что мне нужно ровно 44100. Таким образом, микрофон действительно работает, но позже в коде он не работаетделать свою работу из-за разных СР.Ниже код может объяснить больше.

 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.Но если это путь, я могу предоставить больше кода.

1 Ответ

7 голосов
/ 04 мая 2019

Спасибо всем, кто нашел время для комментариев. Я узнал что-то новое из каждого комментария. Похоже, я нашел решение. Что на самом деле очень просто. Когда категория AVAudioSession равна .defaultToSpeaker (или overrideOutputAudioPort), по-видимому, длина кадра входного буфера отводов изменяется с 4810 на 4800.

Это странно происходит независимо от того, какой микрофон используется . Таким образом, используя

AVAudioSession.sharedInstance().setInputDataSource(datasource);

Помогает ли .

Эта разница, кажется, позже вызывает проблемы в моем коде. Микрофон действительно работал, но позже в коде он не справлялся со своей задачей из-за другой длины кадра.

Решение / обходной путь, в котором я жестко закодировал длину кадра в кране. Поскольку я использую конвертер, я не ожидаю, что это станет проблемой. Это означает, что я могу установить «.defaultToSpeaker», и микрофон все еще работает как положено.

вместимость = 4410 (DUH!)

Возможно, есть другие / лучшие способы решения этой проблемы. Поэтому не стесняйтесь добавлять свой ответ, если так.

...