混音器 AudioUnit 到 RemoteIO AudioUnit

Posted

技术标签:

【中文标题】混音器 AudioUnit 到 RemoteIO AudioUnit【英文标题】:Mixer AudioUnit to RemoteIO AudioUnit 【发布时间】:2014-08-02 13:28:04 【问题描述】:

我有一个带有对应回调的 AudioUnit 可以正常工作,但是现在,我需要将它发送到 RemoteIO,因为我正在实现一些需要 RemoteIO AudioUnit 才能工作的框架。

那么...我需要与此音频单元混音器相同的输出,但需要另一个 kAudioUnitSubType_RemoteIO 类型的音频单元。

请帮忙!

编辑... 这是我正在尝试的代码... 编辑 2- 添加了 iOUnitDescription

AudioComponentDescription iOUnitDescription;
iOUnitDescription.componentType          = kAudioUnitType_Output;
iOUnitDescription.componentSubType       = kAudioUnitSubType_RemoteIO;
iOUnitDescription.componentManufacturer  = kAudioUnitManufacturer_Apple;
iOUnitDescription.componentFlags         = 0;
iOUnitDescription.componentFlagsMask     = 0;


AudioComponent foundIoUnitReference = AudioComponentFindNext (
                                                              NULL,
                                                              &iOUnitDescription
                                                              );
AudioComponentInstanceNew (
                           foundIoUnitReference,
                           &audioUnit
                           );

result = AudioUnitSetProperty (
                               audioUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Input,
                               guitarBus,
                               &stereoStreamFormat,
                               sizeof (stereoStreamFormat)
                               );

if (noErr != result) [self printErrorMessage: @"AudioUnitSetProperty (set mixer unit guitar input bus stream format)" withStatus: result];return;
result = AudioUnitSetProperty (
                               audioUnit,
                               kAudioUnitProperty_SampleRate,
                               kAudioUnitScope_Output,
                               0,
                               &graphSampleRate,
                               sizeof (graphSampleRate)
                               );
if (noErr != result) [self printErrorMessage: @"AudioUnitSetProperty (set AUDIOUNIT unit output stream format)" withStatus: result]; return;


AudioUnitElement mixerUnitOutputBus  = 0;
AudioUnitElement ioUnitOutputElement = 0;

AudioUnitConnection mixerOutToIoUnitIn;
mixerOutToIoUnitIn.sourceAudioUnit    = mixerUnit;
mixerOutToIoUnitIn.sourceOutputNumber = mixerUnitOutputBus;
mixerOutToIoUnitIn.destInputNumber    = ioUnitOutputElement;

AudioUnitSetProperty (
                      audioUnit,                     // connection destination
                      kAudioUnitProperty_MakeConnection,  // property key
                      kAudioUnitScope_Input,              // destination scope
                      ioUnitOutputElement,                // destination element
                      &mixerOutToIoUnitIn,                // connection definition
                      sizeof (mixerOutToIoUnitIn)
                      );

【问题讨论】:

发布您的 AudioUnit 设置的一些代码,这实际上是添加额外的 AudioUnit 并进行正确连接的情况。 【参考方案1】:

我真的需要更多信息。从上面,我看到你在某个地方有一个混音器,一个 guitarBus 大概是你的输入(并且似乎是一个流)。 &iOUnitDescription 的定义是什么。更重要的是,你在哪里挂钩你的 renderCallback,你在回调中做什么以及框架期望什么?

通常,当我需要处理音频时,我会构建自己的图表;为了更好的可移植性,我把它作为自己的类。这对你来说应该是一个很好的起点

这是我如何实现这样的解决方案。

 // header file

  @interface MDMixerGraph : NSObject
    AUGraph graph;
    AudioUnit mixerUnit;
    AudioUnit inputUnit;
    AudioUnit rioUnit;
   
  -(void) setupAUGraph;
  @end

  // implementation

  @implementation MDMixerGraph

  // exception Helper 
  void MDThrowOnError(OSStatus status)
  if (status != noErr) 
      @throw [NSException exceptionWithName:@"MDMixerException"
                                   reason:[NSString stringWithFormat:@"Status Error %d).", (int)status]
                                    userInfo:nil];
     
  


   // helper method for setting up graph nodes
   OSStatus MDAdAUGraphdNode(OSType inComponentType, OSType inComponentSubType, AUGraph inGraph, AUNode *outNode)
   
     AudioComponentDescription desc;
     desc.componentType = inComponentType;
     desc.componentSubType = inComponentSubType;
     desc.componentFlags = 0;
     desc.componentFlagsMask = 0;
     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
     return AUGraphAddNode(inGraph, &desc, outNode);
   

   // setup method to init and start AUGraph
   -(void) setupAUGraph

    //Create the Graph
    MDThrowOnError(NewAUGraph(&graph));

   // setup AU Units
   // Add Audio Units (Nodes) to the graph
   AUNode inputNode, rioNode, mixerNode;

