Потоковое аудио с Swift

Я разрабатываю приложение, которое должно записывать голос пользователя и передавать его на настраиваемое устройство по протоколу MQTT. Спецификация звука для настраиваемого устройства: прямой порядок байтов, беззнаковый, 16-битный LPCM с частотой дискретизации 8 кГц. Пакеты должны быть по 1000 байт каждый.

Я не знаком с AudioEngine, и я нашел этот образец кода, который, как мне кажется, подходит для моего случая:

func startRecord() {
    audioEngine = AVAudioEngine()
    let bus = 0
    let inputNode = audioEngine.inputNode
    let inputFormat = inputNode.outputFormat(forBus: bus)
    
    var streamDescription = AudioStreamBasicDescription()
    streamDescription.mFormatID = kAudioFormatLinearPCM.littleEndian
    streamDescription.mSampleRate = 8000.0
    streamDescription.mChannelsPerFrame = 1
    streamDescription.mBitsPerChannel = 16
    streamDescription.mBytesPerPacket = 1000
    
    
    let outputFormat = AVAudioFormat(streamDescription: &streamDescription)!
    
    guard let converter: AVAudioConverter = AVAudioConverter(from: inputFormat, to: outputFormat) else {
        print("Can't convert in to this format")
        return
    }
    
    inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { (buffer, time) in
        print("Buffer format: \(buffer.format)")
        
        var newBufferAvailable = true
        
        let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
            if newBufferAvailable {
                outStatus.pointee = .haveData
                newBufferAvailable = false
                return buffer
            } else {
                outStatus.pointee = .noDataNow
                return nil
            }
        }
        
        let convertedBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!
        
        var error: NSError?
        let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
        assert(status != .error)
        
        print("Converted buffer format:", convertedBuffer.format)
    }
    
    audioEngine.prepare()
    
    do {
        try audioEngine.start()
    } catch {
        print("Can't start the engine: \(error)")
    }
    
}

Но в настоящее время конвертер не может преобразовать входной формат в мой выходной, и я не понимаю почему. Если я изменю свой выходной формат на что-то вроде этого:

let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 8000.0, channels: 1, interleaved: false)!

Тогда это работает.


person SunnyBunny27    schedule 11.12.2020    source источник


Ответы (1)


Ваш streamDescription неверен, вы не заполнили все поля и mBytesPerPacket ошиблись - это не тот тип пакета, который требует ваш протокол. Для несжатого звука (например, LPCM) AudioStreamBasicDescription требует, чтобы в этом поле было 1. Если ваш протокол требует, чтобы сэмплы располагались группами по 1000, вам придется это сделать.

Попробуй это

var streamDescription = AudioStreamBasicDescription()
streamDescription.mSampleRate = 8000.0
streamDescription.mFormatID = kAudioFormatLinearPCM
streamDescription.mFormatFlags = kAudioFormatFlagIsSignedInteger // no endian flag means little endian
streamDescription.mBytesPerPacket = 2
streamDescription.mFramesPerPacket = 1
streamDescription.mBytesPerFrame = 2
streamDescription.mChannelsPerFrame = 1
streamDescription.mBitsPerChannel = 16
streamDescription.mReserved = 0
person Rhythmic Fistman    schedule 11.12.2020
comment
Спасибо. Теперь это работает. - person SunnyBunny27; 12.12.2020