Can't make AudioQueue play my buffer...
Can't make AudioQueue play my buffer...
- Subject: Can't make AudioQueue play my buffer...
- From: Carlos Eduardo Mello <email@hidden>
- Date: Sun, 12 Apr 2009 13:04:55 -0300
Hi People,
I haven't done any core audio programming in a long time.
Reading the latest docs, I found that AudioQueue would be the best
choice for this little project:
I have a small cocoa app (Obj-C++), which produces buffers, ready to
be output. I mix them in one central buffer (mMixBuffer) and send it
out with this player object (code bellow). I started out with the
audio file playing example from "Audio Queue Services Programming
Guide" (Oct 2007). Since I am doing linear PCM only and playing
samples which are already in memory, I removed all the parts which
dealt with fIle reading and decompression, which I assumed wouldn't be
needed. I followed the code bellow with the debugger. Everything seems
to work OK until it enters the run loop, at which point it never
returns. I checked the buffers and they are full, but I never hear
anything.
Could someone please help me figure out what is wrong with this code?
Is the audio format correct? ( I want 44.1kHz, mono, and the samples
in my buffer are 'floats')
Is there any way to use AudioQueue without having to deal with run
loops?
*P.S.: I lef my own comments in the code to see if I am thinking
straight. If not, please let me know.
Sorry for the message length. Any suggstions will be much appreciated.
Carlos.
static const int kNumberBuffers = 3;
const float kBufferTime = 1.0; // seconds
Player::Player( void )
{
mPlaybackQueue = NULL;
mMixBuffer = NULL;
mBufferByteSize = 0;
mIsRunning = false;
mVolume = 1.0;
mDataFormat.mSampleRate = 44100.0;
mDataFormat.mFormatID = kAudioFormatLinearPCM;
mDataFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
mDataFormat.mBytesPerPacket = sizeof (Float32);
mDataFormat.mFramesPerPacket = 1;
mDataFormat.mBytesPerFrame = 4;
mDataFormat.mChannelsPerFrame = 1;
mDataFormat.mBitsPerChannel = sizeof (Float32) * 8;
}
void Player::Play( void )
{
OSStatus err = noErr;
Float32 gain = Volume();
// Allocate Audio Queue
err = AudioQueueNewOutput( &mDataFormat, HandleOutputBuffer, this,
NULL, kCFRunLoopCommonModes, 0, &mPlaybackQueue );
if( err == noErr )
{
// calculate buffer sizes...
mBufferByteSize = static_cast<long> ( kBufferTime * SAMPLING_RATE *
sizeof(float) );
// reset playback marker...
mMixBuffer->ResetMarker();
// This is needed in order for the callback to do its thing when
priming the queue buffers.
// When there is no more data to fill the buffers, the callback will
set this to false, so...
// before starting the audio queue and running the loop, we need to
turn this on again
// (see below...)
mIsRunning = true;
// Allocate and fill buffers...
for (int i = 0; i < kNumberBuffers; ++i)
{
err = AudioQueueAllocateBuffer( mPlaybackQueue, mBufferByteSize,
&mBuffers[i] );
if( err == noErr )
{
HandleOutputBuffer( this, mPlaybackQueue, mBuffers[i] );
}
}
err = AudioQueueSetParameter( mPlaybackQueue,
kAudioQueueParam_Volume, gain );
if( err == noErr )
{
// ... we need to set this again because after priming the buffers,
// the callback turned it off.
mIsRunning = true;
err = AudioQueueStart( mPlaybackQueue, NULL );
if( err == noErr )
{
do
{
CFRunLoopRunInMode ( kCFRunLoopDefaultMode, 0.25,false );
} while ( mIsRunning );
CFRunLoopRunInMode ( kCFRunLoopDefaultMode, 1, false );
}
}
}
}
void Player::Stop( void )
{
OSStatus err = noErr;
AudioQueueStop( mPlaybackQueue, true );
mIsRunning = false;
// release queue asynch (waiting for buffer completion...)
err = AudioQueueDispose( mPlaybackQueue, false );
}
void Player::HandleOutputBuffer( void *aqData, AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer )
{
OSStatus err = noErr;
UInt32 numBytesRead;
Player * thePlayer = (Player *)aqData;
if(thePlayer->mIsRunning == false) return;
numBytesRead = thePlayer->GetDataFromMixer( inBuffer->mAudioData,
inBuffer->mAudioDataBytesCapacity );
if (numBytesRead > 0)
{
inBuffer->mAudioDataByteSize = numBytesRead;
err = AudioQueueEnqueueBuffer( thePlayer->mPlaybackQueue, inBuffer,
0, NULL );
}
else
{
err = AudioQueueStop( thePlayer->mPlaybackQueue, true );
thePlayer->mIsRunning = false;
}
}
// this method reads as many samples from the mix buffer, as will fit in
// the queue buffer. If there are more samples than max bytes, then it
sets the
// marker for next read operation and returns. Otherwise it sets the
marker to -1
// ( NO_MORE_DATA_IN_BUFFER ) indicating that there is no more data to
read
long Player::GetDataFromMixer( void * queueBuffer, long max )
{
long startSample = mMixBuffer->Marker(); // where to start copying
data from mix buffer
long numSamples = mMixBuffer->Size(); // can't go further than that
in mix buffer
int sampleSize = sizeof(float);
float * qBuffer = (float*)queueBuffer;
if( startSample == NO_MORE_DATA_IN_BUFFER )
return 0;
long i; // keeps track of which element is being writen in queueBuffer
long j; // keeps track of which element is being read from mMixBuffer
// copy data to buffer starting where we last time around (startSample)
for( i = 0, j = startSample; i < ( max / sampleSize ) && j <
numSamples; i++, j++ )
{
qBuffer[i] = mMixBuffer->Value( j );
}
// when we are done copying we check to see if we reached the end of
the source data...
if( j == numSamples )
{
mMixBuffer->SetMarker( NO_MORE_DATA_IN_BUFFER );
}
else
{
mMixBuffer->SetMarker( j );
}
// inform number of bytes placed in queue buffer...
return ( i * sampleSize );
}
_______________________________________________
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