首页 \ 问答 \ AUGraph - 动态重新配置?(AUGraph - reconfigure on the fly?)

AUGraph - 动态重新配置?(AUGraph - reconfigure on the fly?)

我想在播放(渲染)期间重新排列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() (在“实时优先级线程”中运行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变为OI 。)

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

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

*很抱歉这个问题很长。

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

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


I am trying to rearrange the nodes in an AUGraph during playback (render). In particular, I am trying to switch between these two setups:

  1. Multichannel Mixer -> Remote I/O
  2. Multichannel Mixer -> Converter #0 -> Bandpass Filter -> Converter #1 -> Remote I/O

(The stream converters are needed because the bandpass filter uses a floating point format)

Both setups atre tested and work on their own; i.e., if I start with a given setup (node connections), the graph renders properly. But when I try to rearrange the nodes during playback, something goes wrong.

My connection code is this:

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");
        }
    }
}

(The graph and nodes are file-scope globals. This C function is defined in the same file as my Obj-C sound manager class). I use this same function both at graph initialization and afterwards for switching.

I've tried two approaches:

  • Calling the enableBandpassFilter() right away (from within an Obj-C method), and

  • Register a notification callback with AUGraphAddRenderNotify() (which runs in the 'real time priority thread') and calling enableBandpassFilter() from within the callback.

Both approaches fail miserably. To make thing simple and avoid the pitfall of disconnected audio units not being initialized when the graph starts, I start with the 5 node configuration #2 above (bandpass filter: on) and from there try to switch to the bypass configuration #1 above (bandpass filter: off).

On startup, the audio graph looks like this:

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

(The "0Hz" part in the last connection is a bit alarming, but sound flows properly at this point)

When I try to bypass the filter using callbacks, I get the dreaded -10861 error (kAUGraphErr_InvalidConnection) when connection the mixer to the output.

When I try to bypass the filter on the main thread (Obj-C method), I get no error result codes but the filter is not deactivated.

In both cases, after the switch the graph log becomes this:

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)

(Notice the Problem Events when updated: part detailing the impossibility to connect Multichannel Mixer and Remote I/O. Also, the O after each node changes into O I.)

I can't believe the nodes are incompatible, because if I start form that configuration, it works.

So, what is the proper way to reconnect nodes on the fly? What am I missing?

*Sorry for the long question.

EDIT (Solution?): As I mentioned in the comments, it turns out the graph rewiring must be done in the main thread, and not in the Core Audio thread (the relevant objects are locked in that context). I moved the rewiring code to the main thread (instance method), and also added a call to AUGraphClearConnections() before any call to AUGraphConnectNodeInput(), and now it works, even if I don't stop/restart the graph.

The only problem right now is, whenever I rewire, all sounds playing stop (render callbacks stop being called) until I stop/start those sounds again. I must inspect each bus of the mixer to see if the callback is attached, bus enabled, etc... I'll do just that right now.


原文:https://stackoverflow.com/questions/23039319
更新时间:2023-08-29 09:08

最满意答案

