0

I have a multichannel mixer and a remote I/O in a graph, setup to play uncompressed caf files. So far so good.

Next, I am experimenting with doing weird stuff on the render callback (say, generate white noise, or play a sine wave, etc. - procedurally generated sounds).

Instead of adding conditionals to the existing render callback (which is assigned on setup to all the buses of the mixer), I would like to be able to switch the render callback attached to each bus, at runtime.

So far I'm trying this code, but it doesn't work: My alternative render callback does not get called.

- (void) playNoise
{
    if (_noiseBus != -1) {
        // Already playing
        return;
    }

    _noiseBus = [self firstFreeMixerBus];

    AUGraphDisconnectNodeInput(processingGraph,
                               mixerNode,
                               _noiseBus);

    inputCallbackStructArray[_noiseBus].inputProc       = &noiseRenderCallback;
    inputCallbackStructArray[_noiseBus].inputProcRefCon = NULL;

    OSStatus result = AUGraphSetNodeInputCallback(processingGraph,
                                                  mixerNode,
                                                  _noiseBus,
                                                  &inputCallbackStructArray[_noiseBus]);

    if (result != noErr) {
        return NSLog@"AUGraphSetNodeInputCallback");
    }


    result = AudioUnitSetParameter(_mixerUnit,
                                   kMultiChannelMixerParam_Enable,
                                   kAudioUnitScope_Input,
                                   _noiseBus,
                                   1,
                                   0);

    if (result != noErr) {
        return NSLog(@"Failed to enable bus");
    }


    result = AudioUnitSetParameter (_mixerUnit,
                                    kMultiChannelMixerParam_Volume,
                                    kAudioUnitScope_Input,
                                    _noiseBus,
                                    0.5,
                                    0);

    if (result != noErr) {
        return NSLog(@"AudioUnitSetParameter (set mixer unit input volume) Failed");
    }

    unsigned char updated;
    AUGraphUpdate(processingGraph, &(updated));
    // updated ends un being zero ('\0')
}

In the code above, none of the error conditions are met (no function call fails), but the boolean 'updated' remains false until the end.

Am I missing a step, or is it not possible to switch render callbacks after setup? Do I need to set aside dedicated buses to these alternative callbacks? I would like to be able to set custom callbacks from the client code (the side calling my sound engine)...

EDIT Actually it is working, but only after the second time: I must call -playNoise, then -stopNoise, and from then on it will play normally. I couldn't tell, because I was giving up at the first try...

BTW, The updated flag is still 0. I added lots of audio unit calls out of desperation, but perhaps some are not necessary. I'll see which ones I can trim, then keep looking for the reason it needs two calls to work...

EDIT 2: After poking around, adding/removing calls and fixing bugs, I got to the point where the noise render callback works from the first time, but after playing the noise at least once, if I attempt to reuse that bus form playing PCM (caf file), it still uses the noise render callback (despite having disconnected it). I'm going with the solution suggested by @hotpaw2 in the comments and using a 'stub' callback and further function pointers...

Nicolas Miari
  • 16,006
  • 8
  • 81
  • 189
  • 1
    An alternative that works is to have a single fixed render callback that redirects via a function pointer to a configurable render callback. Cost is only an additional stack frame, and it won't be broken by any Audio Unit bugs or OS changes. – hotpaw2 Apr 10 '14 at 21:32
  • Thanks, I'll do just that. I'll set a global array of function pointers (one for each bus), and chose the appropriate one/call it inside the (otherwise empty) render callback. – Nicolas Miari Apr 11 '14 at 02:22

0 Answers0