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

时间:2014-05-13 08:52:13

标签: ios iphone ipad audio core-audio

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

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

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

  1. 使用正确的会话类别设置和激活音频会话。
  2. 刷新kAudioUnitType_RemoteGeneratorkAudioUnitType_RemoteInstrument类型的interpp音频兼容应用列表(我对效果应用不感兴趣)。
  3. 从该列表中拉出最后一个对象,并尝试使用AudioComponentInstanceNew()
  4. 建立连接
  5. 设置我的主机应用需要音频格式的音频流基本描述。
  6. 在输出范围(总线)上设置音频单元属性和回调以及音频单元渲染回调。
  7. 初始化音频单元。
  8. 到目前为止,我已经能够成功建立连接,但我的问题是我的渲染回调根本没有被调用。我无法理解的是如何从节点应用程序中提取音频?我已经读过我需要调用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));
    }
    

0 个答案:

没有答案