【问题标题】:iOS - AudioUnitRender returned error -10876 on device, but running fine in simulatoriOS - AudioUnitRender 在设备上返回错误 -10876,但在模拟器中运行良好
【发布时间】:2011-03-31 15:16:32
【问题描述】:

我遇到了一个问题,导致我无法从设备 (iPhone4) 上的麦克风捕获输入信号。但是,代码在模拟器中运行良好。 该代码最初是从 MixerHost 示例代码中的 Apple 的 MixerHostAudio 类中采用的。在我开始添加用于捕获麦克风输入的代码之前,它在设备和模拟器中运行良好。 想知道是否有人可以帮助我。提前致谢!

这是我的 inputRenderCallback 函数,它将信号输入到混音器输入:

static OSStatus inputRenderCallback (

void                        *inRefCon,
AudioUnitRenderActionFlags  *ioActionFlags,
const AudioTimeStamp        *inTimeStamp, 
UInt32                      inBusNumber,
UInt32                      inNumberFrames,
AudioBufferList             *ioData) {
recorderStructPtr recorderStructPointer     = (recorderStructPtr) inRefCon;
    // ....
        AudioUnitRenderActionFlags renderActionFlags;
        err = AudioUnitRender(recorderStructPointer->iOUnit, 
                              &renderActionFlags, 
                              inTimeStamp, 
                              1, // bus number for input
                              inNumberFrames, 
                              recorderStructPointer->fInputAudioBuffer
                              );
                    // error returned is -10876
    // ....
}

这是我相关的初始化代码: 现在我在混音器中只保留 1 个输入,所以混音器看起来是多余的,但在添加输入捕获代码之前工作正常。

// Convenience function to allocate our audio buffers
- (AudioBufferList *) allocateAudioBufferListByNumChannels:(UInt32)numChannels withSize:(UInt32)size {
    AudioBufferList*            list;
    UInt32                      i;

    list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer));
    if(list == NULL)
        return nil;

    list->mNumberBuffers = numChannels;
    for(i = 0; i < numChannels; ++i) {
        list->mBuffers[i].mNumberChannels = 1;
        list->mBuffers[i].mDataByteSize = size;
        list->mBuffers[i].mData = malloc(size);
        if(list->mBuffers[i].mData == NULL) {
            [self destroyAudioBufferList:list];
            return nil;
        }
    }
    return list;
}

// initialize audio buffer list for input capture
recorderStructInstance.fInputAudioBuffer = [self allocateAudioBufferListByNumChannels:1 withSize:4096];

// I/O unit description
AudioComponentDescription iOUnitDescription;
iOUnitDescription.componentType          = kAudioUnitType_Output;
iOUnitDescription.componentSubType       = kAudioUnitSubType_RemoteIO;
iOUnitDescription.componentManufacturer  = kAudioUnitManufacturer_Apple;
iOUnitDescription.componentFlags         = 0;
iOUnitDescription.componentFlagsMask     = 0;

// Multichannel mixer unit description
AudioComponentDescription MixerUnitDescription;
MixerUnitDescription.componentType          = kAudioUnitType_Mixer;
MixerUnitDescription.componentSubType       = kAudioUnitSubType_MultiChannelMixer;
MixerUnitDescription.componentManufacturer  = kAudioUnitManufacturer_Apple;
MixerUnitDescription.componentFlags         = 0;
MixerUnitDescription.componentFlagsMask     = 0;

AUNode   iONode;         // node for I/O unit
AUNode   mixerNode;      // node for Multichannel Mixer unit

// Add the nodes to the audio processing graph
result =    AUGraphAddNode (
                processingGraph,
                &iOUnitDescription,
                &iONode);

result =    AUGraphAddNode (
                processingGraph,
                &MixerUnitDescription,
                &mixerNode
            );

result = AUGraphOpen (processingGraph);

// fetch mixer AudioUnit instance
result =    AUGraphNodeInfo (
                processingGraph,
                mixerNode,
                NULL,
                &mixerUnit
            );

// fetch RemoteIO AudioUnit instance
result =    AUGraphNodeInfo (
                             processingGraph,
                             iONode,
                             NULL,
                             &(recorderStructInstance.iOUnit)
                             );


    // enable input of RemoteIO unit
UInt32 enableInput = 1;
AudioUnitElement inputBus = 1;
result = AudioUnitSetProperty(recorderStructInstance.iOUnit, 
                              kAudioOutputUnitProperty_EnableIO, 
                              kAudioUnitScope_Input, 
                              inputBus, 
                              &enableInput, 
                              sizeof(enableInput)
                              );
// setup mixer inputs
UInt32 busCount   = 1;

result = AudioUnitSetProperty (
             mixerUnit,
             kAudioUnitProperty_ElementCount,
             kAudioUnitScope_Input,
             0,
             &busCount,
             sizeof (busCount)
         );


UInt32 maximumFramesPerSlice = 4096;

result = AudioUnitSetProperty (
             mixerUnit,
             kAudioUnitProperty_MaximumFramesPerSlice,
             kAudioUnitScope_Global,
             0,
             &maximumFramesPerSlice,
             sizeof (maximumFramesPerSlice)
         );


