Background: I recently began upgrading ancient MacOS 9 / Sound Manager based audio code to Leopard. It's fortunate that I waited around until Leopard to do this, because the new Audio Queue API appears to be a much more direct replacement for the now-deprecated Sound Manager API than the Audio Unit API.
I'm a newcomer to this list, so my apologies if what I'm about to discuss has already been addressed. I'm using MacOS 10.5.4 with Xcode 3.1.
To gain familiarity with the Audio Queue API, I took a look at /Developer/Examples/CoreAudio/SimpleSDK/AudioQueueTools/aqplay.cpp. The problem with this code is that it uses a hack to complete the playing of queued audio buffers before stopping the audio queue. The current code wakes up every 1/4 second to see if all of the source file data has been queued, and then waits another (hard-coded) one second for any queued buffers to play before shutting down the queue. This is a hack because if you increase the number of buffers and forget to increase the hard-coded end-of-stream delay, you risk shutting down the queue before all queued buffers have played. The engineer who wrote this code tried to do the design correctly but (for some reason) abandoned the effort and just released the hack instead.
The changes I made to the code to fix this problem: + in myInfo: renamed mDone to mDoneEnqueuing; added new flag UInt32 mIsRunning (replaces the global gIsRunning, which I removed) + pass myInfo into AudioQueueAddPropertyListener() so that myInfo.mIsRunning can be set within the queue listener callback + the 1/4 second polling loop now exits when myInfo.mIsRunning is false. The flag mDoneEnqueuing isn't used here anymore. + MyAudioQueuePropertyListenerProc(): set myInfo.mIsRunning based on the query to AudioQueueGetProperty() Summary: The queuing callback asynchronously shuts down the queue when EOF is reached, and the listener callback sets a flag when the queue actually shuts down (no more data left to play). I think that this a better example of how to use the Audio Queue API for output, and it's what the Apple engineer was trying to do.
Warning: as I was messing around with this, I uncovered a nasty bug (not yet filed with BugReporter). I originally declared mIsRunning as boolean. When I passed this into AudioQueueGetProperty() with PropertyID kAudioQueueProperty_IsRunning, the function returned a nonzero boolean even though the queue was no longer running. This caused my code to hang because myInfo.mIsRunning never transitioned to zero. Declaring myInfo.mIsRunning as UInt32 solved the problem. Note that AudioQueueGetProperty() doesn't report an error when passed a boolean - it just doesn't set the return value correctly. The size field on output remains at one byte (which is correct).
Within the next few weeks, I hope to take a look at aqrecord.cpp so I can get a handle on recording. I hope that this goes more smoothly :-) Steve
|