简体   繁体   English

如何在 Avfoundation 中正确更改采样率

[英]How to change sample rate properly in Avfoundation

I have done this simple program.我已经完成了这个简单的程序。 what it does is it just record and play back the buffers simultaneously.它所做的只是同时记录和回放缓冲区。 Everything works fine if the sample rate is 44100 hz but if I change the sample rate to 16000 or 8000, it doesn't producing any sound at all or may be some white noise which is not audiable.Why is this happening?如果采样率为 44100 hz,一切正常,但如果我将采样率更改为 16000 或 8000,它根本不会产生任何声音,或者可能是一些听不见的白噪声。为什么会发生这种情况?

How can I record with different sample rate?如何以不同的采样率进行录制?

Following code I have tried:以下代码我试过:

import UIKit
import AVFoundation

class ViewController: UIViewController  {

var engine = AVAudioEngine()
let player = AVAudioPlayerNode()
let audioSession = AVAudioSession.sharedInstance()
let newSrc:UnsafeMutablePointer<Float>! = nil
override func viewDidLoad() {
super.viewDidLoad()



let audioSession = AVAudioSession.sharedInstance()
print(audioSession.sampleRate) // here it prints 44100 hz. because it still using the internal mic.
do {

    try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .allowBluetooth)
    try audioSession.setMode(AVAudioSessionModeDefault)
    try audioSession.setActive(true)

} catch {
}
print(audioSession.sampleRate) // here it will print 16000 hz if my bluetooth earbuds is connected, if not it will be 44100 hz.

let input = engine.inputNode
let bus = 0
let mixer = AVAudioMixerNode() // creating mixer as it is needed to set audio format

engine.attach(mixer)
engine.attach(player)
engine.connect(input, to: mixer, format: input.outputFormat(forBus: 0))

let inputFormat = input.inputFormat(forBus: bus)

engine.connect(player, to: engine.mainMixerNode, format: input.inputFormat(forBus: 0))

let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100.0, channels: 1, interleaved: false)

mixer.installTap(onBus: bus, bufferSize: 1024, format: fmt) { (buffer, time) -> Void in

    print(buffer.format)
    print(buffer.floatChannelData)
    print(buffer.format.streamDescription.pointee.mBytesPerFrame)
    self.player.scheduleBuffer(buffer)
    if self.player.isPlaying {
        print("true")
    }
}


engine.prepare()
do{
    try! engine.start()
    player.play()
} catch {
    print(error)
}
}

}

As discussed here , neither AVAudioEngine mixer nodes nor taps will do rate conversion for you.正如这里讨论的,无论是AVAudioEngine混音器节点还是抽头都不会为您进行速率转换。 In fact in your case instead of throwing or logging an error, the mixer tap silently (get it?) gives you silence.事实上,在你的情况下,而不是抛出或记录错误,混音龙头默默地(明白了吗?)让你沉默。

Since you can't use an AVAudioMixerNode for rate conversion, you can replace it with the convenient AVAudioConverter , making sure to set the correct output format of the AVAudioPlayerNode because由于您不能使用AVAudioMixerNode进行速率转换,您可以将其替换为方便的AVAudioConverter ,确保设置正确的AVAudioPlayerNode输出格式,因为

When playing buffers, there is an implicit assumption that the buffers are at the same sample rate as the node's output format.在播放缓冲区时,有一个隐含的假设,即缓冲区的采样率与节点的输出格式相同。

If you don't do this you may hear gaps and/or pitch shifted audio.如果您不这样做,您可能会听到间隙和/或音调偏移的音频。

Like so像这样

let input = engine.inputNode
let bus = 0
let inputFormat = input.inputFormat(forBus: bus)

engine.attach(player)

let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)!
engine.connect(player, to: engine.mainMixerNode, format: fmt)

let converter = AVAudioConverter(from: inputFormat, to: fmt)!

input.installTap(onBus: bus, bufferSize: 1024, format: inputFormat) { (buffer, time) -> Void in
    let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
        outStatus.pointee = AVAudioConverterInputStatus.haveData
        return buffer
    }

    let convertedBuffer = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: AVAudioFrameCount(fmt.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!

    var error: NSError? = nil
    let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
    assert(status != .error)

    print(convertedBuffer.format)
    print(convertedBuffer.floatChannelData)
    print(convertedBuffer.format.streamDescription.pointee.mBytesPerFrame)
    self.player.scheduleBuffer(convertedBuffer)
}

This solution worked for me这个解决方案对我有用

let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)!
    inputNode.installTap(onBus: 0, bufferSize: 1024, format: fmt) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
        self.recognitionRequest?.append(buffer)
    }

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

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