iOS Swift播放网络流中的音频(aac)

时间:2018-06-26 15:56:14

标签: ios swift audiotoolbox

我正在开发一个iOS应用程序,而我对iOS开发还是很新的。到目前为止,我已经使用VideoToolbox从网络流中实现了h264解码器,这非常困难。 现在,我需要播放来自网络的音频流,但是不涉及任何文件,只需直接从套接字读取原始AAC流即可。此流来自ffmpeg实例的输出。 问题是我不知道如何开始,似乎关于此主题的信息很少。我已经尝试过AVAudioPlayer,但发现只是沉默。我想我首先需要从流中解压缩数据包,就像使用h264解码器一样。

我一直在尝试使用AVAudioEngineAVAudioPlayerNode,但没有成功,与AVAudioPlayer相同。有人可以给我一些指导吗?也许AudioToolboxAudioQueue

非常感谢您的帮助:)

编辑: 我正在玩AVAudioCompressedBuffer,并且使用AVAudioEngineAVAudioNode时没有错误。但是,我不知道该输出意味着什么:

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 :(得分:4)

所以您认为正确(很可能)需要解压缩从流中接收到的数据包。想法是将它们转换为原始PCM格式,以便可以将其直接发送到音频输出。这样,您还可以将想要的任何DSP /音频处理应用于音频流。


正如您所提到的,您可能需要研究AudioQueue的方向,Apple Docs提供了streaming audio in realtime的一个很好的示例,尽管它在obj-c中(在这种情况下,我认为在obj-c中执行此操作可能是一个好主意。这可能是最好的入门指南(将obj-c与swift连接是super simple)。


在Swift中再次查看它,类AVAudioCompressedBuffer似乎可以处理您的情况下的AAC(如果您可以使用它,则无需解码AAC),但是没有直接的设置方法我认为,缓冲区仅用作存储容器。 Here's是一个使用AVAudioCompressedBuffer以及AVAudioFile的人的有效示例(也许您可以将所有内容缓冲到后台线程的文件中?我认为这会增加IO开销)。

但是,如果您在obj-c中解决此问题,则有一个post关于如何直接通过memset设置AVAudioPCMBuffer(可能与AVAudioCompressedBuffer一起使用)(有点令人讨厌,但同时)我自己是一名嵌入式程序员,非常可爱)。

// 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技术将是我的第一站!

希望这会有所帮助!