【问题标题】:AUGraph - reconfigure on the fly?AUGraph - 即时重新配置?
【发布时间】:2014-04-13 05:06:02
【问题描述】:

我正在尝试在播放(渲染)期间重新排列 AUGraph 中的节点。特别是,我试图在这两种设置之间切换:

  1. 多通道混音器 -> 远程 I/O
  2. 多通道混音器 -> 转换器 #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 MixerRemote 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


【解决方案1】:

事实证明,图形重新布线必须在主线程中完成,而不是在 Core Audio 线程中:相关对象被锁定在该上下文中(一些 - 不可否认,有时是矛盾的? - Core Audio 官方文档似乎建议您可以在任何上下文中执行此操作,因为 AUGraph 是线程安全的并且可以处理所有事情)。

所以我将重新布线的代码移到了我的类的一个实例方法中(它在主线程上运行),并且在对AUGraphConnectNodeInput() 的任何调用之前添加了对AUGraphClearConnections() 的调用,现在它可以工作了,即使我不要停止/重新启动图表。

所以我要做的是(主线程):

  1. 致电AUGraphClearConnections()(断开所有连接)。
  2. 建立所有连接(新节点和现有节点,最终形式的完整图)。这包括节点以及输入渲染回调。
  3. 同步模式下调用AUGRaphUpdate()(将NULL传递给第二个参数)。

这就是诀窍。

【讨论】:

  • 我会等几天再接受我自己的答案,以防万一出现更好的情况。
  • 谢谢尼古拉斯。诀窍是AUGRaphUpdate。我终于让我的也开始工作了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多