使用Core Audio获取麦克风输入和扬声器输出

时间:2015-08-12 18:46:45

标签: ios objective-c core-audio

所以我最近调查了核心数据并且仍然是新手。我无法理解我要录制的数据以及它如何影响整体数据流。所以对于某些背景,我有一个应用程序,使用webRTC在手机之间进行视频/音频流。但是,我想查看通过麦克风输入设备的数据和通过扬声器输出的数据。我查看了AurioTouch演示和Core Audio,目前我有这个:

- (void)setupIOUnit
{
    // Create a new instance of AURemoteIO

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

    AudioComponent comp = AudioComponentFindNext(NULL, &desc);
    AudioComponentInstanceNew(comp, &rioUnit);

    //  Enable input and output on AURemoteIO
    //  Input is enabled on the input scope of the input element
    //  Output is enabled on the output scope of the output element

    UInt32 one = 1;
    AudioUnitSetProperty(rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof(one));
    AudioUnitSetProperty(rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &one, sizeof(one));


    // Set the MaximumFramesPerSlice property. This property is used to describe to an audio unit the maximum number
    // of samples it will be asked to produce on any single given call to AudioUnitRender
    UInt32 maxFramesPerSlice = 4096;
    AudioUnitSetProperty(rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(UInt32));

    // Get the property value back from AURemoteIO. We are going to use this value to allocate buffers accordingly
    UInt32 propSize = sizeof(UInt32);
    AudioUnitGetProperty(rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, &propSize);

    // Set the render callback on AURemoteIO
    AURenderCallbackStruct renderCallback;
    renderCallback.inputProc = performRender;
    renderCallback.inputProcRefCon = NULL;
    AudioUnitSetProperty(rioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(renderCallback));

    NSLog(@"render set now");
    // Initialize the AURemoteIO instance
    AudioUnitInitialize(rioUnit);
    [self startIOUnit];
    return;
}

- (OSStatus)startIOUnit
{
    OSStatus err = AudioOutputUnitStart(rioUnit);
    if (err) NSLog(@"couldn't start AURemoteIO: %d", (int)err);
    return err;
}

渲染回调函数

static OSStatus performRender (void                         *inRefCon,
                           AudioUnitRenderActionFlags   *ioActionFlags,
                           const AudioTimeStamp         *inTimeStamp,
                           UInt32                       inBusNumber,
                           UInt32                       inNumberFrames,
                           AudioBufferList              *ioData)
{
    OSStatus err = noErr;
//    the data gets rendered here

    err = AudioUnitRender(rioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, ioData);

    if (ioData->mBuffers[0].mDataByteSize >= 12) {
        NSData *myAudioData = [NSData dataWithBytes: ioData->mBuffers[0].mData length:12];
        NSLog(@" playback's first 12 bytes: %@", myAudioData);
    }

    for (UInt32 i=0; i<ioData->mNumberBuffers; ++i) {
        memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
    }

    return err;
}

这会打印出一些数据,此时我不知道它是麦克风输入还是扬声器输出。让我感到不安的是,即使清除了ioData的缓冲区,我仍然可以在另一部手机上收听音频并播放另一部手机发送的音频。这有点告诉我,我既不接触麦克风输入也不接触扬声器输出。

我看到这一行有一些不同的参数:

AudioUnitSetProperty(rioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(renderCallback));

我想知道我是否有这些错误或其他什么。另外,是这一行:

err = AudioUnitRender(rioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, ioData);

受AudioUnitSetProperty的影响?在这种情况下,1设置了什么?

任何帮助都会很精彩。理想情况下,我希望能够将扬声器输出数据(可能是文件)以及麦克风输入进行采样。

2 个答案:

答案 0 :(得分:6)

远程IO音频单元是核心音频的一部分,可同时进行输入和输出。它是一个完整的单元,可以录制/播放硬件(麦克风/扬声器)和/或程序中的音频。 这有时会让人感到困惑。这样想吧。

**您在远程IO设备上有输入和输出 **您还可以使用远程IO设备上的软件和硬件。 硬件输入是Mic。 硬件输出是扬声器。 软件输入是您以编程方式创建的波形。 软件输出是已创建的波形。

-------输入------------

总线0:从应用程序读取(以编程方式构建音频波形)。在这里编写一个定期自动调用的回调。它说&#34;给我下一个音频样本。&#34;例如,您的代码可以为您提供以编程方式生成的三角波的音频样本 因此,您生成一个波形以输入程序。您也可以从其他音频单元的输出中提供此输入。

总线1:从麦克风读取。在这里,您可以从麦克风中读取音频样本。请注意,这些只是原始样本。您可以选择将它们保存到文件(例如录制应用程序),通过网络发送,甚至将它们连接到扬声器(见下文)。你不会听到麦克风发出的声音....它不会保存......除非你用它做点什么。

---------- ----------输出

公交车0:电话扬声器。在这里,您可以编写音频数据,它将在扬声器上播放。所以你得到另一个回调,说&#34;给我样本玩#34;然后用音频填充缓冲区并播放它。在当前缓冲区完成播放之前的某个时间周期性地发生回调。

总线1:写入您的应用。在这里,您可以获取远程IO生成的音频,并在您的应用中使用它做一些事情。例如,您可以将输出连接到另一个输出或将数据写入文件。

所以回答你的问题&#34;在这种情况下设置1做了什么?&#34;

这是Apple在AudioUnitRender上的规范

OSStatus AudioUnitRender ( AudioUnit inUnit, 
AudioUnitRenderActionFlags *ioActionFlags, 
const AudioTimeStamp *inTimeStamp,
UInt32 inOutputBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData );

1表示您正在读取输出上的总线1,即生成的音频帧。所以你可以在这里做任何你想做的事情,它不会影响演讲者播放的内容。

如果要检查麦克风数据,请在输入上使用总线1。如果要检查扬声器数据,请在输出上使用总线0。

请注意,您无法在回调中花费很长时间。不建议做任何可能花费大量时间的事情(例如写入网络,写入文件,打印)。在这种情况下,您可以使用GCD或类似的东西。

答案 1 :(得分:0)

RemoteIO音频单元不会更改任何其他音频API使用的音频输入或输出。它只将麦克风数据捕获到缓冲区中,或者从与其他音频API使用的缓冲区分开的缓冲区播放音频数据。