【发布时间】:2014-04-13 05:06:02
【问题描述】:
我正在尝试在播放(渲染)期间重新排列 AUGraph 中的节点。特别是,我试图在这两种设置之间切换:
- 多通道混音器 -> 远程 I/O
- 多通道混音器 -> 转换器 #0 -> 带通滤波器 -> 转换器 #1 -> 远程 I/O
(需要流转换器,因为带通滤波器使用浮点格式)
这两种设置都经过了测试并且可以独立运行;即,如果我从给定的设置(节点连接)开始,图形会正确呈现。 但是当我尝试在播放过程中重新排列节点时,出现了问题。
我的连接代码是这样的:
void enableBandpassFilter(Boolean enable)
{
OSStatus result;
if (enable) {
// [ A ] Enable
// Connect mixer to converter0
result = AUGraphConnectNodeInput(processingGraph, // (in) graph
mixerNode, // (in) src node
0, // (in) src output number
converterNode0, // (in) dst node
0); // (in) dst input number
if ( result != noErr ){
DLog(@"AUGraphConnectNodeInput() Failed for mixer->converter0");
}
// Connect converter0 to bandpass
result = AUGraphConnectNodeInput(processingGraph, // (in) graph
converterNode0, // (in) src node
0, // (in) src output number
bandpassNode, // (in) dst node
0); // (in) dst input number
if ( result != noErr ){
DLog(@"AUGraphConnectNodeInput() Failed for converter0->bandpass");
}
// Connect bandpass to converter1
result = AUGraphConnectNodeInput(processingGraph, // (in) graph
bandpassNode, // (in) src node
0, // (in) src output number
converterNode1, // (in) dst node
0); // (in) dst input number
if ( result != noErr ){
DLog(@"AUGraphConnectNodeInput() Failed for bandpass->converter1");
}
// Connect converter1 to i/o
result = AUGraphConnectNodeInput(processingGraph,
converterNode1,
0,
remoteIONode,
0);
if ( result != noErr ){
DLog(@"AUGraphConnectNodeInput() Failed for converter1->output");
}
}
else{
// [ B ] Disable
result = AUGraphDisconnectNodeInput(processingGraph,
remoteIONode,
0);
if ( result != noErr ){
DLog(@"AUGraphDisconnectNodeInput() Failed for output");
}
// Connect mixer to remote I/O
result = AUGraphConnectNodeInput(processingGraph, // (in) graph
mixerNode, // (in) src node
0, // (in) src output number
remoteIONode, // (in) dst node
0); // (in) dst input number
if ( result != noErr ){
DLog(@"AUGraphConnectNodeInput() Failed for mixer->output");
}
}
}
(图形和节点是文件范围的全局变量。这个 C 函数与我的 Obj-C 声音管理器类在同一个文件中定义)。我在图形初始化和之后都使用相同的函数进行切换。
我尝试了两种方法:
立即致电
enableBandpassFilter()(在 Obj-C 方法),以及使用
AUGraphAddRenderNotify()注册通知回调 (在“实时优先级线程”中运行)并调用enableBandpassFilter()来自回调。
这两种方法都失败了。为了简单起见并避免在图表开始时未初始化断开的音频单元的陷阱,我从上面的 5 节点配置 #2(带通滤波器:打开)开始,然后尝试切换到上面的旁路配置 #1(带通滤波器:关闭)。
启动时,音频图如下所示:
AudioUnitGraph 0x1E9B000:
Member Nodes:
node 1: 'aumx' 'mcmx' 'appl', instance 0x170820fe0 O
node 2: 'aufc' 'conv' 'appl', instance 0x178424040 O
node 3: 'aufx' 'bpas' 'appl', instance 0x1784241a0 O
node 4: 'aufc' 'conv' 'appl', instance 0x1708295a0 O
node 5: 'auou' 'rioc' 'appl', instance 0x17082b020 O
Connections:
node 1 bus 0 => node 2 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x00000C2C) 8.24-bit little-endian signed integer, deinterleaved]
node 2 bus 0 => node 3 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 3 bus 0 => node 4 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 4 bus 0 => node 5 bus 0 [ 2 ch, 0 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
Input Callbacks:
{0x10000d17c, 0x10004ea90} => node 1 bus 0 [2 ch, 44100 Hz]
{0x10000d17c, 0x10004ea90} => node 1 bus 1 [2 ch, 44100 Hz]
{0x10000d17c, 0x10004ea90} => node 1 bus 2 [2 ch, 44100 Hz]
{0x10000d17c, 0x10004ea90} => node 1 bus 3 [2 ch, 44100 Hz]
CurrentState:
mLastUpdateError=0, eventsToProcess=F, isInitialized=F, isRunning=F
(上次连接中的“0Hz”部分有点吓人,但此时声音正常)
当我尝试使用回调绕过过滤器时,在将混音器连接到输出时出现可怕的 -10861 错误 (kAUGraphErr_InvalidConnection)。
当我尝试绕过主线程上的过滤器(Obj-C 方法)时,我没有收到错误结果代码,但过滤器没有被停用。
在这两种情况下,切换后图表日志变为:
AudioUnitGraph 0x1EA2000:
Member Nodes:
node 1: 'aumx' 'mcmx' 'appl', instance 0x178228d80 O I
node 2: 'aufc' 'conv' 'appl', instance 0x17062c760 O I
node 3: 'aufx' 'bpas' 'appl', instance 0x17062dfe0 O I
node 4: 'aufc' 'conv' 'appl', instance 0x170636d00 O I
node 5: 'auou' 'rioc' 'appl', instance 0x170637200 O I
Connections:
node 1 bus 0 => node 2 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x00000C2C) 8.24-bit little-endian signed integer, deinterleaved]
node 2 bus 0 => node 3 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 3 bus 0 => node 4 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
Input Callbacks:
{0x1000452fc, 0x100086a40} => node 1 bus 0 [2 ch, 44100 Hz]
{0x1000452fc, 0x100086a40} => node 1 bus 1 [2 ch, 44100 Hz]
{0x1000452fc, 0x100086a40} => node 1 bus 2 [2 ch, 44100 Hz]
{0x1000452fc, 0x100086a40} => node 1 bus 3 [2 ch, 44100 Hz]
Problem Events when updated:
connect:source=1,bus=0,dest=5,bus=0
CurrentState:
mLastUpdateError=0, eventsToProcess=F, isInitialized=T, isRunning=T (1)
(请注意 更新时的问题事件: 部分详细说明了无法连接 Multichannel Mixer 和 Remote I/O。此外,每个节点更改为 O I 后的 O。 )
我不敢相信节点是不兼容的,因为如果我从那个配置开始,它就可以工作。
那么,动态重新连接节点的正确方法是什么?我错过了什么?
*抱歉问题太长了。
编辑(解决方案?):正如我在 cmets 中提到的,事实证明图重新布线必须在主线程中完成 ,而不是在 Core Audio 线程中(相关对象被锁定在该上下文中)。我将重新布线代码移至主线程(实例方法),并且还添加了对AUGraphClearConnections() 的调用在任何对AUGraphConnectNodeInput() 的调用之前,现在它可以工作了,即使我不这样做'不停止/重新启动图表。
现在唯一的问题是,每当我重新接线时,所有声音都会停止播放(渲染回调停止被调用),直到我再次停止/启动这些声音。我必须检查混音器的每条总线,看看是否附加了回调、是否启用了总线等...我现在就这样做。
【问题讨论】:
-
个人经验:我测试了几天,从来没有让任何 AU 组件在运行中成功重新连接,尽管文档说它可以......我总是不得不停止Audio Graph,断开并重新连接,然后重新启动 Audio Graph。
-
好的,但是那行得通吗?它会产生任何可听的伪影,还是无缝的?
-
刚刚找到这篇博文。它说应该始终从主线程调用 AUGraphUpdate,而不是 Core Audio 线程...forum.theamazingaudioengine.com/discussion/96/…
-
感谢您的博文,我以为我在 main 上调用了所有内容,但会再次检查。 Stop and Start AUGraph 方式不是无缝的,因为我正在播放从麦克风实时收集的音频,我可以听到很短的 Off-Time。
-
检查我的编辑:您不需要停止图表,只需使用 AUGraphClearConnections()。或者至少这对我有用!
标签: ios core-audio audiounit