for (UInt16 busNumber = 0; busNumber < busCount; ++busNumber) {

    // set up input callback
    AURenderCallbackStruct inputCallbackStruct;
    inputCallbackStruct.inputProc        = &inputRenderCallback;
inputCallbackStruct.inputProcRefCon  = &recorderStructInstance;

    result = AUGraphSetNodeInputCallback (
                 processingGraph,
                 mixerNode,
                 busNumber,
                 &inputCallbackStruct
             );

            // set up stream format
    AudioStreamBasicDescription mixerBusStreamFormat;
    size_t bytesPerSample = sizeof (AudioUnitSampleType);

    mixerBusStreamFormat.mFormatID          = kAudioFormatLinearPCM;
    mixerBusStreamFormat.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
    mixerBusStreamFormat.mBytesPerPacket    = bytesPerSample;
    mixerBusStreamFormat.mFramesPerPacket   = 1;
    mixerBusStreamFormat.mBytesPerFrame     = bytesPerSample;
    mixerBusStreamFormat.mChannelsPerFrame  = 2;
    mixerBusStreamFormat.mBitsPerChannel    = 8 * bytesPerSample;
    mixerBusStreamFormat.mSampleRate        = graphSampleRate;

    result = AudioUnitSetProperty (
                                   mixerUnit,
                                   kAudioUnitProperty_StreamFormat,
                                   kAudioUnitScope_Input,
                                   busNumber,
                                   &mixerBusStreamFormat,
                                   sizeof (mixerBusStreamFormat)
                                   );


}

// set sample rate of mixer output
result = AudioUnitSetProperty (
             mixerUnit,
             kAudioUnitProperty_SampleRate,
             kAudioUnitScope_Output,
             0,
             &graphSampleRate,
             sizeof (graphSampleRate)
         );


// connect mixer output to RemoteIO
result = AUGraphConnectNodeInput (
             processingGraph,
             mixerNode,         // source node
             0,                 // source node output bus number
             iONode,            // destination node
             0                  // desintation node input bus number
         );


// initialize AudioGraph
result = AUGraphInitialize (processingGraph);

// start AudioGraph
result = AUGraphStart (processingGraph);

// enable mixer input
result = AudioUnitSetParameter (
                     mixerUnit,
                     kMultiChannelMixerParam_Enable,
                     kAudioUnitScope_Input,
                     0, // bus number
                     1, // on
                     0
                  );

【问题讨论】:

    标签: iphone audiounit


    【解决方案1】:

    首先需要注意的是,错误码-10876对应的是名为kAudioUnitErr_NoConnection的符号。您通常可以通过谷歌搜索错误代码编号以及术语 CoreAudio 来找到这些。这应该是您要求系统渲染到未正确连接的 AudioUnit 的提示。

    在您的渲染回调中,您将void* 用户数据转换为recorderStructPtr。我将假设当您调试此代码时,此转换返回一个非空结构,其中包含您的实际音频单元的地址。但是,您应该使用传递给您的渲染回调(即inputRenderCallback 函数)的AudioBufferList 来渲染它。其中包含系统中您需要处理的样本列表。

    【讨论】:

    • 您好 Nik,感谢您的提示。我认为 AudioUnitRender() 从硬件中获取样本,因此传递给 AudioUnitRender() 的 ABL 不必是传递给回调的 ABL?无论如何我都试过了,它仍然报告-10876错误。关于这个 NoConnection 错误,我已经用谷歌搜索过了,只有 2 封邮件/帖子讨论了这个错误。 (我在这里的帖子使搜索结果翻了一番)。我认为它在模拟器和设备中的行为不同已经是一种奇怪的行为。
    • 顺便说一句,我认为 recorderStructPtr 应该是正确的,因为我使用调试器验证了指针地址。
    【解决方案2】:

    我自己解决了这个问题。这是由于我的代码中的一个错误导致 AudioUnitRender() 上出现 10876 错误。

    我将 AudioSession 的类别设置为 AVAudioSessionCategoryPlayback 而不是 AVAudioSessionCategoryPlayAndRecord。当我将类别固定为 AVAudioSessionCategoryPlayAndRecord 后,我终于可以在设备上调用 A*udioUnitRender()* 成功捕获麦克风输入了。

    在调用 AudioUnitRender() 捕获麦克风输入时,使用 AVAudioSessionCategoryPlayback 不会导致任何错误,并且在模拟器中运行良好。我认为这应该是一个问题 iOS 模拟器(虽然不是很重要)。

    【讨论】:

      【解决方案3】:

      当 I/O 单元的流格式属性中的值不一致时,我也看到了这个问题。确保 AudioStreamBasicDescription 的每通道位数、每帧通道数、每帧字节数、每包帧数和每包字节数都有意义。

      具体来说,当我通过更改每帧的通道将流格式从立体声更改为单声道时出现 NoConnection 错误,但忘记更改每帧的字节数和每个数据包的字节数以匹配其中数据量减半的事实单声道帧作为立体帧。

      【讨论】:

        【解决方案4】:

        如果你初始化一个AudioUnit 并且没有设置它的kAudioUnitProperty_SetRenderCallback 属性,如果你在它上面调用AudioUnitRender 你会得到这个错误。

        请致电AudioUnitProcess

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-28
          • 2018-07-13
          相关资源
          最近更新 更多