繁体   English   中英

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

[英]Getting mic input and speaker output using 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有什么作用?

任何帮助他都会很棒。 理想情况下,我希望能够对扬声器的输出数据(也许成文件)以及麦克风输入进行采样。

Remote IO音频单元是核心音频的一部分,既可以输入也可以输出。 它是一个完整的单元,可以录制/播放硬件(麦克风/扬声器)和/或程序中的音频。 有时这使它变得混乱。 这样想吧。

**您在远程IO单元上具有输入和输出。
**您也是远程IO单元上的软件和硬件。 硬件输入是麦克风。 硬件输出是扬声器。 软件输入是您通过编程创建的波形。 软件输出是已创建的波形。

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

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

总线1:从麦克风读取。 在这里,您可以从麦克风读取音频样本。 请注意,这些只是原始样本。 您可以选择将它们保存到文件(例如,录音应用程序),通过网络发送它们,甚至将它们连接到扬声器(请参见下文)。 您不会听到来自麦克风的音频...。它将无法保存...。除非您对此进行了某些操作。

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

总线0:电话扬声器。 您可以在此处写入音频数据,并将其在扬声器上播放。 因此,您会收到另一个回调,说“请给我播放样本”,然后用音频填充缓冲区并播放它。 回调在当前缓冲区完成播放之前的某个时间定期发生。

总线1:写入您的应用。 在这里,您可以获取由远程IO生成的音频,并在您的应用程序中对其进行处理。 例如,您可以将输出连接到另一个输出或将数据写入文件。

因此,回答您的问题“在这种情况下设置1会做什么?”

这是Apple在AudioUnitRender上的规格

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

1表示您正在读取输出的总线1,该输出是生成的音频帧。 因此,您可以在这里做任何您想做的事,并且不会影响扬声器播放的内容。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM