美文网首页程序员音视频开发
关于AudioQueue的一些知识

关于AudioQueue的一些知识

作者: zhonglaoban | 来源:发表于2018-06-08 17:30 被阅读40次

    什么是Audio Queue Services?

    官方文档是这么介绍的:

    Audio Queue Services provides a straightforward, low overhead way to record and play audio in iOS and Mac OS X. It is the recommended technology to use for adding basic recording or playback features to your iOS or Mac OS X application.

    意思是:

    Audio Queue Services 提供直接的、低开销的方法给你用来在iOS和Mac平台上录制和播放音频。对于基础的音频录制和播放,这是推荐的技术。

    它支持这几种格式的音频数据

    • Linear PCM. //是PCM的一种,具备比普通音频中的PCM数码流更高的位深和采样率,音质好很多
    • Any compressed format supported natively on the Apple platform you are developing for. //其它任何苹果支持的数据格式
    • Any other format for which a user has an installed codec.//其它编解码器的数据

    什么是Audio Queue?

    audio queue是一个用来在iOS或Mac OS X平台播放或录制音频的软件对象,它是一种在AudioQueue.h被定义好的AudioQueueRef数据类型。一个audio queue能做以下的事情:

    • 和声音的硬件结合
    • 内存管理
    • 根据需要,使用编解码器来压缩音频格式
    • 充当录音或回放的中介

    Audio Queue的结构

    所有的audio queue都有相同的结构,包括以下几部分:

    • 几个audio queue buffer,每个buffer都是一些音频数据的缓冲区
    • 一个buffer queue,一个由audio queue buffer组成的有序的队列
    • 一个audio queue callback,告诉你回调中的buffer已经使用完毕,你可以填充数据(播放时);或者告诉数据已经填充满了,可以拿去用(录制时)

    这些部分根据是播放还是录制音频各有不同之处,不同的地方就是在于audio queue是连接到输入源还是输出源,并且callback的作用也各有不同

    用于录制的Audio Queue

    一个用于录制的audio queue,可以通过AudioQueueNewInput方法创建,它的结构如图1-1所示。[图片上传失败...(image-9514a2-1528450188109)]

    audio queue的输入源是和硬件绑定的,如自带的麦克风或者耳机的麦克风。
    audio queue的输出端是一个callback,告诉buffer中数据已经填充满了,可以拿去用,你可以写入磁盘存储起来,或者用来播放。

    用于播放的Audio Queue

    一个用于播放的audio queue,可以通过AudioQueueNewOutput方法创建,它的结构如图1-2所示。[图片上传失败...(image-55a53c-1528450188109)]

    一个用于播放的audio queue,他的输入源是callback。它告诉你可以将需要输入的数据或者从文件中读取的数据放入audio queue中,当callback中没有数据,它其实也是在告诉audio queue可以停止播放了。此时audio queue的输出端是和硬件绑定的,如扩音器、耳机等。

    基础知识介绍

    创建Audio Queue
    OSStatus AudioQueueNewOutput (const AudioStreamBasicDescription * inFormat,
                                  AudioQueueOutputCallback inCallbackProc,
                                  void * inUserData,
                                  CFRunLoopRef inCallbackRunLoop,
                                  CFStringRef inCallbackRunLoopMode,
                                  UInt32 inFlags,
                                  AudioQueueRef * outAQ);
                                  
    OSStatus AudioQueueNewOutputWithDispatchQueue(AudioQueueRef * outAQ,
                                                  const AudioStreamBasicDescription * inFormat,
                                                  UInt32 inFlags,
                                                  dispatch_queue_t inCallbackDispatchQueue,
                                                  AudioQueueOutputCallbackBlock inCallbackBlock);
    

    先来看第一个方法:

    第一个参数表示需要播放的音频数据格式类型,是一个AudioStreamBasicDescription对象,是使用AudioFileStream或者AudioFile解析出来的数据格式信息;
    第二个参数AudioQueueOutputCallback是某块Buffer被使用之后的回调;
    第三个参数为上下文对象;
    第四个参数inCallbackRunLoop为AudioQueueOutputCallback需要在的哪个RunLoop上被回调,如果传入NULL的话就会再AudioQueue的内部RunLoop中被回调,所以一般传NULL就可以了;
    第五个参数inCallbackRunLoopMode为RunLoop模式,如果传入NULL就相当于kCFRunLoopCommonModes,也传NULL就可以了;
    第六个参数inFlags是保留字段,目前没作用,传0;
    第七个参数,返回生成的AudioQueue实例;
    返回值用来判断是否成功创建(OSStatus == noErr)。

    第二个方法就是把RunLoop替换成了一个dispatch queue,其余参数同相同。

    Audio Queue Buffers

    一个audio queue buffer是一个AudioQueueBuffer类型的结构体,AudioQueue.h你可以找到它:

    typedef struct AudioQueueBuffer {
       const UInt32   mAudioDataBytesCapacity;
       void *const    mAudioData;
       UInt32         mAudioDataByteSize;
       void           *mUserData;
    } AudioQueueBuffer;
    typedef AudioQueueBuffer *AudioQueueBufferRef;
    
    Audio Queue的方法
    • Start (AudioQueueStart)初始化录制或者播放Audio
    • Prime (AudioQueuePrime)用来播放,在start之前调用,取保在播放之前有数据。这个方法只在播放时有用。
    • Stop (AudioQueueStop)重置AudioQueue,然后停止播放或者录制。当播放时的audio queue callback没有数据了可以调用这个方法。
    • Pause (AudioQueuePause)暂停播放或者录制,不影响buffer也不会重置AudioQueue,用AudioQueueStart可以重新唤醒。
    • Flush (AudioQueueFlush)清空缓冲区的数据,确保所有数据都被播放或录制。
    • Reset (AudioQueueReset)停止AudioQueue,并清空所有的buffer,重置所有解码器和数字信号的状态。

    你可以同步的或者异步的使用AudioQueueStop方法:

    • Synchronous 立即停止,忽略缓存区的数据
    • Asynchronous 当缓存区数据用完时停止
    mAudioData

    一个指向结构体本身的指针,它有一块内存空间,用来做播放或者录制是的数据交换。
    一个audio queue可以拥有任意多个buffer,由你决定。通常来说3个就够了,一个用来填出数据,一个用来读取数据,一个等待着,用来处理一些硬件延迟等事情。

    audio queue对buffer的内存进行管理
    -当我们调用 AudioQueueAllocateBuffer方法时 audio queue为buffer分配内存

    • 等你用AudioQueueDispose方法释放audio queue时,buffer的内存也会被释放。
    创建一个buffer
    OSStatus AudioQueueAllocateBuffer(AudioQueueRef inAQ,
                                      UInt32 inBufferByteSize,
                                      AudioQueueBufferRef * outBuffer);
                                      
    OSStatus AudioQueueAllocateBufferWithPacketDescriptions(AudioQueueRef inAQ,
                                                            UInt32 inBufferByteSize,
                                                            UInt32 inNumberPacketDescriptions,
                                                            AudioQueueBufferRef * outBuffer);
    

    第一个方法传入AudioQueue实例和Buffer大小,传出的Buffer实例;

    第二个方法可以指定生成的Buffer中PacketDescriptions的个数;

    AudioStreamBasicDescription
    struct AudioStreamBasicDescription
    {
        Float64             mSampleRate;  //采样率
        AudioFormatID       mFormatID;  //音频格式
        AudioFormatFlags    mFormatFlags;//音频格式详细
        UInt32              mBytesPerPacket;//一个数据包的字节数
        UInt32              mFramesPerPacket;//一个数据包的帧数
        UInt32              mBytesPerFrame;//一帧的字节数
        UInt32              mChannelsPerFrame;//声道
        UInt32              mBitsPerChannel;//一个声道的字节数
        UInt32              mReserved;//默认为0
    };
    
    AudioQueueEnqueueBuffer
    AudioQueueEnqueueBuffer(            AudioQueueRef                       inAQ,
                                        AudioQueueBufferRef                 inBuffer,
                                        UInt32                              inNumPacketDescs,
                                        const AudioStreamPacketDescription * __nullable inPacketDescs)      __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);
    

    将buffer放入audio queue中

    memcpy

    内存拷贝,将一段内存地址的数据按长度length拷贝到另外一段内存地址中。
    void *memcpy(void *dst, const void *src, size_t n)

    参考文档

    相关文章

      网友评论

        本文标题:关于AudioQueue的一些知识

        本文链接:https://www.haomeiwen.com/subject/ymhgsftx.html