Как правильно изменить частоту дискретизации в Avfoundation - PullRequest
0 голосов
/ 17 мая 2018

Я сделал эту простую программу.он просто записывает и воспроизводит буферы одновременно.Все работает нормально, если частота дискретизации составляет 44100 Гц, но если я изменяю частоту дискретизации на 16000 или 8000, она вообще не производит никакого звука или может быть каким-то белым шумом, который не поддается проверке. Почему это происходит?

Как записать с другой частотой дискретизации?

Следующий код, который я пробовал:

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

}

1 Ответ

0 голосов
/ 20 мая 2018

Как обсуждено здесь , ни AVAudioEngine узлы микшера, ни отводы не будут выполнять преобразование скорости для вас. На самом деле, в вашем случае вместо того, чтобы выдавать или регистрировать ошибку, смеситель тихо (понятно?) Дает вам молчание.

Поскольку вы не можете использовать AVAudioMixerNode для преобразования тарифов, вы можете заменить его на удобное AVAudioConverter, убедившись, что вы установили правильный выходной формат AVAudioPlayerNode, поскольку

При воспроизведении буферов существует неявное предположение, что буферы находятся на одном уровне. частота дискретизации в качестве выходного формата узла.

Если вы этого не сделаете, вы можете услышать пропуски и / или звук со сдвигом высоты тона.

Вот так

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)
}
...