如图所示,全部 iOS 音频技术都是基于 audio units。此处显示的更高级别的技术,如 Media Player,AV Foundation,OpenAL,AudioToolbox,是对 audio units 的封装,为特定的任务提供专用且简化的 API。ios
如在可控性、性能、灵活性有很是高的需求,或者须要实现特定的功能(例如回音消除),直接使用 audio unit 是一个正确的选择。编程
当你须要实现如下需求时,不使用高级 API,直接使用 audio unitsapi
根据不一样功能分类,iOS 提供了七种 audio units缓存
注意:iOS 动态插件结构不支持第三方 audio units,也就是说,动态加载的 audio units 仅能经过操做系统提供。安全
iOS 4 提供了一个效果单元,iPod Equalizer,与 iPod 内置应用使用相同的均衡器。查看这个 audio unit 的 iPod 应用用户界面,进入设置 -> iPod -> EQ。当使用此 audio unit,必须提供本身的用户界面。此 audio unit 提供了一组预设的均衡曲线,例如低音加强,Pop 和 Spoken Word。网络
iOS 提供两个 mixer units。3D Mixer unit 是 OpenAL 的基础,若是须要实现 3D Mixer unit 的特征,能够优先使用 OpenAL,它提供了高级 API,而且很是适合游戏应用程序。关于如何使用 OpenAL,见示例代码: oalTouch。数据结构
Multichannel Mixer unit 为任意数量的单声道或立体声提供混音,立体声输出。能够打开和关闭每个输入,设置输入增益,并设置立体声平移位置。见示例代码:MixerHost。app
iOS 提供了三个 I/O units,其中 Remote I/O unit 是最经常使用的。链接输入输出音频硬件,对传入和传出的样本值低延迟访问,提供硬件音频格式和应用音频格式之间的格式转化。见示例代码:aurioTouch。异步
Voice-Processing I/O unit 是对 Remote I/O unit 的拓展,添加了语音聊天中的回声消除,还提供了自动增益矫正,语音质量调整,静音等特性。模块化
Generic Output unit 不链接音频硬件,而是提供了一种将处理链的输出发送到应用程序的机制。一般会使用作离线音频处理
iOS 4 提供了 Format Converter Unit,一般经过 I/O unit 间接使用。
iOS 中两个和 audio units 相关的 API,一个 API 直接处理 audio units ,另外一个处理 audio processing graphs,在应用中能够同时使用两个 API。
这两个 API 之间有一些功能重叠,能够根据本身编程风格自由组合和搭配,提供的功能以下:
首先须要在音频组件描述数据结构中肯定其类型、子类型和制造商密匙。下面指定了一个特定的 audio Unit,Remote I/O unit,对 componentManufacturer 字段,全部的 iOS audio units 使用 kAudioUnitManufacturer_Apple。如需建立一个通用描述,能够将类型或者子类型设置为0,例如为了匹配全部的 I/O unit,能够将 componentSubType 设置为0。
AudioComponentDescription ioUnitDescription; ioUnitDescription.componentType = kAudioUnitType_Output; ioUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO; ioUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; ioUnitDescription.componentFlags = 0; ioUnitDescription.componentFlagsMask = 0;
使用 audio unit API 获取 audio unit 实例,对于 AudioComponentFindNext ,若是第一个参数传空,按照系统定义的排序,找到第一个符合的 audio unit ,若是该参数为先前找到的音频单元,则该功能找到与描述匹配的下一个 audio unit,例如此用法能够经过重复调用 AudioComponentFindNext 来获取全部 I/O 单元的引用。
AudioComponent foundIoUnitReference = AudioComponentFindNext(NULL, &ioUnitDescription); AudioUnit ioUnitInstance; AudioComponentInstanceNew(foundIoUnitReference, &ioUnitInstance);
使用 audio processing graph API 获取 audio unit
AUGraph processingGraph; NewAUGraph(&processingGraph); AUNode ioNode; AUGraphAddNode(processingGraph, &ioUnitDescription, &ioNode); AUGraphOpen(processingGraph); AudioUnit ioUnit; AUGraphNodeInfo(processingGraph, ioNode, NULL, &ioUnit);
如图所示,Audio Unit 中有一个 input element,一个 output element,这种结构比较常见,但这并不适合全部情况。例如在 mixer unit 中,会存在多个 input element,一个 output element的状况。
element 1 能够理解为 input element(bus),element 0 理解为output element。Input scope 和 Output scope,直接参与音频流的流程,音频从 Input scope 输入,从 Output scope 输出,一些参数或属性适用于 Input scope 或 Output scope。Global scope,应用于整个 audio unit,不与音频流关联,它有一个 element,命名为 element 0,一些属性,像 kAudioUnitProperty_MaximumFramesPerSlice 应用于 Global scope。
设置属性,可使用函数 AudioUnitSetProperty
UInt32 busCount = 2; OSStatus result = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount));
下面是一些经常使用的属性:
大部分属性能够在 audio unit 未初始化的时候设置,由于这些属性通常不会发生改变,有些属性像 iPod EQ unit 中的 kAudioUnitProperty_PresentPreset和 Voice-Processing I/O unit 中的 kAUVoiceIOProperty_MuteOutput 这些属性会在播放音频的时候也会发生改变
查找属性是否可得,访问属性值,监听改变,可使用一下函数:
audio unit 参数是用户能够在音频生成的过程当中更改,事实上,大部分参数能够在 audio unit 正在执行时实时调整的,例如音量。
每个 Element都有本身的 input scope 和 output scope,当描述 I/O unit 的时候可能会有困惑,至关于这样描述,你收到收据来自 input element 的 output scope,发送数据到 output element 的 input scope。
I/O unit 是惟一可以在 audio processing graph 中启动和中止音频流的 audio unit。I/O unit 负责在音频单元APP中的音频流。
AUGraph 用于构建和管理 audio units 处理链,能够利用多个 audio units 和多个回调函数功能,建立几乎任何你能够想象的音频处理解决方案。
AUGraph 增长了线程安全,让你能够即时从新配置处理链,例如你能够安全插入一个均衡器,甚至在音频播放时能够交换混音器输入的其它回调函数。实际上,AUGraph 提供了 iOS 中惟一能够在音频应用程序中执行这种动态从新配置的 API 。
Audio Processing Graph 使用了 AUNode 表示上 graph 中 一个单独的 audio unit ,当使用 Audio Processing Graphs,一般与包含 audio units 的代理 AUNode 交互,而不是直接使用 audio unit。
当将 graph 组合时,须要配置每个 audio unit ,而且必须经过 audio unit API 直接与 audio unit 交互,节点单元自己是不能够配置的,经过这种方式,须要使用这两种 API。
一般状况下,Audio Processing Graphs 一般须要三个任务,将节点添加到 Graph 中,直接配置由节点表示的 audio unit,互连节点。
每个 audio processing graph 有一个 I/O unit,不管你是录音,播放,同步 I/O。Graphs 经过 AUGraphStart 和 AUGraphStop 启动和中止音频流,经过函数 AudioOutputUnitStart 和 AudioOutputUnitStop 传递开始和中止消息到 I/O unit。
audio processing graph 使用“待办事项列表”提供线程安全,API 的一些函数添加工做单元到稍后执行的更改列表中,在你指定完整的更改好,让 graph 实现他们。
这是一些 audio processing graph 支持的重配置函数
下面看一个重配置 audio processing graph 的例子,构建一个 graph 包含 Multichannel Mixer unit 和 Remote I/O unit,将声音输入到混频器的两个输入总线上。从混合器输出数据到 I/O unit 的 Output element 上。
如今用户想插入均衡器到其中一个音频流上,如何完成动态配置
调用 AudioUnitGetProperty 函数获得 mixer input 的流格式(kAudioUnitProperty_StreamForamt)
调用 AudioUnitSetProperty 函数两次,一次设置 iPod EQ unit 的输入格式,一次设置它的输出格式
调用 AudioUnitInitialize 函数,给 iPod EQ 分配资源和准备处理音频,这个函数调用时线程安全的
调用 AUGraphSetNodeInputCallback 函数,设置鼓的回调函数到 iPod EQ unit 的输入
为了给 audio unit 的输入总线提供数据,使用听从 AURenderCallback 原型的回调函数,音频输入单元须要一帧数据的时候触发回调。在处理 audio unit 应用中,写回调函数多是最具备创意的工做,你能根据你的意愿产生和改变声音。
回调函数有严格的性能要求,回调存在于实时线程上,随后回调异步到达,回调函数内部全部的工做发生在时间有限的环境中,当下一帧数据到达,你仍在处理以前的回调产生的帧,声音则会产生间隙,出于这个缘由,不得在回调函数主体中执行耗时操做,例如锁定,分配内存,访问文件系统,网络链接等。
回调函数头部
static OSStatus MyAURenderCallBack(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData);
inRefCon,参数指向回调附加到 audio unit 输入时指定的编程上下文
ioData,指向音频数据缓存区