iosaudiocore-audioaudiounitremoteio

Publishing iOS Audio Unit


I'm trying to make an inter-app audio iOS app and it looks like I'm having trouble the AudioOutputUnitPublish method. Here's the method:

- (void)publishOutputAudioUnit {
    AudioComponentDescription desc = {kAudioUnitType_RemoteInstrument, 
                                     'iasp','rfoo', 0, 1};
    OSStatus result = AudioOutputUnitPublish(&desc, CFSTR("MyMusicApp"), 
                                             1, outputUnit);
    if (result != noErr) 
        NSLog(@"AudioOutputUnitPublish instrument result: %d", (int)result);

    desc = { kAudioUnitType_RemoteGenerator, 'iasp', 'rfoo', 0, 1 };
    result = AudioOutputUnitPublish(&desc, CFSTR("MyMusicApp"), 1, outputUnit);
    if (result != noErr) 
        NSLog(@"AudioOutputUnitPublish generator result: %d", (int)result);
}

Here is my plist info:

<key>AudioComponents</key>
<array>
    <dict>
        <key>manufacturer</key>
        <string>rfoo</string>
        <key>name</key>
        <string>MyMusicApp</string>
        <key>subtype</key>
        <string>iasp</string>
        <key>type</key>
        <string>aurg</string>
        <key>version</key>
        <integer>1</integer>
    </dict>
    <dict>
        <key>manufacturer</key>
        <string>rfoo</string>
        <key>name</key>
        <string>MyMusicApp</string>
        <key>subtype</key>
        <string>iasp</string>
        <key>type</key>
        <string>auri</string>
        <key>version</key>
        <integer>1</integer>
    </dict>
</array>

This is the result I'm getting:

AudioOutputUnitPublish instrument result: -50
AudioOutputUnitPublish generator result: -50

I know OSStatus code -50 means there's an invalid parameter... but I can't seem to figure out which one is invalid. Can anyone help me debug here? Thanks!


EDIT :

Just wanted to post more code so others could help me out more:

I have two audio units and hopefully a third one - MIDISynth (inactive as of now), MultiChannelMixer, and RemoteIO audio unit. I have a render callback attached to the mixer audio unit. I'm guessing I'm connecting something wrong in my AUGraph (none of the examples I've seen have attached an audio rendering callback to the audio unit so this might be where I'm doing something wrong). Hopefully someone can spot out what I'm doing wrong!

Here's the code:

- (AUGraph)createAUGraphWithSynth:(AudioUnit *)sUnit mixUnit:(AudioUnit *)mixUnit remoteUnit:(AudioUnit *)remUnit {
    // Initializations
    AUGraph graph = 0;
    OSStatus result = noErr;
    // Create graph nodes
    AUNode mixerNode, ioNode;

    // Create Component Descriptor
    AudioComponentDescription cd;
    cd.componentManufacturer    = kAudioUnitManufacturer_Apple;
    cd.componentFlags           = 0;
    cd.componentFlagsMask       = 0;

    // Init AUGraph
    Check(result = NewAUGraph(&graph));

    // Init Mixer unit
    cd.componentType    = kAudioUnitType_Mixer;
    cd.componentSubType = kAudioUnitSubType_MultiChannelMixer;
    Check(result = AUGraphAddNode(graph, &cd, &mixerNode));

    // Init io Unit
    cd.componentType    = kAudioUnitType_Output;
    cd.componentSubType = kAudioUnitSubType_RemoteIO;
    Check(result = AUGraphAddNode(graph, &cd, &ioNode));

    // Open AUGraph
    Check(AUGraphOpen(graph));

    // Get mixer unit
    Check(AUGraphNodeInfo(graph, mixerNode, NULL, mixUnit));

    // Get io unit
    Check(AUGraphNodeInfo(graph, ioNode, NULL, remUnit));

    // Set number of input busses
    UInt32 numBuses = 1;
    UInt32 size = sizeof(numBuses);
    Check(AudioUnitSetProperty(*mixUnit,
                               kAudioUnitProperty_ElementCount,
                               kAudioUnitScope_Input,
                               0, &numBuses, size));

    AudioStreamBasicDescription desc;
    const int four_bytes_per_float = 4;
    const int eight_bits_per_byte = 8;

    for (int i = 0; i < numBuses; ++i) {
        AURenderCallbackStruct callbackStruct;
        callbackStruct.inputProc        = outputCallback;
        callbackStruct.inputProcRefCon  = (__bridge void *)self;
    
        Check(AUGraphSetNodeInputCallback(graph, mixerNode, i, &callbackStruct));

        UInt32 size = sizeof(desc);
        Check(AudioUnitGetProperty(*mixUnit,
                                   kAudioUnitProperty_StreamFormat,
                                   kAudioUnitScope_Input,
                                   0, &desc, &size));
    
        memset(&desc, 0, sizeof(desc));
    

        desc.mSampleRate        = SAMPLE_RATE;
        desc.mFormatID          = kAudioFormatLinearPCM;
        desc.mFormatFlags       = kAudioFormatFlagsNativeFloatPacked 
                                | kAudioFormatFlagIsNonInterleaved;
        desc.mBytesPerPacket    = four_bytes_per_float;
        desc.mFramesPerPacket   = 1;
        desc.mBytesPerFrame     = four_bytes_per_float;
        desc.mBitsPerChannel    = four_bytes_per_float * eight_bits_per_byte;
        desc.mChannelsPerFrame  = 2;
        Check(AudioUnitSetProperty(*remUnit,
                                   kAudioUnitProperty_StreamFormat,
                                   kAudioUnitScope_Input,
                                   0, &desc, sizeof(desc)));

    }

    Check(AudioUnitSetProperty(*mixUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0, &desc, sizeof(desc)));

    Check(AudioUnitGetProperty(*mixUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0, &desc, &size));

    memset(&desc, 0, sizeof(desc));

    desc.mSampleRate        = SAMPLE_RATE;
    desc.mFormatID          = kAudioFormatLinearPCM;
    desc.mFormatFlags       = kAudioFormatFlagsNativeFloatPacked 
                            | kAudioFormatFlagIsNonInterleaved;
    desc.mBytesPerPacket    = four_bytes_per_float;
    desc.mFramesPerPacket   = 1;
    desc.mBytesPerFrame     = four_bytes_per_float;
    desc.mBitsPerChannel    = four_bytes_per_float * eight_bits_per_byte;
    desc.mChannelsPerFrame  = 2;
     
    Check(AudioUnitSetProperty(*mixUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               0, &desc, sizeof(desc)));

    // Must configure remote io unit:
    Check(AudioUnitSetProperty(*remUnit,
                               kAudioUnitProperty_StreamFormat,
                               kAudioUnitScope_Output,
                               1, &desc, sizeof(desc)));

     // Connect nodes (synth->output)
     Check(AUGraphConnectNodeInput(graph, mixerNode, 0, ioNode, 0));

     return graph;
 }

Solution

  • The last field in the AudioComponentDescription, componentFlagsMask, should be 0, not 1. (See the documentation. It looks like at least one tutorial misidentifies this field as the component version.)

    Whether this is the sole cause of the problem I'm not sure. The rest of the code looks OK, but I guess it's possible there may be issues elsewhere in the project, eg. with the capabilities.