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:
parent
99e7a2ceac
commit
fdd532356a
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue