【问题标题】:Getting mic input and speaker output using Core Audio使用 Core Audio 获取麦克风输入和扬声器输出
【发布时间】:2015-11-05 12:41:09
【问题描述】:

所以我最近稍微研究了一下核心数据,但我还是个新手。我很难理解我正在使用哪些数据以及它如何影响整个数据流。因此,对于某些背景,我有一个使用 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 有什么作用?

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

【问题讨论】:

  • 也许您指的是 Core Audio 或 Core Media 而不是 Core Data?
  • 已修复并将其更改为核心音频

标签: ios objective-c core-audio


【解决方案1】:

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

** 您在远程 IO 单元上有输入和输出。
** 您还可以在远程 IO 单元上安装软件和硬件。 硬件输入是麦克风。 硬件输出是扬声器。 软件输入是您以编程方式创建的波形。 软件输出是已创建的波形。

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

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

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

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

总线 0:电话扬声器。在这里您可以写入音频数据,它将在扬声器上播放。所以你得到另一个回调,上面写着“给我播放样本”,你用音频填充缓冲区并播放它。在当前缓冲区播放完毕之前的某个时间,回调会定期发生。

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

所以回答你的问题“在这种情况下设置 1 有什么作用?”

这是来自苹果的 AudioUnitRender 规范

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

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-25
      • 2022-09-26
      • 2014-10-31
      • 2017-05-20
      • 1970-01-01
      相关资源
      最近更新 更多