I’ve been trying without success to use Apple’s VPIO unit in an AUGraph.
I’ve set up a little test application. It always instantiates its audio units by creating an AUGraph. That much works. I can use either the AUGraph API calls or the AudioUnit calls after that.
When I use the VPIO by itself, and use the AudioUnit API calls, I can set its input and render callbacks with the following code:
OSStatus err;
AURenderCallbackStruct rcb;
rcb.inputProc = inputCallback;
rcb.inputProcRefCon = (__bridge void*) self;
err = AudioUnitSetProperty(vpioUnit, kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global, ELEMENT_MIKE_1, &rcb, sizeof(rcb));
// check err
rcb.inputProc = renderCallback;
rcb.inputProcRefCon = (__bridge void*) self;
err = AudioUnitSetProperty(vpioUnit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global, ELEMENT_SPKR_0, &rcb, sizeof(rcb));
// check err
When I start the unit, my callbacks get called and my test application works.
When I use the VPIO unit by itself, the AUGraphSetNodeInputCallback() call appears to do nothing. Here’s the relevant code (all else the same as above):
AURenderCallbackStruct callback;
callback.inputProc = inputCallback;
callback.inputProcRefCon = (__bridge void*) self;
err = AUGraphSetNodeInputCallback(mGraph, vpioNode, ELEMENT_MIKE_1, &callback);
// check err
callback.inputProc = renderCallback;
callback.inputProcRefCon = (__bridge void*) self;
err = AudioUnitSetProperty(vpioUnit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global, ELEMENT_SPKR_0, &callback, sizeof(callback));
// check err
…
err = AUGraphInitialize(mGraph);
// check err
err = AUGraphStart(mGraph);
// check err
My render callback is called, but my input callback is not.
I checked by reading back the kAudioUnitProperty_SetRenderCallback property and the AURenderCallbackStruct comes back with a pair of NULL pointers.
I tried putting a second audio unit (a converter) in the graph to provide data to the VPIO unit for output. Here’s the relevant snippet:
err = AUGraphConnectNodeInput(mGraph, cvtNode, 0, vpioNode, ELEMENT_SPKR_0);
// check err
AURenderCallbackStruct callback;
callback.inputProc = inputCallback;
callback.inputProcRefCon = (__bridge void*) self;
err = AUGraphSetNodeInputCallback(mGraph, vpioNode, ELEMENT_MIKE_1, &callback);
// check err
callback.inputProc = renderCallback;
callback.inputProcRefCon = (__bridge void*) self;
err = AudioUnitSetProperty(cvtUnit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global, 0, &callback, sizeof(callback));
// check err
When I start the graph, neither my input nor my render callback is called. I tried to check the setup by reading back the kAudioOutputUnitProperty_SetInputCallback and kAudioUnitProperty_MakeConnection properties, but apparently those
are write-only.
In desperation, I tried connecting the other unit to the VPIO unit by setting the MakeConnection property myself.
AudioUnitConnection conn;
conn.sourceAudioUnit = cvtUnit;
conn.sourceOutputNumber = 0;
conn.destInputNumber = ELEMENT_SPKR_0;
err = AudioUnitSetProperty(vpioUnit, kAudioUnitProperty_MakeConnection,
kAudioUnitScope_Global, ELEMENT_SPKR_0, &conn, sizeof(conn));
// check err
AURenderCallbackStruct rcb;
rcb.inputProc = inputCallback;
rcb.inputProcRefCon = (__bridge void*) self;
err = AudioUnitSetProperty(mIoUnit, kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global, ELEMENT_MIKE_1, &rcb, sizeof(rcb));
// check err
rcb.inputProc = renderCallback;
rcb.inputProcRefCon = (__bridge void*) self;
err = AudioUnitSetProperty(mCvtUnit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global, 0, &rcb, sizeof(rcb));
// check err
When I start the VPIO unit, my input callback is called, but my render callback is not.
I’m ready to conclude that the VPIO unit is “special” – that it does not work with the AUGraph API calls and it does not connect (via kAudioUnitProperty_MakeConnection) to other units.
Can anyone see something boneheaded that I might be doing wrong, or might there be another consideration I’m not taking into account?
I am in awe of the incredible work Apple has done with Core Audio, but I’m equally amazed that they saw fit to throw so much of its value away through insufficient documentation.
Steven J. Clark
VGo Communications