构建 Audio Unit 的流程
- 构建 Audio Unit 的流程
- 指定 Audio Unit 的类型
- 创建 Audio Unit
- 设置 Audio Unit 的属性
构建 Audio Unit 的流程
iOS 有一个用于直接处理 audio units 的 API,另一个用于处理 audio processing graphs,可以同时使用这两种 API。然而这两种 API 中有一部分功能是相同的:
- 获取 audio units 的动态可链接库的引用。
- 实例化 audio units。
- 连接 audio units 并注册回调函数。
- 启动和停止音频流。
指定 Audio Unit 的类型
// Creating an audio component description to identify an audio unit
AudioComponentDescription ioUnitDescription;
ioUnitDescription.componentType = kAudioUnitType_Output;
ioUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
ioUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
ioUnitDescription.componentFlags = 0;
ioUnitDescription.componentFlagsMask = 0;
创建 Audio Unit
使用 audio unit API — AudioComponent 创建:
// Obtaining an audio unit instance using the audio unit API
AudioComponent foundIoUnitReference = AudioComponentFindNext (
NULL,
&ioUnitDescription
);
AudioUnit ioUnitInstance;
AudioComponentInstanceNew (
foundIoUnitReference,
&ioUnitInstance
);
AudioComponentFindNext
:第一个参数设置为 NULL 表示使用系统定义的顺序查找第一个匹配的 audio unit;如果你将上一个使用的 audio unit 引用传给该参数,则该函数将继续寻找下一个与之描述匹配的audio unit。
AudioComponentInstanceNew
的第二个参数类型是 AudioComponentInstance。AudioUnit 实际上就是 AudioComponentInstance,在 AudioComponent 类中有定义:
typedef AudioComponentInstance AudioUnit;
还可以使用 audio processing graph API 初始化 audio unit,即通过 AUNode 创建 Audio Unit,分为 3 步:
- 创建一个 AUGraph。
- 获取一个 AUNode。
- 获取一个 Audio Unit。
// Declare and instantiate an audio processing graph
AUGraph processingGraph;
NewAUGraph (&processingGraph);
// Add an audio unit node to the graph, then instantiate the audio unit
AUNode ioNode;
AUGraphAddNode (
processingGraph,
&ioUnitDescription,
&ioNode
);
AUGraphOpen (processingGraph); // indirectly performs audio unit instantiation
// Obtain a reference to the newly-instantiated I/O unit
AudioUnit ioUnit;
AUGraphNodeInfo (
processingGraph,
ioNode,
NULL,
&ioUnit
);
设置 Audio Unit 的属性
Audio Unit 实际上就是一个 AudioComponentInstance 实例对象,一个 AudioUnit 由 scope 和 element 组成。
scope 是 Audio Unit 内部的编程上下文,其定义为枚举值:
CF_ENUM(AudioUnitScope) {
kAudioUnitScope_Global = 0,
kAudioUnitScope_Input = 1,
kAudioUnitScope_Output = 2,
kAudioUnitScope_Group = 3,
kAudioUnitScope_Part = 4,
kAudioUnitScope_Note = 5,
kAudioUnitScope_Layer = 6,
kAudioUnitScope_LayerItem = 7
};
主要使用到的输入 kAudioUnitScope_Input 和输出 kAudioUnitScope_Output。参考 Figure1-2,Input scope 表示里面的所有的 element 都需要一个输入;Output scope 表示里面的所有的 element 都会输出到某个地方;Global scope 作为整体应用于 Audio Unit 并且不与任何特定音频流相关联,它只有一个 element,用来配置一些和输入输出无关的属性。
术语 element 和 bus 在 Audio Unit 中是一个含义。当 Element 是 Input/Output scope 的一部分时,它类似于物理音频设备中的信号总线。在强调信号流时使用 bus,在强调音频单元的特定功能时使用 element。
使用 scope 和 element 来设置 Audio Unit 的属性,函数原型为:
AudioUnitSetProperty( AudioUnit inUnit,
AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
const void * __nullable inData,
UInt32 inDataSize
);
各参数意义:
-
AudioUnitPropertyID:设置属性名称。有以下枚举值:
- kAudioOutputUnitProperty_EnableIO:用于在 I/O unit 上启用或禁用输入或输出。默认情况下,输出已启用但输入已禁用。
- kAudioUnitProperty_ElementCount:elements 的数量。
- kAudioUnitProperty_MaximumFramesPerSlice:为了指定音频数据的最大帧数,音频单元应准备在响应渲染调用时生成。对于大多数音频单元,在大多数情况下,必须按照参考文档中所述设置此属性。如果不这样做,当屏幕锁定时,音频将停止。
- kAudioUnitProperty_StreamFormat:指定特定 audio unit 输入或输出总线的音频流数据格式。
-
AudioUnitScope:AudioUnit 的 Scope,主要用于输入输出范围。
-
AudioUnitElement:AudioUnit 的 Element,默认用 1 表示输入总线,用 1 表示输出总线。
-
inData:输入值。
-
inDataSize:输入值的长度。
大多数属性只能在 audio unit 没有初始化时指定,但是某些特定属性可以在 audio unit 运行时设置,如 kAUVoiceIOProperty_MuteOutput
静音功能。
要测试属性的可用性,访问其值以及监视其值的更改,可以使用以下函数:
- AudioUnitGetPropertyInfo:发现属性是否可用;如果是,可以获得其值的数据大小,以及是否可以更改该值。
- AudioUnitGetProperty、AudioUnitSetProperty:获取、设置一个属性值,可以在 Audio Unit 运行时使用。
- AudioUnitAddPropertyListener、AudioUnitRemovePropertyListenerWithUserData:添加或删除用于监控属性值更改的回调函数。
函数实例:
UInt32 busCount = 2;
OSStatus result = AudioUnitSetProperty (
mixerUnit,
kAudioUnitProperty_ElementCount, // the property key
kAudioUnitScope_Input, // the scope to set the property on
0, // the element to set the property on
&busCount, // the property value
sizeof (busCount)
);