iOS Swift проигрывает аудио (aac) из сетевого потока - PullRequest
0 голосов
/ 26 июня 2018

Я занимаюсь разработкой приложения для iOS, и я довольно новичок в разработке для iOS. До сих пор я реализовал h264-декодер из сетевого потока с использованием VideoToolbox, что было довольно сложно. Теперь мне нужно воспроизвести аудиопоток, исходящий из сети, но без участия файла, только необработанный поток AAC, считываемый непосредственно из сокета. Этот поток поступает из выходных данных экземпляра ffmpeg. Проблема в том, что я не знаю, как начать с этого, кажется, есть немного информации по этой теме. Я уже пробовал с AVAudioPlayer, но нашел только тишину. Я думаю, что сначала мне нужно распаковать пакеты из потока, как с помощью декодера h264.

Я пробовал также с AVAudioEngine и AVAudioPlayerNode, но безуспешно, так же, как с AVAudioPlayer. Может ли кто-нибудь дать мне руководство? Может быть AudioToolbox? AudioQueue

Большое спасибо за помощь:)

Edit: Я играю с AVAudioCompressedBuffer и без ошибок использую AVAudioEngine и AVAudioNode. Но я не знаю, что означает этот вывод:

inBuffer: <AVAudioCompressedBuffer@0x6040004039f0: 0/1024 bytes>

Значит ли это, что буфер пуст? Я пытался заполнить этот буфер несколькими способами, но всегда возвращает что-то вроде 0/1024. Я думаю, что я не делаю это правильно:

compressedBuffer.mutableAudioBufferList.pointee = audioBufferList

Есть идеи?

Спасибо!

Редактировать 2: Я редактирую для отражения моего кода для распаковки буфера. Может быть, кто-то может указать мне в правильном направлении. Примечание. Пакет, который принимается этой функцией, фактически передается без заголовка ADTS (9 байт), но я также попытался передать его с заголовком.

func decodeCompressedPacket(packet: Data) -> AVAudioPCMBuffer {

    var packetCopy = packet
    var streamDescription: AudioStreamBasicDescription = AudioStreamBasicDescription.init(mSampleRate: 44100, mFormatID: kAudioFormatMPEG4AAC, mFormatFlags: UInt32(MPEG4ObjectID.AAC_LC.rawValue), mBytesPerPacket: 0, mFramesPerPacket: 1024, mBytesPerFrame: 0, mChannelsPerFrame: 1, mBitsPerChannel: 0, mReserved: 0)
    let audioFormat = AVAudioFormat.init(streamDescription: &streamDescription)
    let compressedBuffer = AVAudioCompressedBuffer.init(format: audioFormat!, packetCapacity: 1, maximumPacketSize: 1024)

    print("packetCopy count: \(packetCopy.count)")
    var audioBuffer: AudioBuffer = AudioBuffer.init(mNumberChannels: 1, mDataByteSize: UInt32(packetCopy.count), mData: &packetCopy)
    var audioBufferList: AudioBufferList = AudioBufferList.init(mNumberBuffers: 1, mBuffers: audioBuffer)
    var mNumberBuffers = 1
    var packetSize = packetCopy.count
    // memcpy(&compressedBuffer.mutableAudioBufferList[0].mBuffers, &audioBuffer, MemoryLayout<AudioBuffer>.size)
    // memcpy(&compressedBuffer.mutableAudioBufferList[0].mBuffers.mDataByteSize, &packetSize, MemoryLayout<Int>.size)
    // memcpy(&compressedBuffer.mutableAudioBufferList[0].mNumberBuffers, &mNumberBuffers, MemoryLayout<UInt32>.size)

    // compressedBuffer.mutableAudioBufferList.pointee = audioBufferList

    var bufferPointer = compressedBuffer.data

    for byte in packetCopy {
        memset(compressedBuffer.mutableAudioBufferList[0].mBuffers.mData, Int32(byte), MemoryLayout<UInt8>.size)
    }

    print("mBuffers: \(compressedBuffer.audioBufferList[0].mBuffers.mNumberChannels)")
    print("mBuffers: \(compressedBuffer.audioBufferList[0].mBuffers.mDataByteSize)")
    print("mBuffers: \(compressedBuffer.audioBufferList[0].mBuffers.mData)")


    var uncompressedBuffer = uncompress(inBuffer: compressedBuffer)
    print("uncompressedBuffer: \(uncompressedBuffer)")
    return uncompressedBuffer
}

1 Ответ

0 голосов
/ 27 июня 2018

Таким образом, вы правы, полагая, что вам (скорее всего) нужно будет распаковать пакеты, полученные из потока. Идея состоит в том, чтобы перевести их в необработанный формат PCM, чтобы их можно было отправлять непосредственно на аудиовыход. Таким образом, вы также можете применить любые аудио / видео манипуляции, которые вы хотите, к аудио потоку.


Как вы упомянули, вам, вероятно, нужно смотреть в направлении AudioQueue, и документы Apple предоставляют хороший пример потокового аудио в режиме реального времени , хотя это в obj-c (в этом На мой взгляд, это может быть хорошей идеей для выполнения этого в obj-c). Это, пожалуй, лучшее место для начала (взаимодействие obj-c с swift - это super simple ).


Еще раз посмотрев на него в Swift, есть класс AVAudioCompressedBuffer , который, кажется, обрабатывает AAC для вашего случая (не нужно будет декодировать AAC, если вы заставите это работать), однако прямого метода нет Я полагаю, что для установки буфера так, как он предназначен для того, чтобы быть просто контейнером хранения. Вот рабочий пример того, как кто-то использует AVAudioCompressedBuffer вместе с AVAudioFile (может быть, вы можете буферизовать все в файлы в фоновых потоках? Я думаю, это будет слишком много IO).

Однако, если вы решите эту проблему в obj-c, появится сообщение о том, как установить AVAudioPCMBuffer (возможно, работает с AVAudioCompressedBuffer?) Напрямую через memset (что-то вроде перебора, но в то же время прекрасен как встроенный программист сам).

// make a silent stereo buffer  
AVAudioChannelLayout *chLayout = [[AVAudioChannelLayout alloc] initWithLayoutTag:kAudioChannelLayoutTag_Stereo];  
AVAudioFormat *chFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32  
                                                          sampleRate:44100.0  
                                                          interleaved:NO  
                                                        channelLayout:chLayout];  

AVAudioPCMBuffer *thePCMBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:chFormat frameCapacity:1024];  

thePCMBuffer.frameLength = thePCMBuffer.frameCapacity;  

for (AVAudioChannelCount ch = 0; ch < chFormat.channelCount; ++ch) {  
    memset(thePCMBuffer.floatChannelData[ch], 0, thePCMBuffer.frameLength * chFormat.streamDescription->mBytesPerFrame);  
}  

Я знаю, что это много, и ни в коем случае не кажется простым решением, но я думаю, что техника obj-c AudioQueue была бы моей первой остановкой!

Надеюсь, это поможет!

...