So I've actually implemented both of the methods you mention for getting the sound from the game into Core Audio. Currently I'm calling gameGetSoundSamples() from the render callback because it just ended up being easier, and there are no threading concerns in the current implementation because nothing else touches the game sound sample data.
Roughly speaking, I have:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | if (globalRunning && game is initialized)
{
gameSound->frameCount = inNumberFrames;
gameCode.getSoundSamples(nullptr, gameMemory, gameSound);
memcpy(ioData->mBuffers[0].mData, gameSound->samples,
inNumberFrames * bytesPerFrame);
}
else
{
memset(ioData->mBuffers[0].mData, 0, inNumberFrames * bytesPerFrame);
*ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
}
return noErr;
|
I used a ring buffer when I first set up my OS X layer, and it works as well but you need to handle a few issues. In terms of threading concerns, as long as you maintain that the read & write pointers are only accessed from their respective read & write methods, the only potentially shared data would be bytesFree (or bytesWritten, or whatever..). You can protect that with OSAtomicAdd32Barrier(). Other than that, you don't need locks as long as there is only one thread writing and one reading.
However, the bigger issue is handling the inevitable case when reading occurs faster than writing (or vice versa) which will eventually cause the read/write pointers to cross. So I set up a temporary hack for a solution that adjusted the number of samples the game produced if the read/write pointers got too close. e.g. if bytes were being consumed faster than I was writing them, write 1.5x as many samples per frame. Obviously not a long term solution, and could introduce some latency, but it worked. :lol:
EDIT: As for other options, I also tried AudioQueue services which lets you specify the size of the buffers it enqueues (as well as the number of buffers to maintain). This seemed to work fine, but in the spirit of HmH I wanted to keep things as low-level as possible.