Search code examples
iosobjective-ciphonecore-audioaudiounit

How to play a signal with AudioUnit (iOS)?


I need to generate a signal and play it with iPhone's speakers or a headset.

To do so I generate an interleaved signal. Then i need to instantiate an AudioUnit inherited class object with the next info: 2 channels, 44100 kHz sample rate, some buffer size to store a few frames.

Then I need to write a callback method which will take a chink of my signal and pit it into iPhone's output buffer.

The problem is that I have no idea how to write an AudioUnit inherited class. I can't understand Apple's documentation regarding it, and all the examples I could find either read from file and play it with huge lag or use depricated constructions.

I start to think I am stupid or something. Please, help...


Solution

  • To play audio to the iPhone's hardware with an AudioUnit, you don't derive from the AudioUnit as CoreAudio is a c framework - instead you give it a render callback in which you feed the unit your audio samples. The following code sample shows you how. You need to replace the asserts with real error handling and you'll probably want to change or at least inspect the audio unit's sample format using the kAudioUnitProperty_StreamFormat selector. My format happens to be 48kHz floating point interleaved stereo.

    static OSStatus
    renderCallback(
                   void* inRefCon,
                   AudioUnitRenderActionFlags* ioActionFlags,
                   const AudioTimeStamp* inTimeStamp,
                   UInt32 inBusNumber,
                   UInt32 inNumberFrames,
                   AudioBufferList* ioData)
    {
        // inRefCon contains your cookie
    
        // write inNumberFrames to ioData->mBuffers[i].mData here
    
        return noErr;
    }
    
    AudioUnit
    createAudioUnit() {
        AudioUnit   au;
        OSStatus err;
    
        AudioComponentDescription desc;
        desc.componentType = kAudioUnitType_Output;
        desc.componentSubType = kAudioUnitSubType_RemoteIO;
        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
        desc.componentFlags = 0;
        desc.componentFlagsMask = 0;
    
        AudioComponent comp = AudioComponentFindNext(NULL, &desc);
        assert(0 != comp);
    
        err = AudioComponentInstanceNew(comp, &au);
        assert(0 == err);
    
    
        AURenderCallbackStruct input;
        input.inputProc = renderCallback;
        input.inputProcRefCon = 0;  // put your cookie here
    
        err = AudioUnitSetProperty(au, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(input));
        assert(0 == err);
    
        err = AudioUnitInitialize(au);
        assert(0 == err);
    
        err = AudioOutputUnitStart(au);
        assert(0 == err);
    
        return au;
    }