核心音频 - Interapp音频 - 如何从Host App内的Node应用程序中检索输出音频数据包?

Sab*_*bin 5 iphone audio core-audio ipad ios

我正在编写一个HOST应用程序,它使用Core Audio的新iOS 7 Inter App Audio技术从单个NODE"生成器"应用程序中提取音频并将其路由到我的host应用程序中.我正在使用音频组件服务和音频单元组件服务C框架来实现这一目标.

我想要实现的是建立与可以生成声音的外部节点应用程序的连接.我希望将声音路由到我的主机应用程序,并让我的主机应用程序能够直接访问音频数据包数据作为原始音频数据流.

我在我的HOST应用程序中编写了代码,按顺序执行以下操作:

  1. 使用正确的会话类别设置和激活音频会话.
  2. 刷新一个类型为(kAudioUnitType_RemoteGeneratorkAudioUnitType_RemoteInstrument我对效果应用程序不感兴趣)的interpp音频兼容应用程序列表.
  3. 从该列表中拉出最后一个对象并尝试使用建立连接 AudioComponentInstanceNew()
  4. 设置我的主机应用程序需要音频格式的音频流基本描述.
  5. 在输出范围(总线)上设置音频单元属性和回调以及音频单元渲染回调.
  6. 初始化音频单元.

到目前为止,我已经能够成功建立连接,但我的问题是我的渲染回调根本没有被调用.我无法理解的是如何从节点应用程序中提取音频?我已经读过我需要调用AudioUnitRender()才能在节点应用程序上启动渲染周期,但是在我的情况下需要如何设置呢?我已经看到了其他示例,其中从渲染回调中调用了AudioUnitRender(),但是这对我不起作用,因为我的渲染回调当前没有被调用.我是否需要设置自己的音频处理线程并定期调用AudioUnitRender()我的"节点"?

以下是我的HOST应用程序内部描述的代码.

static OSStatus MyAURenderCallback (void                        *inRefCon,
                                    AudioUnitRenderActionFlags  *ioActionFlags,
                                    const AudioTimeStamp        *inTimeStamp,
                                    UInt32                      inBusNumber,
                                    UInt32                      inNumberFrames,
                                    AudioBufferList             *ioData) 
{
     //Do something here with the audio data? 
     //This method is never being called? 
     //Do I need to puts AudioUnitRender() in here? 
}

    - (void)start
    {
        [self configureAudioSession];
        [self refreshAUList];
    }

    - (void)configureAudioSession
    {
        NSError *audioSessionError = nil;
        AVAudioSession *mySession = [AVAudioSession sharedInstance];
        [mySession setPreferredSampleRate: _graphSampleRate error: &audioSessionError];
        [mySession setCategory: AVAudioSessionCategoryPlayAndRecord error: &audioSessionError];
        [mySession setActive: YES error: &audioSessionError];
        self.graphSampleRate = [mySession sampleRate];
    }

    - (void)refreshAUList
    {
        _audioUnits = @[].mutableCopy;

        AudioComponentDescription searchDesc = { 0, 0, 0, 0, 0 }, foundDesc;
        AudioComponent comp = NULL;

        while (true) {

        comp = AudioComponentFindNext(comp, &searchDesc);

        if (comp == NULL) break;

        if (AudioComponentGetDescription(comp, &foundDesc) != noErr) continue;

        if (foundDesc.componentType == kAudioUnitType_RemoteGenerator || foundDesc.componentType == kAudioUnitType_RemoteInstrument) {

            RemoteAU *rau = [[RemoteAU alloc] init];
            rau->_desc = foundDesc;
            rau->_comp = comp;

            AudioComponentCopyName(comp, &rau->_name);
            rau->_image = AudioComponentGetIcon(comp, 48);
            rau->_lastActiveTime = AudioComponentGetLastActiveTime(comp);

            [_audioUnits addObject:rau];
        }
    }

    [self connect];
}

- (void)connect  {

    if ([_audioUnits count] <= 0) {
        return;
    }

    RemoteAU *rau = [_audioUnits lastObject];

    AudioUnit myAudioUnit;

    //Node application will get launched in background
    Check(AudioComponentInstanceNew(rau->_comp, &myAudioUnit));

    AudioStreamBasicDescription format = {0};
    format.mChannelsPerFrame  = 2;
    format.mSampleRate = [[AVAudioSession sharedInstance] sampleRate];
    format.mFormatID = kAudioFormatMPEG4AAC;
    UInt32 propSize = sizeof(format);
    Check(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &propSize, &format));

    //Output format from node to host
    Check(AudioUnitSetProperty(myAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &format, sizeof(format)));

    //Setup a render callback to the output scope of the audio unit representing the node app
    AURenderCallbackStruct callbackStruct = {0};
    callbackStruct.inputProc = MyAURenderCallback;
    callbackStruct.inputProcRefCon = (__bridge void *)(self);
    Check(AudioUnitSetProperty(myAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Output, 0, &callbackStruct, sizeof(callbackStruct)));

    //setup call backs
    Check(AudioUnitAddPropertyListener(myAudioUnit, kAudioUnitProperty_IsInterAppConnected, IsInterappConnected, NULL));
    Check(AudioUnitAddPropertyListener(myAudioUnit, kAudioOutputUnitProperty_HostTransportState, AudioUnitPropertyChangeDispatcher, NULL));

    //intialize the audio unit representing the node application
    Check(AudioUnitInitialize(myAudioUnit));
}
Run Code Online (Sandbox Code Playgroud)