//Input Node -- this may need to be a different type to accept your Stream (not enough info above) 
MDThrowOnError(MDAdAUGraphdNode(kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, graph, &inputUnit));

//Remote IO Node - your output node
MDThrowOnError(MDAdAUGraphdNode(kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, graph, &rioNode));

//mixerNode - Depending on output and input change the mixer sub-type here
// you can configure additional nodes depending on your needs for inputs and outputs
MDThrowOnError(MDAdAUGraphdNode(kAudioUnitType_Mixer, kAudioUnitSubType_AU3DMixerEmbedded, graph, &mixerNode));

// open graph
MDThrowOnError(AUGraphOpen(graph));

// we need a ref to the Audio Units so lets grab all of them here

MDThrowOnError(AUGraphNodeInfo(graph, inputNode, NULL, &inputUnit));
MDThrowOnError(AUGraphNodeInfo(graph, rioNode, NULL, &rioUnit));
MDThrowOnError(AUGraphNodeInfo(graph, mixerNode, NULL, &mixerUnit));

// setup the connections here, input to output of the graph.
/// the graph looks like inputNode->mixerNode->rioNode

MDThrowOnError(AUGraphConnectNodeInput(graph, inputNode, 0, mixerNode, 0));
MDThrowOnError(AUGraphConnectNodeInput(graph, mixerNode, 0, rioNode, 0));

// Init the graph

MDThrowOnError(AUGraphInitialize(graph));

//do any other setup here for your stream    

// Finally, Start the graph

MDThrowOnError(AUGraphStart(graph));


在您的 View Controller 扩展中,您只需;

  // define the MDMixerGraph Class
  // @property (nonatomic) MDMixerGraph *mixer;

在实现中

  self.mixer = [[MDMixerGraph alloc]init];
 [self.mixer setupAUGraph];

并且您已经引用了 rioUnit 以传递给您的框架 (self.mixer.rioUnit);在不了解您的需求连接/处理的更多信息的情况下,这是我能为您做的最好的事情。

干杯!

【讨论】:

感谢您的回答。我在问题上添加了 &iOUnitDescription 的定义和调用渲染回调的方式。在回调中,我正在混合样本,没有得到输入,所以 guitarBus 并不是真正的吉他,而是打击乐样本的总线。 真的我用的是Mixerhost sample的base,这部分代码是一样的。渲染回调运行良好,一切运行良好,但我需要获取带有混音器音频单元输出的 RemoteIO 音频单元 尝试理解代码而不是复制它...如果您仔细查看 MixerHost 代码,您会发现图表设置与我上面的代码相似。您只需要“公开” ioNode。正如我上面所说,在标题中声明一个 AudioUnit rioUnit。然后获取参考(再次像我上面所做的那样)......使用 MixerHose 名称的代码将是 result = AUGraphNodeInfo ( processingGraph, ioNode, NULL, &rioUnit ); -- 你可以将 rioUnit 传递给你的框架 澄清一下,混音器已经连接到 RemoteIO 单元,您只需使其可见,以便将其传递给您的框架。您可以使用 AUGraphNodeInfo 执行此操作。

以上是关于混音器 AudioUnit 到 RemoteIO AudioUnit的主要内容,如果未能解决你的问题,请参考以下文章

如何在苹果的 AudioUnit 3D 混音器上设置总线?

ExtAudioFileWrite 创建静音 m4a

如何使用带有 Xamarin 的 AudioUnit 录制音频

CoreAudio,iOS:无法通过 RemoteIO 使用单声道输入和立体声输出

如何在 iPhone 的 Core Audio (Audio Unit/ Remote IO) 中将录制的声音更改为男人的声音

在 iOS 上使用音频单元混合多个信号