本篇是AudioQueue的官方文档的笔记。Audio Queue Services可以play和record以下三类任何audio data:
Linear 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.对于最后一种类型,我们可以在使用AudioQueue同时自己将自己需要的format转化成LPCM。AudioQueue是对mic和speaker的高度抽象,同时可以非常简单的时间音频codecs。与此同时,它也有一些高级功能,例如多个音频的同步播放,回放等等。
这章会了解到audio queue的功能,结构体,以及内部运行的机理。具体的内容包括audio queues,audio queue buffers,audio queue会使用到的callback等。还有就是audio queue的状态以及参数。
An audio queue 是iOS中play和record audio的对象.底层是AudioQueueRef
。Audio queue可以完成以下工作:
Audio queue的具体结构有以下几个部分构成:
A set of audio queue buffers, each of which is a temporary repository for some audio dataA buffer queue, an ordered list for the audio queue buffersAn audio queue callback function, that you write根据我们使用audio queue的用途(record or play),具体的结构略有不同,仅仅只是callback函数函数的内容不同。
一个用于record 的audio queue,需要使用AudioQueueNewInput
方法创建,它的具体结构如图:
一个用于play的audio queue,需要使用AudioQueueNewOutput
函数创建,
audio queue buffer的数据结构如下:
1234567 | typedef struct AudioQueueBuffer { const UInt32 mAudioDataBytesCapacity; void *const mAudioData; UInt32 mAudioDataByteSize; void *mUserData;} AudioQueueBuffer;typedef AudioQueueBuffer *AudioQueueBufferRef; |
其中mAudioData字段表示这个buffer中的有用数据的地址,其他的字段用来辅助audio queue来管理使用这个buffer。一个audio queue可以使用任何数目的buffers。但是我们一般选择3个,比较好管理。
Audio queue通过下面的方式管理它们内部的buffers:
An audio queue allocates a buffer when you call the AudioQueueAllocateBuffer function.When you release an audio queue by calling the AudioQueueDispose function, the queue releases its buffers.buffer queue是由audio buffers组成的,是audio queue中的buffers。我们前面介绍了audio queue是如何使用callback管理内部的buffers。不论当前是用于record或者是pleyback,将buffer放到audio queue都是需要我们在callback函数中去手动调用的。
Audio queue buffers在queue是顺序播放的,我们可以通theAudioQueueEnqueueBufferWithParameters
方法来进行控制
Audio queue在运行过程中会不断的调用callback函数,通常间隔时间和audio queue buffer的大小相关,一般是几秒一次。
audio queue callback主要任务是将audio queue buffer归还给audio queue。callback中通过AudioQueueEnqueueBuffer
方法将buffer加载到audio queue的最后。在playback中,可以使用AudioQueueEnqueueBufferWithParameters
在enqueue的过程中进行更多的控制。
如果你仅仅使用audio queue去将record的audio data写入file system,callback的方法实现的原型如下:
12345678 | AudioQueueInputCallback ( void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions, const AudioStreamPacketDescription *inPacketDescs); |
一个recording audio queue会触发我们注册的callback,会在callback的参数中传入所有需要的关于audio data的相关信息:
inUserData 是一个自定义的结构体,用来存储audio queueu以及audio queue buffer的状态信息,也包括AudioFileID,audio data format等。inAQ 表示哪个audio queue触发这个callback。inBuffer 是一个audio queue buffer,它的内容是由audio queue填充的,内部包括最新的audio data。并且这些audio data已经根据初始化时候传递的格式参数格式化好的数据。inStartTime 表示这个buffer中的第一个采样的采样时间点,一般app中不太需要这个参数。inNumberPacketDescriptions 表示inPacketDescs参数中的packet descriptions的个数。如果你是录入VBR format,audio queue就会在callback中提供这个参数,如果是CBR,audio queue就不会使用packet descriptions参数,这个参数会是NULL。inPacketDescs 表示buffer中samples相关的一系列的packet descriptions。是否设置同上一个参数。这个片段会介绍如果使用playing audio queue,那么callback应该的信息:
12345 | AudioQueueOutputCallback ( void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer); |
一个playback audio queue会触发这个callback,提供一些关于audio data的有用信息:
inUserData 见上inAQ 表示哪个audio queue触发这个callback。inBuffer 表示被audio queue设置为空的audio queue buffer,你需要在callback中将其内部信息填满,填充内容是你从AudioFile中读取的audio data。我们日常使用Audio Queue Services时,都会使用codecs(audio data coding/decoding componets)用来在不同audio format之间进行转化。
每个audio queue都有一个audio data format,可以在AudioStreamBasicDescription
结构体中得到。当我们在ASBD中指定了mFormatID
以后,audio queue在向buffer中填充数据时候就会使用相应的codec。同样如果指定sample rate和channel count,audio queue也会同样。具体的过程见下图:
整个过程中,callback函数压根就不需要知道data fromat是什么。
在播放过程中,正好和录音过程相反,只需要在创建audio queue时候将data format告知即可。
audio queue在创建和销毁的过程有一个声明周期。app需要管理它的声明周期,控制它的状态,具体控制状态的方法如下:
Start (AudioQueueStart
).初始化audio queue用来record或者playback。Prime (AudioQueuePrime
).对于playback,在调用AudioQueueStart
挚爱去哪调用确保数据可用,这个方法和record没有关系。Stop (AudioQueueStop
). 调用以后会重置audio queue,然后会停止record或者playback。在playback应用中,一般在没有audio data可以播放时候调用。Pause (AudioQueuePause
). 在record或者playback中调用这个方法不会影响到buffers。如果需要恢复,调用AudioQueueStart
。Flush (AudioQueueFlush
). 在enqueue最后一个audio queue buffer以后调用这个方法,确保所有的数据被record或者play(主要是在midst processing的数据)。Reset (AudioQueueReset
). 调用以后立即停止audio queue,然后将所有的buffers移除,重置所有的DSP状态等到。在调用AudioQueueStop
方法时候有两种模式:同步和异步。
当我们的record使用Audio Queue Services,存储的路径可以是磁盘上的任何地方,或者网络,或者内存中。这部分内容记录大多数的使用场景,存储在磁盘中。
具体的步骤如下:
定义一个结构体去存储状态,format,文件路径等信息。完成audio queue callback函数,其中将record以后的数据进行存储。为audio queue buffers计算出合适的大小,并且在file中写入magic cookies。初始化自定义的结构体创建recording audio queue,然后给它创建3个audio queue buffers,然后创建一个file用来存储record以后的audio data。启动audio queue当audio queue停止以后,dispose它以及buffers具体的实现内容可以参考Apple官方文档:Recording Audio。
当我们使用Audio Queue Service去play audio时,音频源文件可以是任何在disk file或者memory中,这部分内容是如何用Audio Queue Service播放存储在disk上的audio file。
具体的步骤如下:
定义一个结构体管理Audio queue的状态,format,file path等完成audio queue callback函数去进行实际的播放创建一个函数用来计算最适合的audio queue buffer的大小打开audio file,确定它的audio data format创建audio queue,对它进行配置为audio queue创建buffers,然后启动audio queue,当播放结束,callback让audio queue停止播放销毁audio queue具体的实现内容可以参考Apple官方文档:Playing Audio。
请参考我的github: https://github.com/brownfeng/AudioQueueServiceDemo
新闻热点
疑难解答