3 Stimmen

iOS - AudioUnitRender gibt Fehler -10876 auf dem Gerät zurück, läuft aber im Simulator einwandfrei

Ich bin auf ein Problem gestoßen, das es mir unmöglich machte, das Eingangssignal vom Mikrofon des Geräts (iPhone4) zu erfassen. Im Simulator läuft der Code jedoch einwandfrei. Der Code wurde ursprünglich von Apples MixerHostAudio-Klasse aus MixerHost Beispielcode übernommen. es läuft gut sowohl auf Gerät und im Simulator, bevor ich begann, Code für die Erfassung von Mikrofon-Eingang hinzufügen. Ich frage mich, ob mir jemand helfen könnte. Vielen Dank im Voraus!

Hier ist meine inputRenderCallback-Funktion, die das Signal in den Mischereingang einspeist:

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
    // ....
}

Hier ist mein zugehöriger Initialisierungscode: Jetzt habe ich nur 1 Eingang im Mixer, so dass der Mixer scheint redundant, aber funktioniert gut, bevor Sie Input Capture Code.

// 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
                  );

1voto

Nik Reiman Punkte 37385

Zunächst ist zu beachten, dass der Fehlercode -10876 dem Symbol mit dem Namen kAudioUnitErr_NoConnection . Sie können diese in der Regel finden, indem Sie die Fehlercode-Nummer zusammen mit dem Begriff CoreAudio googeln. Das sollte ein Hinweis darauf sein, dass Sie das System auffordern, an eine AudioUnit zu rendern, die nicht richtig angeschlossen ist.

Innerhalb Ihres Render-Callbacks werfen Sie die void* Benutzerdaten an eine recorderStructPtr . Ich gehe davon aus, dass Sie beim Debuggen dieses Codes eine Nicht-Null-Struktur zurückgegeben haben, in der die Adresse Ihrer tatsächlichen Audioeinheit enthalten ist. Sie sollten es jedoch mit der AudioBufferList die an Ihren Render-Callback übergeben wird (d.h. die inputRenderCallback Funktion). Diese enthält die Liste der Proben aus dem System, die Sie verarbeiten müssen.

1voto

brian_wang Punkte 113

Ich habe das Problem selbst gelöst. Es ist auf einen Fehler in meinem Code zurückzuführen, der den Fehler 10876 bei AudioUnitRender() .

Ich habe die Kategorie meiner AudioSession als AVAudioSessionCategoryPlayback anstelle von AVAudioSessionCategoryPlayAndRecord . Als ich die Kategorie auf AVAudioSessionCategoryPlayAndRecord kann ich endlich den Mikrofoneingang erfolgreich erfassen, indem ich A* aufrufe udioUnitRender() * auf dem Gerät.

Die Verwendung von AVAudioSessionCategoryPlayback führt nicht zu einem Fehler beim Aufruf von AudioUnitRender() um den Mikrofoneingang zu erfassen, und es funktioniert gut im Simulator. Ich denke, dies sollte ein Thema für den iOS-Simulator (wenn auch nicht kritisch).

0voto

Greg Punkte 9754

Ich habe auch gesehen, dass dieses Problem auftritt, wenn die Werte in der Streamformat-Eigenschaft der E/A-Einheit inkonsistent sind. Stellen Sie sicher, dass Ihre AudioStreamBasicDescription Die Angaben Bits pro Kanal, Kanäle pro Frame, Bytes pro Frame, Frames pro Paket und Bytes pro Paket sind alle sinnvoll.

Der NoConnection-Fehler trat auf, als ich ein Stream-Format von Stereo auf Mono änderte, indem ich die Kanäle pro Frame änderte, aber vergaß, die Bytes pro Frame und die Bytes pro Paket zu ändern, um der Tatsache Rechnung zu tragen, dass ein Mono-Frame halb so viele Daten enthält wie ein Stereo-Frame.

0voto

Eric Punkte 14375

Wenn Sie eine AudioUnit und setzen Sie nicht seine kAudioUnitProperty_SetRenderCallback Eigenschaft, erhalten Sie diesen Fehler, wenn Sie die AudioUnitRender darauf.

Rufen Sie an. AudioUnitProcess stattdessen auf sie.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X