Have the AudioUnit callback drive the internal mixer directly instead

of going through an intermediate thread and buffer. This seems to be
how Core Audio is meant to be used, although I still haven't read the
manual.

Indeed, sound on OS X works perfectly now.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5555 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Soren Jorvang 2010-05-31 05:05:53 +00:00
parent 99e7a2ceac
commit fdd532356a
2 changed files with 62 additions and 97 deletions

View File

@ -17,33 +17,23 @@
#include "CoreAudioSoundStream.h" #include "CoreAudioSoundStream.h"
volatile unsigned int numBytesToRender; /* XXX */
typedef struct internal
{
AudioUnit audioUnit;
short realtimeBuffer[1024]; /* XXX */
};
OSStatus callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, OSStatus callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
UInt32 inNumberFrames, AudioBufferList *ioData) UInt32 inNumberFrames, AudioBufferList *ioData)
{ {
internal *soundStruct = (internal *)inRefCon; for (UInt32 i = 0; i < ioData->mNumberBuffers; i++)
for (int i=0; i < (int)ioData->mNumberBuffers; i++)
{ {
memcpy(ioData->mBuffers[i].mData, &soundStruct->realtimeBuffer, ((CoreAudioSound *)inRefCon)-> \
RenderSamples(ioData->mBuffers[i].mData,
ioData->mBuffers[i].mDataByteSize); ioData->mBuffers[i].mDataByteSize);
} }
numBytesToRender = ioData->mBuffers[0].mDataByteSize; /* XXX */ return noErr;
return 0;
} }
void CoreAudioSound::SoundLoop() void CoreAudioSound::RenderSamples(void *target, UInt32 size)
{ {
CoreAudioInit(); m_mixer->Mix((short *)target, size / 4);
} }
CoreAudioSound::CoreAudioSound(CMixer *mixer) : SoundStream(mixer) CoreAudioSound::CoreAudioSound(CMixer *mixer) : SoundStream(mixer)
@ -54,19 +44,12 @@ CoreAudioSound::~CoreAudioSound()
{ {
} }
bool CoreAudioSound::CoreAudioInit() bool CoreAudioSound::Start()
{ {
ComponentDescription desc;
OSStatus err; OSStatus err;
UInt32 enableIO; UInt32 enableIO;
AURenderCallbackStruct callback_struct; AURenderCallbackStruct callback_struct;
AudioStreamBasicDescription format; AudioStreamBasicDescription format;
UInt32 numSamplesPerSlice;
UInt32 numSamplesPerSliceSize = sizeof numSamplesPerSlice;
internal *soundStruct = (internal *)malloc(sizeof(internal));
memset(soundStruct->realtimeBuffer, 0,
sizeof soundStruct->realtimeBuffer);
desc.componentType = kAudioUnitType_Output; desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentSubType = kAudioUnitSubType_HALOutput;
@ -75,105 +58,87 @@ bool CoreAudioSound::CoreAudioInit()
desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentManufacturer = kAudioUnitManufacturer_Apple;
Component component = FindNextComponent(NULL, &desc); Component component = FindNextComponent(NULL, &desc);
if (component == NULL) if (component == NULL) {
printf("error finding audio component\n"); printf("error finding audio component\n");
return false;
}
err = OpenAComponent(component, &soundStruct->audioUnit); err = OpenAComponent(component, &audioUnit);
if (err) if (err != noErr) {
printf("error opening audio component\n"); printf("error opening audio component\n");
return false;
}
//enable output device
enableIO = 1; enableIO = 1;
AudioUnitSetProperty(soundStruct->audioUnit, AudioUnitSetProperty(audioUnit,
kAudioOutputUnitProperty_EnableIO, kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output, 0, &enableIO, kAudioUnitScope_Output, 0, &enableIO,
sizeof enableIO); sizeof enableIO);
//set audio format
FillOutASBDForLPCM(format, m_mixer->GetSampleRate(), FillOutASBDForLPCM(format, m_mixer->GetSampleRate(),
2, 16, 16, false, false, false); 2, 16, 16, false, false, false);
err = AudioUnitSetProperty(soundStruct->audioUnit, err = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_StreamFormat, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, 0, &format, kAudioUnitScope_Input, 0, &format,
sizeof(AudioStreamBasicDescription)); sizeof(AudioStreamBasicDescription));
if (err) if (err != noErr) {
printf("error setting audio format\n"); printf("error setting audio format\n");
return false;
}
callback_struct.inputProc = callback; callback_struct.inputProc = callback;
callback_struct.inputProcRefCon = soundStruct; callback_struct.inputProcRefCon = this;
err = AudioUnitSetProperty(soundStruct->audioUnit, err = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, 0, &callback_struct, kAudioUnitScope_Input, 0, &callback_struct,
sizeof callback_struct); sizeof callback_struct);
if (err) if (err != noErr) {
printf("error setting audio callback\n"); printf("error setting audio callback\n");
return false;
}
err = AudioUnitGetProperty(soundStruct->audioUnit, err = AudioUnitInitialize(audioUnit);
kAudioUnitProperty_MaximumFramesPerSlice, if (err != noErr) {
kAudioUnitScope_Global, 0,
&numSamplesPerSlice, &numSamplesPerSliceSize);
if (err)
printf("error getting audio buffer size\n");
numBytesToRender = numSamplesPerSlice * 4;
err = AudioUnitInitialize(soundStruct->audioUnit);
if (err)
printf("error initializing audiounit\n"); printf("error initializing audiounit\n");
return false;
}
err = AudioOutputUnitStart(soundStruct->audioUnit); err = AudioOutputUnitStart(audioUnit);
if (err) if (err != noErr) {
printf("error starting audiounit\n"); printf("error starting audiounit\n");
return false;
}
do
{
soundCriticalSection.Enter();
m_mixer->Mix(soundStruct->realtimeBuffer, numBytesToRender);
soundCriticalSection.Leave();
soundSyncEvent.Wait();
} while(!threadData);
err = AudioOutputUnitStop(soundStruct->audioUnit);
if (err)
printf("error stopping audiounit\n");
err = AudioUnitUninitialize(soundStruct->audioUnit);
if (err)
printf("error uninitializing audiounit\n");
err = CloseComponent(soundStruct->audioUnit);
if (err)
printf("error while closing audio component\n");
free(soundStruct);
return true; return true;
} }
void *coreAudioThread(void *args) void CoreAudioSound::SoundLoop()
{ {
((CoreAudioSound *)args)->SoundLoop();
return NULL;
}
bool CoreAudioSound::Start()
{
soundSyncEvent.Init();
thread = new Common::Thread(coreAudioThread, (void *)this);
return true;
} }
void CoreAudioSound::Stop() void CoreAudioSound::Stop()
{ {
threadData = 1; OSStatus err;
soundSyncEvent.Set();
delete thread;
thread = NULL;
err = AudioOutputUnitStop(audioUnit);
if (err != noErr) {
printf("error stopping audiounit\n");
return; return;
} }
err = AudioUnitUninitialize(audioUnit);
if (err != noErr) {
printf("error uninitializing audiounit\n");
return;
}
err = CloseComponent(audioUnit);
if (err != noErr) {
printf("error while closing audio component\n");
return;
}
}
void CoreAudioSound::Update() void CoreAudioSound::Update()
{ {
soundSyncEvent.Set();
} }

View File

@ -31,10 +31,12 @@
class CoreAudioSound : public SoundStream class CoreAudioSound : public SoundStream
{ {
#if defined(__APPLE__) #if defined(__APPLE__)
Common::Thread *thread; Common::Thread *thread;
Common::CriticalSection soundCriticalSection;
Common::Event soundSyncEvent; Common::Event soundSyncEvent;
Common::CriticalSection soundCriticalSection;
ComponentDescription desc;
AudioUnit audioUnit;
public: public:
CoreAudioSound(CMixer *mixer); CoreAudioSound(CMixer *mixer);
@ -53,8 +55,7 @@ public:
virtual void Update(); virtual void Update();
private: void RenderSamples(void *target, UInt32 size);
bool CoreAudioInit();
#else #else
public: public:
CoreAudioSound(CMixer *mixer) : SoundStream(mixer) {} CoreAudioSound(CMixer *mixer) : SoundStream(mixer) {}
@ -62,4 +63,3 @@ public:
}; };
#endif #endif