dolphin/Source/Core/AudioCommon/Src/CoreAudioSoundStream.cpp
Soren Jorvang 7f50bb5579 Get the audio unit output buffer size and use that as the rendering
quantum, as the callback wants us to provide exactly the amount of
samples needed.

This is incomplete because core audio may ask for less than the full
buffer size (for me, typically 1484 or 1488 bytes of a 2048 byte
buffer). As a quick hack until I read the rather impenetrable core
audio documentation, assume that each callback request will want
about the same number of samples as the preceeding one.

This makes sound bearable.

Also various cleanup.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5543 8ced0084-cf51-0410-be5f-012b33b47a6e
2010-05-30 04:21:01 +00:00

180 lines
4.6 KiB
C++

// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "CoreAudioSoundStream.h"
volatile unsigned int numBytesToRender; /* XXX */
typedef struct internal
{
AudioUnit audioUnit;
short realtimeBuffer[1024]; /* XXX */
};
OSStatus callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
UInt32 inNumberFrames, AudioBufferList *ioData)
{
internal *soundStruct = (internal *)inRefCon;
for (int i=0; i < (int)ioData->mNumberBuffers; i++)
{
memcpy(ioData->mBuffers[i].mData, &soundStruct->realtimeBuffer,
ioData->mBuffers[i].mDataByteSize);
}
numBytesToRender = ioData->mBuffers[0].mDataByteSize; /* XXX */
return 0;
}
void CoreAudioSound::SoundLoop()
{
CoreAudioInit();
}
CoreAudioSound::CoreAudioSound(CMixer *mixer) : SoundStream(mixer)
{
}
CoreAudioSound::~CoreAudioSound()
{
}
bool CoreAudioSound::CoreAudioInit()
{
ComponentDescription desc;
OSStatus err;
UInt32 enableIO;
AURenderCallbackStruct callback_struct;
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.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
Component component = FindNextComponent(NULL, &desc);
if (component == NULL)
printf("error finding audio component\n");
err = OpenAComponent(component, &soundStruct->audioUnit);
if (err)
printf("error opening audio component\n");
//enable output device
enableIO = 1;
AudioUnitSetProperty(soundStruct->audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output, 0, &enableIO,
sizeof enableIO);
//set audio format
FillOutASBDForLPCM(format, m_mixer->GetSampleRate(),
2, 16, 16, false, false, false);
err = AudioUnitSetProperty(soundStruct->audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, 0, &format,
sizeof(AudioStreamBasicDescription));
if (err)
printf("error setting audio format\n");
callback_struct.inputProc = callback;
callback_struct.inputProcRefCon = soundStruct;
err = AudioUnitSetProperty(soundStruct->audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, 0, &callback_struct,
sizeof callback_struct);
if (err)
printf("error setting audio callback\n");
err = AudioUnitGetProperty(soundStruct->audioUnit,
kAudioUnitProperty_MaximumFramesPerSlice,
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");
err = AudioOutputUnitStart(soundStruct->audioUnit);
if (err)
printf("error starting audiounit\n");
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;
}
void *coreAudioThread(void *args)
{
((CoreAudioSound *)args)->SoundLoop();
return NULL;
}
bool CoreAudioSound::Start()
{
soundSyncEvent.Init();
thread = new Common::Thread(coreAudioThread, (void *)this);
return true;
}
void CoreAudioSound::Stop()
{
threadData = 1;
soundSyncEvent.Set();
delete thread;
thread = NULL;
return;
}
void CoreAudioSound::Update()
{
soundSyncEvent.Set();
}