AUGraph - 动态重新配置?

时间:2014-04-13 05:06:03

标签: ios core-audio audiounit

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

  1. 多通道混合器 - >远程I / O
  2. 多通道混合器 - >转换器#0 - >带通滤波器 - >转换器#1 - >远程I / O
  3. (因为带通滤波器使用浮点格式,所以需要流转换器)

    两个设置都经过测试并自行开展;即,如果我从给定的设置(节点连接)开始,则图形正确呈现。 但是当我在播放过程中尝试重新排列节点时,出现了问题。

    我的连接代码是:

    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更改为O I。)

    我无法相信这些节点是不兼容的,因为如果我开始构建该配置,它就会起作用。

    那么,动态重新连接节点的正确方法是什么?我错过了什么?

    *很抱歉这个问题很长。

    编辑(解决方案?):正如我在评论中提到的那样,图表重新布线 必须在主线程中完成 ,而不是在Core Audio线程中(相关对象在该上下文中被锁定)。我将重新布线的代码移动到主线程(实例方法),并在<{em>}对AUGraphClearConnections()的任何调用之前添加了对AUGraphConnectNodeInput() 的调用,现在它可以正常工作,即使我没有停止/重新启动图表

    现在唯一的问题是,每当我重新连接时,所有声音都会停止播放(渲染回调停止被调用),直到我再次停止/启动这些声音。我必须检查调音台的每个总线,看看回调是否已连接,总线启用等等......我现在就做到这一点。

1 个答案:

答案 0 :(得分:5)

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

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

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

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