我正在开发一个iOS应用程序,而我对iOS开发还是很新的。到目前为止,我已经使用VideoToolbox从网络流中实现了h264解码器,这非常困难。
现在,我需要播放来自网络的音频流,但是不涉及任何文件,只需直接从套接字读取原始AAC流即可。此流来自ffmpeg实例的输出。
问题是我不知道如何开始,似乎关于此主题的信息很少。我已经尝试过AVAudioPlayer
,但发现只是沉默。我想我首先需要从流中解压缩数据包,就像使用h264解码器一样。
我一直在尝试使用AVAudioEngine
和AVAudioPlayerNode
,但没有成功,与AVAudioPlayer
相同。有人可以给我一些指导吗?也许AudioToolbox
? AudioQueue
?
非常感谢您的帮助:)
编辑:
我正在玩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
}
答案 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
技术将是我的第一站!
希望这会有所帮助!