简体   繁体   English

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

[英]iOS Swift playing audio (aac) from network stream

I'm developing an iOS application and I'm quite new to iOS development. 我正在开发一个iOS应用程序,我对iOS开发很新。 So far I have implemented a h264 decoder from network stream using VideoToolbox, which was quite hard. 到目前为止,我已经使用VideoToolbox从网络流中实现了h264解码器,这非常困难。 Now I need to play an audio stream that comes from network, but with no file involved, just a raw AAC stream read directly from the socket. 现在我需要播放来自网络的音频流,但不涉及文件,只需从套接字直接读取原始AAC流。 This streams comes from the output of a ffmpeg instance. 此流来自ffmpeg实例的输出。 The problem is that I don't know how to start with this, it seems there is little information about this topic. 问题是我不知道如何从这开始,似乎关于这个主题的信息很少。 I have already tried with AVAudioPlayer but found just silence. 我已经尝试过AVAudioPlayer但发现只是沉默。 I think I have first need to decompress the packets from the stream, just like with the h264 decoder. 我想我首先需要解压缩流中的数据包,就像使用h264解码器一样。

I have been trying also with AVAudioEngine and AVAudioPlayerNode but no sucess, same as with AVAudioPlayer . 我一直在尝试使用AVAudioEngineAVAudioPlayerNode但没有成功,与AVAudioPlayer相同。 Can someone provide me some guidance? 有人可以给我一些指导吗? Maybe AudioToolbox ? 也许AudioToolbox AudioQueue ? AudioQueue

Thank you very much for the help :) 非常感谢你的帮助 :)

Edit: I'm playing around with AVAudioCompressedBuffer and having no error using AVAudioEngine and AVAudioNode . 编辑:我正在玩AVAudioCompressedBuffer ,使用AVAudioEngineAVAudioNode没有错误。 But, I don't know what this output means: 但是,我不知道这个输出意味着什么:

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

Does this mean that the buffer is empty? 这是否意味着缓冲区为空? I have been trying to feed this buffer in several ways, but always returns something like 0/1024. 我一直试图以几种方式提供这个缓冲区,但总是返回类似0/1024的东西。 I think I'm not doing this right: 我想我做得不对:

compressedBuffer.mutableAudioBufferList.pointee = audioBufferList

Any idea? 任何的想法?

Thank you! 谢谢!

Edit 2: I'm editing for reflecting my code for decompressing the buffer. 编辑2:我正在编辑以反映我的代码以解压缩缓冲区。 Maybe some one can point me in the right direction. 也许有人可以指出我正确的方向。 Note: The packet that is ingested by this function actually is passed without the ADTS header (9 bytes) but I have also tried passing it with the header. 注意:由此函数摄取的数据包实际上是在没有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
}

So you are right in thinking you will (most likely) need to decompress the packets received from the stream. 因此,您认为您(很可能)需要解压缩从流中接收的数据包。 The idea is to get them to raw PCM format so that this can be sent directly to the audio output. 我们的想法是将它们转换为原始PCM格式,以便将其直接发送到音频输出。 This way you could also apply any DSP / audio manipulation you could want to the audio stream. 这样,您还可以将任何您想要的DSP /音频操作应用于音频流。


As you mentioned, you will probably need to be looking into the AudioQueue direction and the Apple Docs provide a good example of streaming audio in realtime , although this is in obj-c (in this case I think it may be a good idea to carry this out in obj-c). 正如您所提到的,您可能需要查看AudioQueue方向,Apple Docs提供实时流式传输音频的良好示例,尽管这是obj-c(在这种情况下我认为携带它可能是个好主意)这个在obj-c)。 This is probably the best place to get started (interfacing the obj-c to swift is super simple ). 这可能是开始的最佳场所(将obj-c连接到swift非常简单 )。


Looking again at it in Swift there is the class AVAudioCompressedBuffer which seems to handle AAC for your case (would not need to decode the AAC if you get this to work), however there is no direct method for setting the buffer as it is intended for just being a storage container, I believe. 再看看它在Swift中有AVAudioCompressedBuffer类似乎可以为你的情况处理AAC(如果你让它工作就不需要解码AAC),但是没有直接的方法来设置缓冲区,因为它是用于我相信,只是一个存储容器。 Here's a working example of someone using the AVAudioCompressedBuffer along with an AVAudioFile (maybe you could buffer everything into files in background threads? I think it would be too much IO overhead). 这是一个使用AVAudioCompressedBuffer和AVAudioFile的人一个工作示例(也许你可以将所有内容缓冲到后台线程中的文件中?我认为这将是过多的IO开销)。

However, if you tackle this in obj-c there is a post on how to set the AVAudioPCMBuffer (maybe works with AVAudioCompressedBuffer?) directly through memset (kind of digusting but at the same time lovely as an embedded programmer myself). 但是,如果解决这个OBJ中-C有一个岗位上如何设置AVAudioPCMBuffer(可能与AVAudioCompressedBuffer工作?)直接通过memset (那种digusting但在同一时间,可爱的如同一个嵌入式程序员自己)。

// 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);  
}  

I know this is a lot to take and no way seems like a simple solution, but I think the obj-c AudioQueue technique would be my first stop! 我知道这是一个很好的选择,似乎不是一个简单的解决方案,但我认为obj-c AudioQueue技术将是我的第一站!

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM