IOS AudioUnit проблема с треском при воспроизведении (swift) - PullRequest
3 голосов
/ 11 ноября 2019

Я пытаюсь воспроизвести байты, поступающие от UDP с устройства Android в IOS. Я использую TPCircularBuffer для воспроизведения байтов. Мой код ниже:

let success = initCircularBuffer(&circularBuffer, 1024)
        if success {
            print("Circular buffer init was successful")
        } else {
            print("Circular buffer init not successful")
        }



func udpReceive() {
        receivingQueue.async {
            repeat {
                do {
                    let datagram = try self.tcpClient?.receive()
                    let byteData = datagram?["data"] as? Data
                    let dataLength = datagram?["length"] as? Int
                    self.dataLength = dataLength!

                    let _ = TPCircularBufferProduceBytes(&self.circularBuffer, byteData!.bytes, UInt32(dataLength! * MemoryLayout<UInt8>.stride * 2))

                } catch {
                    fatalError(error.localizedDescription)
                }
            } while true
        }


    }

    func consumeBuffer() -> UnsafeMutableRawPointer? {
        self.availableBytes = 0
        let tail = TPCircularBufferTail(&self.circularBuffer, &self.availableBytes)
        return tail
    }

Мы записываем с частотой дискретизации 16 КБ и отправляем в IOS через UDP со стороны Android, и оттуда мы используем AudioUnit для воспроизведения наших байтов, но проблема заключается в потрескивании и звук отсечения в нашем голосе.

Код обратного вызова для воспроизведения:

func performPlayback(
        _ ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
        inTimeStamp: UnsafePointer<AudioTimeStamp>,
        inBufNumber: UInt32,
        inNumberFrames: UInt32,
        ioData: UnsafeMutablePointer<AudioBufferList>
    ) -> OSStatus {

        var buffer = ioData[0].mBuffers             

        let bufferTail = consumeBuffer()

        memcpy(buffer.mData, bufferTail, min(self.dataLength, Int(availableBytes)))
        buffer.mDataByteSize = UInt32(min(self.dataLength, Int(availableBytes)))


        TPCircularBufferConsume(&self.circularBuffer, UInt32(min(self.dataLength, Int(availableBytes))))

        return noErr
    }

UDP отправляет нам 1280 байт на выборку. Мы считаем, что проблема в том, что размер буфера установлен неправильно. Может кто-нибудь направить меня, как установить правильный размер буфера. Это было бы действительно полезно. Я знаю работу @Gruntcakes в качестве инженера voip https://stackoverflow.com/a/57136561/12020007. Я также изучал работу @ hotpaw2 и смотрел на https://stackoverflow.com/a/58545845/12020007, чтобы проверить, есть ли какая-то проблема с многопоточностью. Любая помощь будет оценена.

1 Ответ

4 голосов
/ 12 ноября 2019

Обратный вызов аудиоустройства должен возвращать только запрошенное количество кадров (выборок), как указано параметром inNumberFrames. Ваш код, похоже, копирует несколько разное количество семплов в AudioBufferList, что не сработает, поскольку аудиоустройство iOS будет отправлять только запрошенное количество кадров на аудиовыход.

Вы можете указать предпочтительную длительность буфера в конфигурации аудио сеанса, но это только предложение. iOS может свободно игнорировать это предложение и использовать inNumberFrames, которые лучше соответствуют звуковому оборудованию устройства, активности системы и текущему состоянию питания.

Не забудьте предварительно заполнить циклический буфер достаточно для учетадля максимального ожидаемого времени джиттера в сети (UDP). Возможно, измерить дрожание задержки между пакетами в сети и вычислить его статистику, min, max, std.dev. и т. д.

Если ваши буферы UDP не имеют степени 2 или содержат сэмплы, которые не имеют аппаратной частоты дискретизации iOS, то вам также придется учитывать дробный буфер и джиттер повторной выборки вВаша безопасность буферизует накладные расходы.

...