构建音频单元应用程序
首先选择设计模式
- I/O 直接相连模式
- 没有渲染回调函数的i/o
- 带有渲染回调函数的 I/O
- 仅有渲染回调函数的输出
- 其他音频单元托管设计模式
构建app
- 配置音频会话
- 指定想要的音频单位
- 构建音频处理graph
- 配置音频单元
- 写入并附加渲染回调函数
- 连接音频单元节点
- 提供用户界面
- 初始化并启动音频处理graph
故障排除提示
使用特定的音频单元
使用I/O 音频单元
- 远程I/O单元
- 语音处理I/O单元
- 通用输出单元
使用混音器单元
- 多声道混音器单元
- 3D 混音器单元
使用效果单元
构建音频单元应用程序
现在我们已经了解音频单元托管的工作方式,也已经准备好构建app应用程序的音频单元部分。主要步骤是选择设计模式,然后编写代码来实现该模式。
首先选择设计模式
在ios应用中托管音频单元有六种基本设计模式。首先选择最能代表希望应用对音频做什么的那个。在学习每种模式的时候,注意下常用功能。每种模式
- 只有一个I/O单元
- 在整个音频处理的grahp中使用音频单元流格式-尽管该模式可能存在改变,例如为混音器单元提供单声道和立体声。
- 要求在特定位置设置流格式和流格式的某些部分
正确设置流格式对于建立音频数据流至关重要。这些模式中的大多数依赖于音频流格式从源到目的地的自动传播,如音频单元连接锁提供的。尽可能的利用这种传播,因为它减少了编写和维护的代码量。同时,请确保您了解设置流格式所需要的流格式。例如,我们必须在ipod EQ 设备的输入和输出上设置完整的流格式。有关所有ios音频单元流格式的要求可以看 Using Specific Audio Units
在大多数情况下,本章中的设计模式采用音频处理grahp(AUGraph类型)。我们可以在不使用grahp的情况下实现这些模式中的任意一种,但是用简化代码并不支持动态分配重新配置。
I/O 直接相连模式
I/O直通模式将传入的音频直接发送到输出硬件,没有选项可以处理音频数据。虽然这没有多大的实用价值,但是基于此模式构建托管的app的音频单元是验证和巩固我们对音频单元概念的理解的好方法。
如图所示,音频输入硬件将流格式强制放在远程 I/O 单元输入原件的朝外侧。反过来,我们指定此元素的向内侧使用的格式。音频单元关键需要执行格式转换。为避免不必要的采样率转换,请使用流格式使用的音频硬件采样率。
默认情况下是禁止 输入的 element ,因此我们需要手动开启它。否则,音频无法流动。
在图中所示的模式利用了两个远程I/O 元件之间的音频单元连接。具体来说,我们不需要在音频元件的输入scope 上的output element 设置流格式。连接传播我们为input element 指定的格式。
输出元件的朝外侧采用音频输出硬件的流格式,输出元件需要根据对输出音频格式执行格式转换。
该模式,我们无需配置任何音频数据缓冲区。
没有渲染回调函数的i/o
在远程I/O 单元的element之间添加一个或者多个其他音频单元,可以构建更有趣的app。例如,我们可以使用多声道混音器单元将传入的麦克风音频定位在立体声场中或提供输出音量控制。在这种设计模式中,仍然没有回调功能,如下图,这简化了模式,但是先知了它的实用性。
在此模式中,我们可以像I/O直接相连模式中一样配置远程的I/O 单元的两个元素。要设置多声道混音器单元,必须在混音器输出上设置流格式的采样率,如上图
混音器的输入流格式通过传输从远程I/O单元的输入 element 的输出通过音频单元连接自动建立。类似的,远程I/O 单元的输出的element 的input scope的流格式是也是通过音频单元连接,该数据来自混音器单元的output的传播。
在这种模式的任何实例中-实际上,除了I/O单元之外,每当使用其他音频单元时-必须按照 Audio Unit Properties Reference
中的描述设置kAudioUnitProperty_MaximumFramesPerSlice
与I/O 直接相连模式一样,我们不需要配置任何音频数据缓冲区。
带有渲染回调函数的 I/O
通过在远程I/O 单元的输入和输出元件之间防止渲染回调函数,我们可以在传入音频到达硬件之前对其进行操作。在一个非常简单的情况下,我们可以使用渲染回调函数来调整输出音量,也可以添加颤音,铃声调制,回声或者其他效果。通过使用Accelerate框架中提供的傅里叶变化和积分公式,我们可以做的事情可就是无穷无尽的。
如图所示,此模式使用远程i/o单元的两个element。将渲染回调函数附加到output element 的input scope上。当该元素需要另一组音频样本值时,他会调用我们的回调函数。反过来,我们的回调通过调用远程I/O 单元的输入 element的渲染会地哦啊函数来获取新样本
。
与其他I/O 模式一样,我们必须在远程I/O 单元上开启输入,默认情况下输入是禁止的。而且,对于其他I/O模式,我们无需要配置任何音频数据缓冲区
注意,当我们使用渲染回调涵涵说建立从一个音频单元到另一个音频单元的音频路径时,回调函数取代了音频单元连接
仅有渲染回调函数的输出
对于游戏音乐和合成器选择此模式-当我们需要为其生成声音并需要最大的响应app。最简单的是,这种模式设计到一个渲染回调函数,它直接连接到远程I/O 单元输出element 的 output的 scope
你可以使用相同的模式构建具有更复杂的音频结构的app。例如,当我们希望生成多个声音,将它们混合在一起,然后通过设备的输出硬件播放他们,看下图。这里该模式采用音频处理grahp和两个额外的音频单元,多声道混音器和Ipod EQ
上图,需要注意Ipod EQ 要求我们在在输入和输出上设置完整的流格式。另一方面,多通道混音器只需要再其输出上设置正确的采样率。然后,整个流格式由音频单元连接从混音器的输出传播到远程I/O单元输出单元的input scope。具体细节看Using Specific Audio Units.
对于每个多通道混音器收入单元,如上图,需要设置完整的流格式。对于输入0,可以显示设置它。对于输入1 ,格式通过音频单元连接从Ipod EQ 单元的输出传播。通常,我们必须分别考虑每个音频单元的流格式需求。
其他音频单元托管设计模式
音频单元托管还有两种设计模式。要录制和分析音频,请使用渲染回调函数创建仅限输入的应用。回调函数由应用程序调用,然后它调用RemoteI/O 单元的input元素的render方法。但是,在大多数情况下,像这样的应用程序的更好选择是使用音频队列对象。使用音频队列对象提高了更大的灵活性,因为他的渲染回调函数不在实时线程上。
要执行离线音频处理,需要使用通用输出单元。与远程I/O 单元不同,该音频单元不连接到设备的音频硬件。当使用它向app发送音频时,它取决于app调用其render 方法
构建app
无论选择哪种设计模式,构建音频单元托管app的步骤基本相同:
- 1.配置音频会话
- 2.指定音频单元
- 3.创建音频处理graph,然后获取音频单元
- 5.配置音频单元
- 6.连接音频单元节点
- 7.提供用户界面
- 8.初始化然后启动音频处理graph
配置音频会话
构建音频单元app的第一步与任何ios音频app 相同,配置音频会话。音频会话的特性在很大程度上决定了app的音频功能以及与系统其它部分的交互性。首先指定要在app中使用的采样率,如下
self.graphSampleRate = 44100.0; // Hertz
接下来,使用音频会话对象请求系统使用您的首选采样率作为设备硬件的采样率,如下列代码。这里的目的是避免硬件和app之间的采样率转换。这可以最大程度的提高cpu的性能和音质,并最大限度的减少电池消耗。
NSError *audioSessionError = nil;
AVAudioSession *mySession = [AVAudioSession sharedInstance]; // 1
[mySession setPreferredHardwareSampleRate: graphSampleRate // 2
error: &audioSessionError];
[mySession setCategory: AVAudioSessionCategoryPlayAndRecord // 3
error: &audioSessionError];
[mySession setActive: YES // 4
error: &audioSessionError];
self.graphSampleRate = [mySession currentHardwareSampleRate]; // 5
上述代码解释
- 1获取app 的单例音频会话对象的引用
- 2.请求硬件的采样率。
- 3.请求我们想要的音频会话category。这里是录制和播放
- 4.激活音频会话
- 5.音频会话激活后,根据系统提供的实际采样率更新自己的采样率变量。
这里可能需要配置一个硬件特性:音频硬件I/O 缓冲区持续时间。在44.1KHZ采样率下,模式持续时间约为23ms。相当于1024个样本的slice大小。如果app的I/O 延迟至关重要,那么我们需要请求较小的持续时间,最低月为0.005毫秒(相当256个样本)
self.ioBufferDuration = 0.005;
[mySession setPreferredIOBufferDuration: ioBufferDuration
error: &audioSessionError];
这里关于音频会话的向导可以参考 Audio Session Programming Guide
指定想要的音频单位
在运行时,音频会话配置代码后,app还是没有获取音频单元。我们可以使用AudioComponentDescription指定音频单元。
AudioComponentDescription ioUnitDescription;
ioUnitDescription.componentType = kAudioUnitType_Output;
ioUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
ioUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
ioUnitDescription.componentFlags = 0;
ioUnitDescription.componentFlagsMask = 0;
获取到音频单元说明符,然后根据我们选择的模式构建音频处理graph
构建音频处理graph
一般步骤如下
- 实例化AUGraph对象。该对象代表音频处理grahp
- 2.实例化一个或者多个AUNode 对象。每个类型代表grahp中的音频单元
- 3.将 AUNode 加入到 AUGraph中
- 4.打开图形并实例化音频单元
- 5.获取对音频单元的引用
如下列代码
AUGraph processingGraph;
NewAUGraph (&processingGraph);
AUNode ioNode;
AUNode mixerNode;
AUGraphAddNode (processingGraph, &ioUnitDesc, &ioNode);
AUGraphAddNode (processingGraph, &mixerDesc, &mixerNode)
AUGraphAddNode 函数调用使用音频单元说明符ioUnitDesc和mixerDesc。此时,graph 将被实例化,并拥有app中使用的结点。打开graph 并实例化音频单元使用AUGraphOpen
AUGraphOpen (processingGraph);
然后,通过AUGraphNodeInfo函数获取对音频单元实例的引用
AudioUnit ioUnit;
AudioUnit mixerUnit;
AUGraphNodeInfo (processingGraph, ioNode, NULL, &ioUnit);
AUGraphNodeInfo (processingGraph, mixerNode, NULL, &mixerUnit)
ioUinit 和mixerUnit 变量现在包含了对graph中音频单元实例的引用,允许您配置并互联音频单元。
配置音频单元
每个ios 音频单元都需要自己的配置,可以参考 Using Specific Audio Units。但是有些配置是常见的,所有ios音频开发人员都应该熟悉他们。
默认情况下,远程I/O 单元已启用输出但是禁止输入。如果想app同时执行I/O 或者仅仅使用输入,那么必须要重新配置I/O 单元。具体看而已看Audio Unit Properties Reference中的kAudioOutputUnitProperty_EnableIO
除了远程I/O 和语音处理I/O 单元外,所有的ios音频单元都需要配置其kAudioUnitProperty_MaximumFramesPerSlice属性。该属性确保音频单元准好相应于渲染调用产生足够数量的音频数据帧。具体可以参考Audio Unit Properties Reference中的 kAudioUnitProperty_MaximumFramesPerSlice
所有的音频单元都需要再输入和输出或者两者上定义其音频流格式。具体可以看 Audio Stream Formats Enable Data Flow.
有关各种ios音频设备的特定流格式要求。可以看Using Specific Audio Units.
写入并附加渲染回调函数
对于采用渲染回调函数的设计模式,我们必须编写这些函数,然后将他们附加到正确的点上。 Render Callback Functions Feed Audio to Audio Units描述了这些回调函数并且解释了如何正确的工作原理。这里我们可以参考官方demo aurioTouch
当音频不流动,我们可以使用音频单元API 立即附加渲染回调如下
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = &renderCallback;
callbackStruct.inputProcRefCon = soundStructArray;
AudioUnitSetProperty (
myIOUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0, // output element
&callbackStruct,
sizeof (callbackStruct)
);
通过使用音频处理graph API ,我们可以以现场安全的方式附加渲染回调,即使在音频流动时候也可以这样做。
如下
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = &renderCallback;
callbackStruct.inputProcRefCon = soundStructArray;
AUGraphSetNodeInputCallback (
processingGraph,
myIONode,
0, // output element
&callbackStruct
);
// ... some time later
Boolean graphUpdated;
AUGraphUpdate (processingGraph, &graphUpdated);
连接音频单元节点
在大多数情况下,使用音频处理graph API中的AUGraphConnectNodeInput和AUGraphDisconnectNodeInput函数建立或断开音频之间的连接是最好和最容易的。这些函数是线程安全的,可以避免显示定义连接的编码开销,因为在不使用graph的时候必须这么做。
下列代码显示如何处理使用音频处理grahp API 混合器结点的输出连接到I/O 单元输出元件的输入
AudioUnitElement mixerUnitOutputBus = 0;
AudioUnitElement ioUnitOutputElement = 0;
AUGraphConnectNodeInput (
processingGraph,
mixerNode, // source node
mixerUnitOutputBus, // source node bus
iONode, // destination node
ioUnitOutputElement // desinatation node element
);
我们也可以使用音频单元属性机制直接建立和断开音频单元之间的连接。我们使用AudioUnitSetProperty函数的kAudioUnitProperty_MakeConnection属性,如下,该方法要求我们为每个连接定义AudioUnitConnection结构以用做其属性值。
AudioUnitElement mixerUnitOutputBus = 0;
AudioUnitElement ioUnitOutputElement = 0;
AudioUnitConnection mixerOutToIoUnitIn;
mixerOutToIoUnitIn.sourceAudioUnit = mixerUnitInstance;
mixerOutToIoUnitIn.sourceOutputNumber = mixerUnitOutputBus;
mixerOutToIoUnitIn.destInputNumber = ioUnitOutputElement;
AudioUnitSetProperty (
ioUnitInstance, // connection destination
kAudioUnitProperty_MakeConnection, // property key
kAudioUnitScope_Input, // destination scope
ioUnitOutputElement, // destination element
&mixerOutToIoUnitIn, // connection definition
sizeof (mixerOutToIoUnitIn)
);
提供用户界面
到这里,我们构建的app已经完成构建和配置。在许多情况下,我们需要提供一个用户界面,让用户微调音频行为。我们可以定制用户界面以允许用户调整特定的音频单元参数,并在某些特使情况下调整音频单元属性。
这里构建UI就不做赘述了
初始化并启动音频处理graph
在开始音频流之前,我们必须通过调用AUGraphInitialize函数来初始化音频graph,如下
- 1.通过为每个音频单独的调用AudioUnitInitialize函数来初始化graph所拥有的音频单元。(如果要在不适用grahp的情况下构建处理链,则必须依次显示初始化每个音频单元)
- 2.验证graph的连接和音频流数据格式
- 3.在音频单元连接上传播流格式
OSStatus result = AUGraphInitialize (processingGraph);
// Check for error. On successful initialization, start the graph...
AUGraphStart (processingGraph);
// Some time later
AUGraphStop (processingGraph);
故障排除提示
每当Core Audio功能提供返回值,捕获该值并检查成功或失败。失败时候,使用xcode的调试功能,可以看Xcode Debugging Guide。
注意函数调用之间的依赖关系。例如,只有在成功初始化后才能启动音频处理graph。检查AUGraphInitialize的返回值。如果函数成功返回,则可以启动graph。如果失败,确定出了什么问题。检查导致初始化的所有音频单元函数调用是否成功返回。具体可以参考mixerHost工程中的configureAndInitializeAudioProcessingGraph方法。
其次,如果图形初始化失败,请利用CAShow函数,此函数将graph的状态打印在xcode的控制台。mixerHost也有此技术的演示。
确保将每个AudioStreamBasicDescription结构初始化为0,如下
AudioStreamBasicDescription stereoStreamFormat = {0};
将ASBD的的字段初始化为0 ,可以确保没有字段包含垃圾数据。(在外部存储中声明结构的情况下-例如,作为类声明中的实例变量-其字段会自动初始化为0,我们无需自己初始化他们)
要将AudioStreamBasicDescription结构的字段值打印到xcode控制台,可以执行下列代码
- (void) printASBD: (AudioStreamBasicDescription) asbd {
char formatIDString[5];
UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID);
bcopy (&formatID, formatIDString, 4);
formatIDString[4] = '\0';
NSLog (@" Sample Rate: %10.0f", asbd.mSampleRate);
NSLog (@" Format ID: %10s", formatIDString);
NSLog (@" Format Flags: %10X", asbd.mFormatFlags);
NSLog (@" Bytes per Packet: %10d", asbd.mBytesPerPacket);
NSLog (@" Frames per Packet: %10d", asbd.mFramesPerPacket);
NSLog (@" Bytes per Frame: %10d", asbd.mBytesPerFrame);
NSLog (@" Channels per Frame: %10d", asbd.mChannelsPerFrame);
NSLog (@" Bits per Channel: %10d", asbd.mBitsPerChannel);
}
以上方法可以快速找到asbd中的问题
在为音频单元流格式定义ASBD的时候,请注意确保您遵循使用特定音频单元的使用表中的“Recommended stream format attributes”和“Stream format notes”。
使用特定的音频单元
每个ios音频单元都有一些与所有其他东西相同的东西以及某些独特的东西。本文档前面的章节描述了常见的方法,其中包括需要再运行时查询音频单元,实例化它,并确保其流格式的正确。本章将介绍音频单元之间的差异,并提供了有关如何使用它们的详细情况。
使用I/O 音频单元
ios 提供三个i/o (输入和输出)单元。绝大数音频单元app使用远程 I/O 单元,他连接到输入和输入音频的硬件,并提供对各个输入和输出音频样本值的低延迟的访问。对于VoIP应用,语言处理I/O单元通过添加回声消除和其他功能来扩展远程I/O单元。要将音频发送回app而不是输出音频硬件,需要通用输入单元。
远程I/O单元
远程I/O 单元(subtype kAudioUnitSubType_RemoteIO)连接到硬件设备,用于输入,输出或同时输入和输出。用于播放,录制或低延迟同时输入和输出,不需要回声消除。
设备的音频硬件将其音频流格式强制放置在远程I/O 单元的外侧,可以看 Understanding Where and How to Set Stream Formats.音频单元提供硬件音频格式和应用音频格式之间的格式转换,通过附带的格式转换器音频单元进行格式转换。
有关代码可以看 aurioTouch
Audio unit feature | Details |
---|---|
Elements | 一个input element:element 1,一个output element:element 0 |
推荐流格式属性 |
kAudioFormatLinearPCM AudioUnitSampleType kAudioFormatFlagsAudioUnitCanonical |
流格式说明 | 远程I/O的朝外侧从音频硬件获取其格式:如下所示: input element(element 1)所在的input scope从当前活动的音频输入硬件获取其流格式 output element(element 0)所在的output scope从当前活动的输出音频硬件获取其流格式 在input element所在的output scope 设置app格式。input element根据需要在其input 和ouptut的scope 之间进行格式转换。使用app流格式的硬件采样率 如果output element的input scope 由音频单元连接提供,那么它从该连接获取其流格式。但是,如果他由渲染回调函数提供,我们需要在其上设置app格式 |
参数 | 无 |
属性 | See I/O Audio Unit Properties . |
属性说明 | 我们不需要才次音频设备上设置kAudioUnitProperty_MaximumFramesPerSlice属性 |
上表流格式说明如下图
语音处理I/O单元
语音处理I/O单元(subtype kAudioUnitSubType_VoiceProcessingIO)具有远程I/O单元的特性,并为双向双工通信添加了回声抑制。他还增加了自动增益校正,语音处理质量调整和静音功能。该单元用于
VoIP 的应用
该单元包含所有远程I/O 单元的所有功能。此外,次音频单元还有特定的属性,可以看Voice-Processing I/O Audio Unit Properties
通用输出单元
将音频处理graph的输出发送到app而不是输出硬件的时候,需要使用子类型是kAudioUnitSubType_GenericOutput。我们通常会使用通用输出单元进行离线音频处理。与其他I/O单元一样,通用输出单元包含格式转换单元。这使通用输出单元可以在音频处理graph中使用的流格式与所需格式之间执行格式转换。
我们还可以使用通用输入单元作为作为subgraph的最终借点,放入superGraph 中。
使用混音器单元
ios 提供了两个混音器单元。在大多数情况下,我们应该使用多声道混音器单元,他可以为任意数量的单声道或者立体声流提供混音。如果需要3D 混音器单元的功能,我们可能会使用openAL.openAL建立在3DMixer 单元之上,提供与简单API 相同的性能,非常适合游戏app 开发。
多声道混音器单元
多声道混音器单元(子类型kAudioUnitSubType_MultiChannelMixer)可接收任意数量的单声道和立体声流,并将它们组合成单个立体声输出。它控制每个输入和输出的音频增益,并允许我们分别打开或者关闭每个输入。从ios4.0 开始,多声道混音器支持每个输入的立体声声像。
有关代码可以看mixerHost
Audio unit feature | Details |
---|---|
Elements | 一个或者多个input element ,每个input element可以是单声道或立体声 ,一个立体声output element |
推荐流格式属性 |
kAudioFormatLinearPCM AudioUnitSampleType kAudioFormatFlagsAudioUnitCanonical |
流格式说明 | 在input scope,管理流格式如下:如果input bus由音频单元连接,它将从该连接获取其流格式 如果input bus 由渲染回调函数提供,那么bus上设置完整的应用程序流格式。使用于回调提供的数据相同的流格式 在output scope,仅仅设置app的采样率就可以了 |
参数 | See Multichannel Mixer Unit Parameters . |
属性 | kAudioUnitProperty_MeteringMode |
属性说明 | 默认情况下kAudioUnitProperty_MaximumFramesPerSlice属性的值是1024 ,当屏幕锁定并且显示器休眠时,该值不够 。如果app在屏幕锁定的时候要播放音频,那么必须增加此属性的值。做法如下:如果音频输入处于活动状态,那么无需设置kAudioUnitProperty_MaximumFramesPerSlice属性 如果音频输入为激活,需要将该值设置为4096
|
3D 混音器单元
3D 混音器单元(subtype kAudioUnitSubType_3DMixe)控制每个输入的立体声声像,回放速度和增益,并控制其他特征,例如与收听者的视距。输出具有音频增益控制。要了解音频单元可以执行的操作可以考虑使用openAL
在大多数情况下,如果需要3D混音器单元的功能,最佳选择的是使用OpenAL. 可以看代码oalTouch
Audio unit feature | Details |
---|---|
Elements | 一个或者多个input element ,每个input element可以是单声道或立体声 ,一个立体声output element |
推荐流格式属性 | UInt16 kAudioFormatFlagsCanonical |
流格式说明 | 在input scope,管理流格式如下:如果input bus由音频单元连接,它将从该连接获取其流格式 如果input bus 由渲染回调函数提供,那么bus上设置完整的应用程序流格式。使用于回调提供的数据相同的流格式 在output scope,仅仅设置app的采样率就可以了 |
参数 | See 3D Mixer Unit Parameters . |
属性 | 看3D Mixer Audio Unit Properties. 注意,大多数这些属性仅在该音频单元的max os X 版本中实现的 |
属性说明 | 默认情况下kAudioUnitProperty_MaximumFramesPerSlice属性的值是1024 ,当屏幕锁定并且显示器休眠时,该值不够 。如果app在屏幕锁定的时候要播放音频,那么必须增加此属性的值。做法如下:如果音频输入处于活动状态,那么无需设置kAudioUnitProperty_MaximumFramesPerSlice属性 如果音频输入为激活,需要将该值设置为4096
|
使用效果单元
iPod EQ单元(子类型kAudioUnitSubType_AUiPodEQ)是iOS 4中提供的唯一效果单元。这与内置IPodapp使用的均衡器相同。要查看此音频设备的iPod应用程序用户界面,请转至设置> iPod> EQ。该音频单元提供一组预设均衡曲线,如低音增强器,流行音乐和口语。
您必须为iPod EQ设备提供自己的用户界面,就像您必须为任何音频设备一样。 Mixer iPodEQ AUGraph Test 项目演示了如何使用iPod EQ单元并显示一种为其提供用户界面的用法。
Audio unit feature | Details |
---|---|
Elements | 一个单声道或者立体声input element,一个单声道或者立体声output element |
推荐流格式属性 |
kAudioFormatLinearPCM AudioUnitSampleType kAudioFormatFlagsAudioUnitCanonical |
流格式说明 | 在input scope,管理流格式如下:如果input bus由音频单元连接,它将从该连接获取其流格式 如果input bus 由渲染回调函数提供,那么bus上设置完整的应用程序流格式。使用于回调提供的数据相同的流格式 在output scope,仅仅设置app的采样率就可以了 |
参数 | 无 |
属性 | kAudioUnitProperty_FactoryPresets和kAudioUnitProperty_PresentPreset |
属性说明 |