我想我已经就此得出了自己的结论。 我决定使用Drop Off库作为Content Organizer内置功能的一部分(上面的#1)。 到目前为止,这似乎是最简单的方法,因为我可以通过功能的Entity.xml文件中的配置来完成大部分操作。 我尝试过的许多其他方法似乎都需要Sandbox解决方案中没有的功能。

为了实现这一点,我定义了站点列并将它们添加到自定义文档类型,然后将此文档类型添加到所有库。 使用Drop Off库,我可以定义规则以根据自定义文档类型中的一个字段移动文件。 我希望做任何后续步骤,作为在上传文件或作为关联表格时在Drop Off库上启动的工作流程。


I think I've come to my own conclusions on this. I've decided to go with a Drop Off library as part of the Content Organizer built-in feature (#1 above). This appears to be the simplest approach so far since I can do the majority through configuration in the Entity.xml files of the features. Many of the other methods I tried seems like they would require functionality not available in a Sandbox solution.

In order to achieve this, I defined site columns and added them to custom Document Type, then added this Document Type to all libraries. Using the Drop Off library, I can define rules to move the file based on one of the fields in the custom Document Type. I'm hoping to do any follow-up steps as a workflow that kicks off on the Drop Off library when a file is uploaded or as an Associated Form.

相关问答

更多
  • 我想我已经就此得出了自己的结论。 我决定使用Drop Off库作为Content Organizer内置功能的一部分(上面的#1)。 到目前为止,这似乎是最简单的方法,因为我可以通过功能的Entity.xml文件中的配置来完成大部分操作。 我尝试过的许多其他方法似乎都需要Sandbox解决方案中没有的功能。 为了实现这一点,我定义了站点列并将它们添加到自定义文档类型,然后将此文档类型添加到所有库。 使用Drop Off库,我可以定义规则以根据自定义文档类型中的一个字段移动文件。 我希望做任何后续步骤,作为在 ...
  • 实现这一目标的方法是设置等待特定响应。 并设置结果等待被拒绝。 因此,Workflow会自动向尚未响应的用户发送邮件,并删除任务项。 希望这对某人有所帮助。 Way to achieve this is to set wait for particular response . and set outcome to wait for rejected. So that Workflow will automatically send mail to user who have not responded y ...
  • 使用以下代码的事件接收器(ItemAdded): public override void ItemAdded(SPItemEventProperties properties) { base.ItemAdded(properties); //Updating the column properties.ListItem["EventReceiver"] = "True"; //Commit change ...
  • 通过将Nintex 2013 Workflow 3.1.2.0升级到3.1.4.11解决了问题,但未在发行说明中提及。 Issue was solved with upgrading Nintex 2013 Workflow 3.1.2.0 to 3.1.4.11 Not mentioned in the release notes though.
  • 在Sharepoint Designer中,选择要将工作流添加到的库。 单击功能区上的“列出工作台” 为您的工作流程和可选描述提供名称 在工作流程设计器中设置工作流程: 一个。 添加操作“发送电子邮件” 湾 指定您可以使用Lookups搜索与您上传或修改的项目相关的值的电子邮件参数。 例如,您可以在该字段中选择Sharepoint Group,甚至是创建当前项目的用户 C。 在正文字段中,您可以通过单击添加或更改查找来插入文档名称,标题等值 d。 根据需要添加更多操作 单击功能区中的“工作流程设置” 取消允 ...
  • 没有将工作流与列表定义关联的默认方式,如果您想要执行以下任一选项,请执行以下操作 编写一个功能接收器并编写代码将工作流关联到列表。 另一种选择是创建内容类型,并且可以使用功能将工作流与该内容类型相关联。 There is no default way to associate a Workflow to the List Definition, If you want to do you have to follow one of the following option Write a Feature R ...
  • 作为参考,这是我发现的: 要使批准功能正常工作,列表应该具有: 选中“需要内容审批”选项(该选项在版本控制设置中可用)。 在工作流程配置中,选中“更新审批状态(使用此工作流程来控制内容审批)”选项。 如果工作流配置为控制内容批准,但该列表未在其上配置内容批准,则SharePoint会生成上述错误。 For reference, this is what i've found: For the approval functionality to work correctly, the list should ...
  • 调用此函数传递指定的参数: static void StartWorkflow(SPListItem listItem, SPSite spSite, string wfName) { SPList parentList = listItem.ParentList; SPWorkflowAssociationCollection associationCollection = parentList.WorkflowAssociations; f ...
  • 键入current然后按Enter键将显示所需的If语句。 Type current and then press enter it will give the If statement required.
  • 系统帐户无法触发SharePoint中的工作流,这可能是您在“创建者”中的用户名。 手动创建列表项(使用添加项)时,您使用您的用户帐户创建了该项。 最简单和最安全的做法是删除RunWithElevatedPermissions,但只有那些有权在目标列表中创建条目的用户才能使用您的页面。 如果您的要求说其他用户也必须使用您的页面,则必须使用模拟。 您所做的是使用具有在列表中创建项目的权限的非系统用户的凭据SPUserToken 。 这篇博客文章有一个关于如何使用SPUserToken的例子。 您也可以作为不同 ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。