AudioUnit problem: CFRunLoopRunInMode() spins after first thread exits, and second thread begins?
AudioUnit problem: CFRunLoopRunInMode() spins after first thread exits, and second thread begins?
- Subject: AudioUnit problem: CFRunLoopRunInMode() spins after first thread exits, and second thread begins?
- From: Jeremy Friesner <email@hidden>
- Date: Wed, 15 Oct 2008 13:00:59 -0700
Hi all,
I have a curious problem with my audio playback code. What my program
does is spawn a thread that uses AudioUnit to play back a generated
stream of audio. In general, this works fine. The problem occurs
when (for reasons I won't go into here) my program needs to shut down
the thread, and then later spawn another one that is identical to it.
The second time, the thread doesn't work correctly... in particular,
CFRunLoopRunInMode() immediately returns 1 (aka kCFRunLoopRunFinished)
instead of waiting the expected one second and then returning
kCFRunLoopTimedOut. This causes one of my Mac's CPU cores to become
pegged at 100%, which I want to avoid.
Can anyone hazard a guess as to why this is happening? I do a
"gentle" shutdown of the first thread (my main thread sets the
_keepGoing flag to false, and then waits for the audio thread to clean
up after itself and exit), so I'd expect it to work okay...
Code sample is below.
Thanks,
Jeremy Friesner
--------------
static OSStatus RenderAudioFunc(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
return ((CoreAudioDataIO *)inRefCon)->RenderAudio(ioActionFlags,
inTimeStamp, inBusNumber, inNumberFrames, ioData);
}
OSStatus
CoreAudioDataIO :: RenderAudio(AudioUnitRenderActionFlags * /
*ioActionFlags*/,
const AudioTimeStamp * /*inTimeStamp*/,
UInt32 /*inBusNumber*/,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
[... code to write audio samples to ioData->mBuffers[0].mData
omitted ...]
return _keepGoing ? noErr : -1;
}
// Audio thread is started here
void CoreAudioDataIO :: MyAudioThreadEntryFunc()
{
// Open the default output unit
ComponentDescription desc; memset(&desc, 0, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
Component comp = FindNextComponent(NULL, &desc);
if (comp == NULL) {printf ("FindNextComponent failed!\n");
exit(10);}
AudioUnit outputUnit;
OSStatus err = OpenAComponent(comp, &outputUnit);
if (comp == NULL) {printf ("OpenAComponent=%ld failed!\n", err);
exit(10);}
// Set up a callback function to generate output to the output unit
AURenderCallbackStruct input; memset(&input, 0, sizeof(input));
input.inputProc = RenderAudioFunc;
input.inputProcRefCon = this;
err = AudioUnitSetProperty (outputUnit,
kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0,
&input, sizeof(input));
if (err) {printf ("AudioUnitSetProperty-CB=%ld\n", err); exit(10);}
// We tell the Output Unit what format we're going to supply data
to it
// this is necessary if you're providing data through an input
callback
// AND you want the DefaultOutputUnit to do any format conversions
// necessary from your format to the device's format.
AudioStreamBasicDescription streamFormat; memset(&streamFormat, 0,
sizeof(streamFormat));
streamFormat.mSampleRate = SAMPLES_PER_SECOND; // the
sample rate of the audio stream
streamFormat.mFormatID = kAudioFormatLinearPCM; // the
specific encoding type of audio stream
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat |
kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved;
#if (BYTE_ORDER == BIG_ENDIAN)
streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
#endif
streamFormat.mBytesPerPacket = 4;
streamFormat.mFramesPerPacket = 1;
streamFormat.mBytesPerFrame = 4;
streamFormat.mChannelsPerFrame = 1;
streamFormat.mBitsPerChannel = 32;
err = AudioUnitSetProperty (outputUnit,
kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0,
&streamFormat, sizeof(AudioStreamBasicDescription));
if (err) {printf ("AudioUnitSetProperty-SF=%4.4s, %ld\n",
(char*)&err, err); exit(10);}
// Initialize unit
err = AudioUnitInitialize(outputUnit);
if (err) {printf ("AudioUnitInitialize=%ld\n", err); exit(10);}
Float64 outSampleRate;
UInt32 size = sizeof(Float64);
err = AudioUnitGetProperty(outputUnit,
kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0,
&outSampleRate, &size);
if (err) {printf ("AudioUnitSetProperty-GF=%4.4s, %ld\n",
(char*)&err, err); exit(10);}
// Start the rendering
// The DefaultOutputUnit will do any format conversions to the
format of the default device
err = AudioOutputUnitStart (outputUnit);
if (err) {printf ("AudioOutputUnitStart=%ld\n", err); exit(10);}
// we call the CFRunLoopRunInMode to service any notifications
that the audio
// system has to deal with
while(_keepGoing) CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0,
false); // in fault mode, this loop spins at 100% CPU --jaf
// REALLY after you're finished playing STOP THE AUDIO OUTPUT
UNIT!!!!!!
verify_noerr (AudioOutputUnitStop(outputUnit));
err = AudioUnitUninitialize (outputUnit);
if (err) {printf ("AudioUnitUninitialize=%ld\n", err); exit(10);}
CloseComponent(outputUnit);
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden