AUGraph - 动态重新配置?

Nic*_*ari 3 core-audio audiounit ios

我想在播放(渲染)过程中重新安排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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(图形和节点是文件范围的全局变量.这个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
Run Code Online (Sandbox Code Playgroud)

(最后一次连接中的"0Hz"部分有点警报,但此时声音正常流动)

当我尝试使用回调绕过过滤器kAUGraphErr_InvalidConnection时,在将混音器连接到输出时,我得到了可怕的-10861错误().

当我尝试绕过主线程上的过滤器(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)
Run Code Online (Sandbox Code Playgroud)

(注意在更新时问题活动:部分详细介绍了不可能进行连接Multichannel MixerRemote I/O此外,.O之后每个节点变为O I.)

我无法相信节点是不兼容的,因为如果我从表单开始配置,它就可以工作.

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

*很抱歉这个问题很长.

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

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

Nic*_*ari 5

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

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

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

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

这样就可以了.