0

I wrote a command line c tool generating an sine wave and playing it using CoreAudio on the default audio output. I am initializing a AURenderCallbackStruct and initialize an AudioUnit using AudioUnitInitialize (as already discussed in this forum). All this is working as intended, but when it comes to closing the program I am not able to close the AudioUnit, neither with using AudioOutputUnitStop(player.outputUnit); nor AudioOutputUnitStop(player.outputUnit); nor AudioComponentInstanceDispose(player.outputUnit);

The order of appearance of these calls in the code does not change the behavior. The program is compiled without error messages, but the sine is still audible as long as the rest of the program is running.

Here is the code I'm using for initializing the AudioUnit:

void CreateAndConnectOutputUnit (ToneGenerator *player) {

    AudioComponentDescription outputcd = {0};
    outputcd.componentType = kAudioUnitType_Output;
    outputcd.componentSubType = kAudioUnitSubType_DefaultOutput;
    outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;

    AudioComponent comp = AudioComponentFindNext (NULL, &outputcd);
    if (comp == NULL) {
        printf ("can't get output unit");
        exit (-1);
    }

    AudioComponentInstanceNew(comp, &player->outputUnit);

    // register render callback
    AURenderCallbackStruct input;
    input.inputProc = SineWaveRenderCallback;
    input.inputProcRefCon = player;
    AudioUnitSetProperty(player->outputUnit,
                         kAudioUnitProperty_SetRenderCallback,
                         kAudioUnitScope_Output,
                         0,
                         &input,
                         sizeof(input);

    // initialize unit
    AudioUnitInitialize(player->outputUnit);
}

In my main program I'm starting the AudioUnit and the sine wave.

void main {
    // code for doing various things

    ToneGenerator player = {0};         // create a sound object
    CreateAndConnectOutputUnit (&player);
    AudioOutputUnitStart(player.outputUnit);

    // waiting to listen to the sine wave
    sleep(3);

    // attempt to stop the sound output
    AudioComponentInstanceDispose(player.outputUnit);
    AudioUnitUninitialize(player.outputUnit);
    AudioOutputUnitStop(player.outputUnit);

    //additional code that should be executed without sine wave being audible
}

As I'm new to both, this forum as well as programming in Xcode I hope that I could explain this issue in a way that you can help me out and I hope that I didn't miss the answer somewhere in the forum while searching for a solution.

Thank you in advance for your time and input,

Stefan

Stefan H
  • 1
  • 2
  • I would start with ensuring that things happen in the reverse order: InstanceNew;Initialize;Start --> Stop;Uninitialize;InstanceDispose, and checking the return values of all functions. (They return error codes for a reason, and that reason is not that they should be ignored.) – molbdnilo Jun 03 '16 at 14:56
  • Thank you very much for your answer molbdnilo. Changing the order seems logic but does not change the behavior. The functions are throwing Error -2147450879. I didn't find useful information on these errors. I'm using this function for catching the errors: [link](https://github.com/Xcode-Snippets/Objective-C/blob/master/checkerror.m). – Stefan H Jun 04 '16 at 08:57

2 Answers2

2

You should manage and unmanage your audio unit in a logical order. It doesn't make sense to stop playback on an already uninitialized audio unit, which had in fact previously been disposed of in the middle of the playback. Rather than that, try the following order:

AudioOutputUnitStop(player.outputUnit);           //first stops playback
AudioUnitUninitialize(player.outputUnit);         //then deallocates unit's resources
AudioComponentInstanceDispose(player.outputUnit); //finally disposes of the AU itself

The sine wave command line app you're after is a well elaborated lesson in this textbook. Please read it step by step.

Last, but not least, your question has nothing to do with C++, CoreAudio is a plain-C API, so C++ in both your title and tag are wrong and misleading.

user3078414
  • 1,942
  • 2
  • 16
  • 24
  • Thank you very much for your feedback. As described above, I did change the order of calling the functions, without change. My code is actually based on the linked textbook. If i run the original code, it seems to work, so that I expect the issue to appear in the additional code. I'll dig into this. I also corrected the link to c++. – Stefan H Jun 04 '16 at 09:08
  • Be prepared for a steep learning curve and maximum reading concentration. This API is _very_ verbous. What seems to me is that you are trying to devise means of controlling the unit's lifetime, more meaningful than `sleep(3)`. It is important that you *don't* "disconnect" the rest of your program from your AU while it is still playing. – user3078414 Jun 04 '16 at 09:16
0

An Audio Unit runs in an asynchronous thread that may not actually stop immediately when you call AudioOutputUnitStop. Thus, it may work better to wait a fraction of a second (at least a couple audio callback buffer durations in time) before calling AudioUnitUninitialize and AudioComponentInstanceDispose on a potentially still running audio unit.

Also, check to make sure your player.outputUnit value is a valid unit (and not an uninitialized or trashed variable) at the time you stop the unit.

hotpaw2
  • 70,107
  • 14
  • 90
  • 153