Replaced Mac OS X's C++ cdrom code with almost-direct translation to C. Sam
requested this effort on the mailing list, apparently because of binary compatibility issues between 10.4 and earlier systems (or gcc4 and earlier compilers?). Works fine with SDL12/test/testcdrom.c, with this command line: ./testcdrom -status -list -play -sleep 5000 -pause -sleep 3000 -resume \ -sleep 5000 -stop -sleep 3000 -play -sleep 3000 -stop \ -sleep 3000 -eject Unix Makefiles work, XCode project still need updating for new filenames. --HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401146
This commit is contained in:
parent
cddfe242c6
commit
7be238c6aa
9 changed files with 1160 additions and 987 deletions
352
src/cdrom/macosx/AudioFilePlayer.c
Normal file
352
src/cdrom/macosx/AudioFilePlayer.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
|
||||
This file based on Apple sample code. We haven't changed the file name,
|
||||
so if you want to see the original search for it on apple.com/developer
|
||||
*/
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AudioFilePlayer.cpp
|
||||
//
|
||||
#include "AudioFilePlayer.h"
|
||||
|
||||
/*
|
||||
void ThrowResult (OSStatus result, const char* str)
|
||||
{
|
||||
SDL_SetError ("Error: %s %d", str, result);
|
||||
throw result;
|
||||
}
|
||||
*/
|
||||
|
||||
#if DEBUG
|
||||
static void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||
{
|
||||
if (!inDesc) {
|
||||
printf ("Can't print a NULL desc!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
|
||||
printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
|
||||
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
|
||||
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
|
||||
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
|
||||
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
|
||||
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
|
||||
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int AudioFilePlayer_SetDestination (AudioFilePlayer *afp, AudioUnit *inDestUnit)
|
||||
{
|
||||
//if (afp->mConnected) throw static_cast<OSStatus>(-1); //can't set dest if already engaged
|
||||
if (afp->mConnected)
|
||||
return 0 ;
|
||||
|
||||
memcpy(&afp->mPlayUnit, inDestUnit, sizeof (afp->mPlayUnit));
|
||||
|
||||
OSStatus result = noErr;
|
||||
|
||||
|
||||
//we can "down" cast a component instance to a component
|
||||
ComponentDescription desc;
|
||||
result = GetComponentInfo ((Component)*inDestUnit, &desc, 0, 0, 0);
|
||||
if (result) return 0; //THROW_RESULT("GetComponentInfo")
|
||||
|
||||
// we're going to use this to know which convert routine to call
|
||||
// a v1 audio unit will have a type of 'aunt'
|
||||
// a v2 audio unit will have one of several different types.
|
||||
if (desc.componentType != kAudioUnitComponentType) {
|
||||
result = badComponentInstance;
|
||||
//THROW_RESULT("BAD COMPONENT")
|
||||
if (result) return 0;
|
||||
}
|
||||
|
||||
/* Set the input format of the audio unit. */
|
||||
result = AudioUnitSetProperty (*inDestUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&afp->mFileDescription,
|
||||
sizeof (afp->mFileDescription));
|
||||
//THROW_RESULT("AudioUnitSetProperty")
|
||||
if (result) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void AudioFilePlayer_SetNotifier(AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon)
|
||||
{
|
||||
afp->mNotifier = inNotifier;
|
||||
afp->mRefCon = inRefCon;
|
||||
}
|
||||
|
||||
static int AudioFilePlayer_IsConnected(AudioFilePlayer *afp)
|
||||
{
|
||||
return afp->mConnected;
|
||||
}
|
||||
|
||||
static AudioUnit AudioFilePlayer_GetDestUnit(AudioFilePlayer *afp)
|
||||
{
|
||||
return afp->mPlayUnit;
|
||||
}
|
||||
|
||||
static void AudioFilePlayer_Print(AudioFilePlayer *afp)
|
||||
{
|
||||
#if DEBUG
|
||||
printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false"));
|
||||
printf ("- - - - - - - - - - - - - - \n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void AudioFilePlayer_SetStartFrame (AudioFilePlayer *afp, int frame)
|
||||
{
|
||||
SInt64 position = frame * 2352;
|
||||
|
||||
afp->mStartFrame = frame;
|
||||
afp->mAudioFileManager->SetPosition (afp->mAudioFileManager, position);
|
||||
}
|
||||
|
||||
|
||||
static int AudioFilePlayer_GetCurrentFrame (AudioFilePlayer *afp)
|
||||
{
|
||||
return afp->mStartFrame + (afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) / 2352);
|
||||
}
|
||||
|
||||
static void AudioFilePlayer_SetStopFrame (AudioFilePlayer *afp, int frame)
|
||||
{
|
||||
SInt64 position = frame * 2352;
|
||||
|
||||
afp->mAudioFileManager->SetEndOfFile (afp->mAudioFileManager, position);
|
||||
}
|
||||
|
||||
void delete_AudioFilePlayer(AudioFilePlayer *afp)
|
||||
{
|
||||
if (afp != NULL)
|
||||
{
|
||||
afp->Disconnect(afp);
|
||||
|
||||
if (afp->mAudioFileManager) {
|
||||
delete_AudioFileManager(afp->mAudioFileManager);
|
||||
afp->mAudioFileManager = 0;
|
||||
}
|
||||
|
||||
if (afp->mForkRefNum) {
|
||||
FSClose (afp->mForkRefNum);
|
||||
afp->mForkRefNum = 0;
|
||||
}
|
||||
free(afp);
|
||||
}
|
||||
}
|
||||
|
||||
static int AudioFilePlayer_Connect(AudioFilePlayer *afp)
|
||||
{
|
||||
#if DEBUG
|
||||
printf ("Connect:%x, engaged=%d\n", (int)afp->mPlayUnit, (afp->mConnected ? 1 : 0));
|
||||
#endif
|
||||
if (!afp->mConnected)
|
||||
{
|
||||
if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager))
|
||||
return 0;
|
||||
|
||||
// set the render callback for the file data to be supplied to the sound converter AU
|
||||
afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc;
|
||||
afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager;
|
||||
|
||||
OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&afp->mInputCallback,
|
||||
sizeof(afp->mInputCallback));
|
||||
if (result) return 0; //THROW_RESULT("AudioUnitSetProperty")
|
||||
afp->mConnected = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// warning noted, now please go away ;-)
|
||||
// #warning This should redirect the calling of notification code to some other thread
|
||||
static void AudioFilePlayer_DoNotification (AudioFilePlayer *afp, OSStatus inStatus)
|
||||
{
|
||||
if (afp->mNotifier) {
|
||||
(*afp->mNotifier) (afp->mRefCon, inStatus);
|
||||
} else {
|
||||
SDL_SetError ("Notification posted with no notifier in place");
|
||||
|
||||
if (inStatus == kAudioFilePlay_FileIsFinished)
|
||||
afp->Disconnect(afp);
|
||||
else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun)
|
||||
afp->Disconnect(afp);
|
||||
}
|
||||
}
|
||||
|
||||
static void AudioFilePlayer_Disconnect (AudioFilePlayer *afp)
|
||||
{
|
||||
#if DEBUG
|
||||
printf ("Disconnect:%x,%ld, engaged=%d\n", (int)afp->mPlayUnit, 0, (afp->mConnected ? 1 : 0));
|
||||
#endif
|
||||
if (afp->mConnected)
|
||||
{
|
||||
afp->mConnected = 0;
|
||||
|
||||
afp->mInputCallback.inputProc = 0;
|
||||
afp->mInputCallback.inputProcRefCon = 0;
|
||||
OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&afp->mInputCallback,
|
||||
sizeof(afp->mInputCallback));
|
||||
if (result)
|
||||
SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result);
|
||||
|
||||
afp->mAudioFileManager->Disconnect(afp->mAudioFileManager);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
UInt32 offset;
|
||||
UInt32 blockSize;
|
||||
} SSNDData;
|
||||
|
||||
static int AudioFilePlayer_OpenFile (AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileDataSize)
|
||||
{
|
||||
ContainerChunk chunkHeader;
|
||||
ChunkHeader chunk;
|
||||
SSNDData ssndData;
|
||||
|
||||
OSErr result;
|
||||
HFSUniStr255 dfName;
|
||||
ByteCount actual;
|
||||
SInt64 offset;
|
||||
|
||||
// Open the data fork of the input file
|
||||
result = FSGetDataForkName(&dfName);
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName")
|
||||
|
||||
result = FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm, &afp->mForkRefNum);
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork")
|
||||
|
||||
// Read the file header, and check if it's indeed an AIFC file
|
||||
result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual);
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
if (chunkHeader.ckID != 'FORM') {
|
||||
result = -1;
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");
|
||||
}
|
||||
|
||||
if (chunkHeader.formType != 'AIFC') {
|
||||
result = -1;
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'");
|
||||
}
|
||||
|
||||
// Search for the SSND chunk. We ignore all compression etc. information
|
||||
// in other chunks. Of course that is kind of evil, but for now we are lazy
|
||||
// and rely on the cdfs to always give us the same fixed format.
|
||||
// TODO: Parse the COMM chunk we currently skip to fill in mFileDescription.
|
||||
offset = 0;
|
||||
do {
|
||||
result = FSReadFork(afp->mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual);
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
// Skip the chunk data
|
||||
offset = chunk.ckSize;
|
||||
} while (chunk.ckID != 'SSND');
|
||||
|
||||
// Read the header of the SSND chunk. After this, we are positioned right
|
||||
// at the start of the audio data.
|
||||
result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual);
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset);
|
||||
if (result) return 0; //THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition")
|
||||
|
||||
// Data size
|
||||
*outFileDataSize = chunk.ckSize - ssndData.offset - 8;
|
||||
|
||||
// File format
|
||||
afp->mFileDescription.mSampleRate = 44100;
|
||||
afp->mFileDescription.mFormatID = kAudioFormatLinearPCM;
|
||||
afp->mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
|
||||
afp->mFileDescription.mBytesPerPacket = 4;
|
||||
afp->mFileDescription.mFramesPerPacket = 1;
|
||||
afp->mFileDescription.mBytesPerFrame = 4;
|
||||
afp->mFileDescription.mChannelsPerFrame = 2;
|
||||
afp->mFileDescription.mBitsPerChannel = 16;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
AudioFilePlayer *new_AudioFilePlayer (const FSRef *inFileRef)
|
||||
{
|
||||
SInt64 fileDataSize = 0;
|
||||
|
||||
AudioFilePlayer *afp = (AudioFilePlayer *) malloc(sizeof (AudioFilePlayer));
|
||||
if (afp == NULL)
|
||||
return NULL;
|
||||
memset(afp, '\0', sizeof (*afp));
|
||||
|
||||
#define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m
|
||||
SET_AUDIOFILEPLAYER_METHOD(SetDestination);
|
||||
SET_AUDIOFILEPLAYER_METHOD(SetNotifier);
|
||||
SET_AUDIOFILEPLAYER_METHOD(SetStartFrame);
|
||||
SET_AUDIOFILEPLAYER_METHOD(GetCurrentFrame);
|
||||
SET_AUDIOFILEPLAYER_METHOD(SetStopFrame);
|
||||
SET_AUDIOFILEPLAYER_METHOD(Connect);
|
||||
SET_AUDIOFILEPLAYER_METHOD(Disconnect);
|
||||
SET_AUDIOFILEPLAYER_METHOD(DoNotification);
|
||||
SET_AUDIOFILEPLAYER_METHOD(IsConnected);
|
||||
SET_AUDIOFILEPLAYER_METHOD(GetDestUnit);
|
||||
SET_AUDIOFILEPLAYER_METHOD(Print);
|
||||
SET_AUDIOFILEPLAYER_METHOD(OpenFile);
|
||||
#undef SET_AUDIOFILEPLAYER_METHOD
|
||||
|
||||
if (!afp->OpenFile (afp, inFileRef, &fileDataSize))
|
||||
{
|
||||
free(afp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// we want about 4 seconds worth of data for the buffer
|
||||
int bytesPerSecond = (UInt32) (4 * afp->mFileDescription.mSampleRate * afp->mFileDescription.mBytesPerFrame);
|
||||
|
||||
#if DEBUG
|
||||
printf("File format:\n");
|
||||
PrintStreamDesc (&afp->mFileDescription);
|
||||
#endif
|
||||
|
||||
afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum,
|
||||
fileDataSize,
|
||||
bytesPerSecond);
|
||||
if (afp->mAudioFileManager == NULL)
|
||||
{
|
||||
delete_AudioFilePlayer(afp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return afp;
|
||||
}
|
||||
|
|
@ -1,330 +0,0 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
|
||||
This file based on Apple sample code. We haven't changed the file name,
|
||||
so if you want to see the original search for it on apple.com/developer
|
||||
*/
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AudioFilePlayer.cpp
|
||||
//
|
||||
#include "AudioFilePlayer.h"
|
||||
|
||||
void ThrowResult (OSStatus result, const char* str)
|
||||
{
|
||||
SDL_SetError ("Error: %s %d", str, result);
|
||||
throw result;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||
{
|
||||
if (!inDesc) {
|
||||
printf ("Can't print a NULL desc!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
printf (" Sample Rate:%f\n", inDesc->mSampleRate);
|
||||
printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
|
||||
printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
|
||||
printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
|
||||
printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
|
||||
printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
|
||||
printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
|
||||
printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
|
||||
printf ("- - - - - - - - - - - - - - - - - - - -\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
OSStatus AudioFileManager::FileInputProc (void *inRefCon,
|
||||
AudioUnitRenderActionFlags inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
AudioBuffer *ioData)
|
||||
{
|
||||
AudioFileManager* THIS = (AudioFileManager*)inRefCon;
|
||||
return THIS->Render(*ioData);
|
||||
}
|
||||
|
||||
OSStatus AudioFileManager::Render (AudioBuffer &ioData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
if (mBufferOffset >= mBufferSize) {
|
||||
result = GetFileData(&mTmpBuffer, &mBufferSize);
|
||||
if (result) {
|
||||
SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
|
||||
mParent.DoNotification (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
mBufferOffset = 0;
|
||||
}
|
||||
|
||||
if (ioData.mDataByteSize > mBufferSize - mBufferOffset)
|
||||
ioData.mDataByteSize = mBufferSize - mBufferOffset;
|
||||
ioData.mData = (char *)mTmpBuffer + mBufferOffset;
|
||||
mBufferOffset += ioData.mDataByteSize;
|
||||
|
||||
mByteCounter += ioData.mDataByteSize;
|
||||
AfterRender();
|
||||
return result;
|
||||
}
|
||||
|
||||
AudioFileManager::~AudioFileManager ()
|
||||
{
|
||||
if (mFileBuffer) {
|
||||
free (mFileBuffer);
|
||||
mFileBuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
AudioFilePlayer::AudioFilePlayer (const FSRef *inFileRef)
|
||||
: mConnected (false),
|
||||
mAudioFileManager (0),
|
||||
mNotifier (0),
|
||||
mStartFrame (0)
|
||||
{
|
||||
SInt64 fileDataSize = 0;
|
||||
|
||||
OpenFile (inFileRef, fileDataSize);
|
||||
|
||||
// we want about 4 seconds worth of data for the buffer
|
||||
int bytesPerSecond = UInt32 (4 * mFileDescription.mSampleRate * mFileDescription.mBytesPerFrame);
|
||||
|
||||
#if DEBUG
|
||||
printf("File format:\n");
|
||||
PrintStreamDesc (&mFileDescription);
|
||||
#endif
|
||||
|
||||
mAudioFileManager = new AudioFileManager (*this,
|
||||
mForkRefNum,
|
||||
fileDataSize,
|
||||
bytesPerSecond);
|
||||
}
|
||||
|
||||
void AudioFilePlayer::SetDestination (AudioUnit &inDestUnit)
|
||||
{
|
||||
if (mConnected) throw static_cast<OSStatus>(-1); //can't set dest if already engaged
|
||||
|
||||
mPlayUnit = inDestUnit;
|
||||
|
||||
OSStatus result = noErr;
|
||||
|
||||
|
||||
//we can "down" cast a component instance to a component
|
||||
ComponentDescription desc;
|
||||
result = GetComponentInfo ((Component)inDestUnit, &desc, 0, 0, 0);
|
||||
THROW_RESULT("GetComponentInfo")
|
||||
|
||||
// we're going to use this to know which convert routine to call
|
||||
// a v1 audio unit will have a type of 'aunt'
|
||||
// a v2 audio unit will have one of several different types.
|
||||
if (desc.componentType != kAudioUnitComponentType) {
|
||||
result = badComponentInstance;
|
||||
THROW_RESULT("BAD COMPONENT")
|
||||
}
|
||||
|
||||
/* Set the input format of the audio unit. */
|
||||
result = AudioUnitSetProperty (inDestUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&mFileDescription,
|
||||
sizeof (mFileDescription));
|
||||
THROW_RESULT("AudioUnitSetProperty")
|
||||
}
|
||||
|
||||
void AudioFilePlayer::SetStartFrame (int frame)
|
||||
{
|
||||
SInt64 position = frame * 2352;
|
||||
|
||||
mStartFrame = frame;
|
||||
mAudioFileManager->SetPosition (position);
|
||||
}
|
||||
|
||||
|
||||
int AudioFilePlayer::GetCurrentFrame ()
|
||||
{
|
||||
return mStartFrame + (mAudioFileManager->GetByteCounter() / 2352);
|
||||
}
|
||||
|
||||
void AudioFilePlayer::SetStopFrame (int frame)
|
||||
{
|
||||
SInt64 position = frame * 2352;
|
||||
|
||||
mAudioFileManager->SetEndOfFile (position);
|
||||
}
|
||||
|
||||
AudioFilePlayer::~AudioFilePlayer()
|
||||
{
|
||||
Disconnect();
|
||||
|
||||
if (mAudioFileManager) {
|
||||
delete mAudioFileManager;
|
||||
mAudioFileManager = 0;
|
||||
}
|
||||
|
||||
if (mForkRefNum) {
|
||||
FSClose (mForkRefNum);
|
||||
mForkRefNum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioFilePlayer::Connect()
|
||||
{
|
||||
#if DEBUG
|
||||
printf ("Connect:%x, engaged=%d\n", (int)mPlayUnit, (mConnected ? 1 : 0));
|
||||
#endif
|
||||
if (!mConnected)
|
||||
{
|
||||
mAudioFileManager->DoConnect();
|
||||
|
||||
|
||||
// set the render callback for the file data to be supplied to the sound converter AU
|
||||
mInputCallback.inputProc = AudioFileManager::FileInputProc;
|
||||
mInputCallback.inputProcRefCon = mAudioFileManager;
|
||||
|
||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&mInputCallback,
|
||||
sizeof(mInputCallback));
|
||||
THROW_RESULT("AudioUnitSetProperty")
|
||||
mConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
// warning noted, now please go away ;-)
|
||||
// #warning This should redirect the calling of notification code to some other thread
|
||||
void AudioFilePlayer::DoNotification (OSStatus inStatus) const
|
||||
{
|
||||
AudioFilePlayer* THIS = const_cast<AudioFilePlayer*>(this);
|
||||
|
||||
if (mNotifier) {
|
||||
(*mNotifier) (mRefCon, inStatus);
|
||||
} else {
|
||||
SDL_SetError ("Notification posted with no notifier in place");
|
||||
|
||||
if (inStatus == kAudioFilePlay_FileIsFinished)
|
||||
THIS->Disconnect();
|
||||
else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun)
|
||||
THIS->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioFilePlayer::Disconnect ()
|
||||
{
|
||||
#if DEBUG
|
||||
printf ("Disconnect:%x,%ld, engaged=%d\n", (int)mPlayUnit, 0, (mConnected ? 1 : 0));
|
||||
#endif
|
||||
if (mConnected)
|
||||
{
|
||||
mConnected = false;
|
||||
|
||||
mInputCallback.inputProc = 0;
|
||||
mInputCallback.inputProcRefCon = 0;
|
||||
OSStatus result = AudioUnitSetProperty (mPlayUnit,
|
||||
kAudioUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&mInputCallback,
|
||||
sizeof(mInputCallback));
|
||||
if (result)
|
||||
SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result);
|
||||
|
||||
mAudioFileManager->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
struct SSNDData {
|
||||
UInt32 offset;
|
||||
UInt32 blockSize;
|
||||
};
|
||||
|
||||
void AudioFilePlayer::OpenFile (const FSRef *inRef, SInt64& outFileDataSize)
|
||||
{
|
||||
ContainerChunk chunkHeader;
|
||||
ChunkHeader chunk;
|
||||
SSNDData ssndData;
|
||||
|
||||
OSErr result;
|
||||
HFSUniStr255 dfName;
|
||||
ByteCount actual;
|
||||
SInt64 offset;
|
||||
|
||||
// Open the data fork of the input file
|
||||
result = FSGetDataForkName(&dfName);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName")
|
||||
|
||||
result = FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm, &mForkRefNum);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork")
|
||||
|
||||
// Read the file header, and check if it's indeed an AIFC file
|
||||
result = FSReadFork(mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
if (chunkHeader.ckID != 'FORM') {
|
||||
result = -1;
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");
|
||||
}
|
||||
|
||||
if (chunkHeader.formType != 'AIFC') {
|
||||
result = -1;
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'");
|
||||
}
|
||||
|
||||
// Search for the SSND chunk. We ignore all compression etc. information
|
||||
// in other chunks. Of course that is kind of evil, but for now we are lazy
|
||||
// and rely on the cdfs to always give us the same fixed format.
|
||||
// TODO: Parse the COMM chunk we currently skip to fill in mFileDescription.
|
||||
offset = 0;
|
||||
do {
|
||||
result = FSReadFork(mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
// Skip the chunk data
|
||||
offset = chunk.ckSize;
|
||||
} while (chunk.ckID != 'SSND');
|
||||
|
||||
// Read the header of the SSND chunk. After this, we are positioned right
|
||||
// at the start of the audio data.
|
||||
result = FSReadFork(mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")
|
||||
|
||||
result = FSSetForkPosition(mForkRefNum, fsFromMark, ssndData.offset);
|
||||
THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition")
|
||||
|
||||
// Data size
|
||||
outFileDataSize = chunk.ckSize - ssndData.offset - 8;
|
||||
|
||||
// File format
|
||||
mFileDescription.mSampleRate = 44100;
|
||||
mFileDescription.mFormatID = kAudioFormatLinearPCM;
|
||||
mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
|
||||
mFileDescription.mBytesPerPacket = 4;
|
||||
mFileDescription.mFramesPerPacket = 1;
|
||||
mFileDescription.mBytesPerFrame = 4;
|
||||
mFileDescription.mChannelsPerFrame = 2;
|
||||
mFileDescription.mBitsPerChannel = 16;
|
||||
}
|
|
@ -37,12 +37,14 @@
|
|||
|
||||
const char* AudioFilePlayerErrorStr (OSStatus error);
|
||||
|
||||
/*
|
||||
void ThrowResult (OSStatus result, const char *str);
|
||||
|
||||
#define THROW_RESULT(str) \
|
||||
if (result) { \
|
||||
ThrowResult (result, str); \
|
||||
}
|
||||
*/
|
||||
|
||||
typedef void (*AudioFilePlayNotifier)(void *inRefCon,
|
||||
OSStatus inStatus);
|
||||
|
@ -54,49 +56,25 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
class AudioFileManager;
|
||||
struct S_AudioFileManager;
|
||||
|
||||
#pragma mark __________ AudioFilePlayer
|
||||
class AudioFilePlayer
|
||||
typedef struct S_AudioFilePlayer
|
||||
{
|
||||
public:
|
||||
AudioFilePlayer (const FSRef *inFileRef);
|
||||
|
||||
~AudioFilePlayer();
|
||||
//public:
|
||||
int (*SetDestination)(struct S_AudioFilePlayer *afp, AudioUnit *inDestUnit);
|
||||
void (*SetNotifier)(struct S_AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon);
|
||||
void (*SetStartFrame)(struct S_AudioFilePlayer *afp, int frame); // seek in the file
|
||||
int (*GetCurrentFrame)(struct S_AudioFilePlayer *afp); // get the current frame position
|
||||
void (*SetStopFrame)(struct S_AudioFilePlayer *afp, int frame); // set limit in the file
|
||||
int (*Connect)(struct S_AudioFilePlayer *afp);
|
||||
void (*Disconnect)(struct S_AudioFilePlayer *afp);
|
||||
void (*DoNotification)(struct S_AudioFilePlayer *afp, OSStatus inError);
|
||||
int (*IsConnected)(struct S_AudioFilePlayer *afp);
|
||||
AudioUnit (*GetDestUnit)(struct S_AudioFilePlayer *afp);
|
||||
void (*Print)(struct S_AudioFilePlayer *afp);
|
||||
|
||||
void SetDestination (AudioUnit &inDestUnit);
|
||||
|
||||
void SetNotifier (AudioFilePlayNotifier inNotifier, void *inRefCon)
|
||||
{
|
||||
mNotifier = inNotifier;
|
||||
mRefCon = inRefCon;
|
||||
}
|
||||
|
||||
void SetStartFrame (int frame); // seek in the file
|
||||
|
||||
int GetCurrentFrame (); // get the current frame position
|
||||
|
||||
void SetStopFrame (int frame); // set limit in the file
|
||||
|
||||
void Connect();
|
||||
|
||||
void Disconnect();
|
||||
|
||||
void DoNotification (OSStatus inError) const;
|
||||
|
||||
bool IsConnected () const { return mConnected; }
|
||||
|
||||
AudioUnit GetDestUnit () const { return mPlayUnit; }
|
||||
|
||||
#if DEBUG
|
||||
void Print() const
|
||||
{
|
||||
printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false"));
|
||||
printf ("- - - - - - - - - - - - - - \n");
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
//private:
|
||||
AudioUnit mPlayUnit;
|
||||
SInt16 mForkRefNum;
|
||||
|
||||
|
@ -104,9 +82,9 @@ private:
|
|||
|
||||
AudioStreamBasicDescription mFileDescription;
|
||||
|
||||
bool mConnected;
|
||||
int mConnected;
|
||||
|
||||
AudioFileManager* mAudioFileManager;
|
||||
struct S_AudioFileManager* mAudioFileManager;
|
||||
|
||||
AudioFilePlayNotifier mNotifier;
|
||||
void* mRefCon;
|
||||
|
@ -115,41 +93,32 @@ private:
|
|||
|
||||
#pragma mark __________ Private_Methods
|
||||
|
||||
void OpenFile (const FSRef *inRef, SInt64& outFileSize);
|
||||
};
|
||||
int (*OpenFile)(struct S_AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileSize);
|
||||
} AudioFilePlayer;
|
||||
|
||||
|
||||
AudioFilePlayer *new_AudioFilePlayer(const FSRef *inFileRef);
|
||||
void delete_AudioFilePlayer(AudioFilePlayer *afp);
|
||||
|
||||
|
||||
|
||||
#pragma mark __________ AudioFileManager
|
||||
class AudioFileManager
|
||||
typedef struct S_AudioFileManager
|
||||
{
|
||||
public:
|
||||
AudioFileManager (AudioFilePlayer &inParent,
|
||||
SInt16 inForkRefNum,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize);
|
||||
|
||||
~AudioFileManager();
|
||||
|
||||
|
||||
//public:
|
||||
// this method should NOT be called by an object of this class
|
||||
// as it is called by the parent's Disconnect() method
|
||||
void Disconnect ();
|
||||
|
||||
void DoConnect ();
|
||||
|
||||
OSStatus Read(char *buffer, UInt32 *len);
|
||||
|
||||
const char* GetFileBuffer () { return mFileBuffer; }
|
||||
|
||||
const AudioFilePlayer& GetParent () const { return mParent; }
|
||||
|
||||
void SetPosition (SInt64 pos); // seek/rewind in the file
|
||||
|
||||
int GetByteCounter () { return mByteCounter; } // return actual bytes streamed to audio hardware
|
||||
|
||||
void SetEndOfFile (SInt64 pos); // set the "EOF" (will behave just like it reached eof)
|
||||
void (*Disconnect)(struct S_AudioFileManager *afm);
|
||||
int (*DoConnect)(struct S_AudioFileManager *afm);
|
||||
OSStatus (*Read)(struct S_AudioFileManager *afm, char *buffer, UInt32 *len);
|
||||
const char* (*GetFileBuffer)(struct S_AudioFileManager *afm);
|
||||
const AudioFilePlayer *(*GetParent)(struct S_AudioFileManager *afm);
|
||||
void (*SetPosition)(struct S_AudioFileManager *afm, SInt64 pos); // seek/rewind in the file
|
||||
int (*GetByteCounter)(struct S_AudioFileManager *afm); // return actual bytes streamed to audio hardware
|
||||
void (*SetEndOfFile)(struct S_AudioFileManager *afm, SInt64 pos); // set the "EOF" (will behave just like it reached eof)
|
||||
|
||||
protected:
|
||||
AudioFilePlayer& mParent;
|
||||
//protected:
|
||||
AudioFilePlayer* mParent;
|
||||
SInt16 mForkRefNum;
|
||||
SInt64 mAudioDataOffset;
|
||||
|
||||
|
@ -157,9 +126,9 @@ protected:
|
|||
|
||||
int mByteCounter;
|
||||
|
||||
bool mReadFromFirstBuffer;
|
||||
bool mLockUnsuccessful;
|
||||
bool mIsEngaged;
|
||||
int mReadFromFirstBuffer;
|
||||
int mLockUnsuccessful;
|
||||
int mIsEngaged;
|
||||
|
||||
int mNumTimesAskedSinceFinished;
|
||||
|
||||
|
@ -167,27 +136,34 @@ protected:
|
|||
void* mTmpBuffer;
|
||||
UInt32 mBufferSize;
|
||||
UInt32 mBufferOffset;
|
||||
public:
|
||||
const UInt32 mChunkSize;
|
||||
//public:
|
||||
UInt32 mChunkSize;
|
||||
SInt64 mFileLength;
|
||||
SInt64 mReadFilePosition;
|
||||
bool mWriteToFirstBuffer;
|
||||
bool mFinishedReadingData;
|
||||
int mWriteToFirstBuffer;
|
||||
int mFinishedReadingData;
|
||||
|
||||
protected:
|
||||
OSStatus Render (AudioBuffer &ioData);
|
||||
//protected:
|
||||
OSStatus (*Render)(struct S_AudioFileManager *afm, AudioBuffer *ioData);
|
||||
OSStatus (*GetFileData)(struct S_AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize);
|
||||
void (*AfterRender)(struct S_AudioFileManager *afm);
|
||||
|
||||
//public:
|
||||
//static
|
||||
OSStatus (*FileInputProc)(void *inRefCon,
|
||||
AudioUnitRenderActionFlags inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
AudioBuffer *ioData);
|
||||
} AudioFileManager;
|
||||
|
||||
|
||||
AudioFileManager *new_AudioFileManager (AudioFilePlayer *inParent,
|
||||
SInt16 inForkRefNum,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize);
|
||||
|
||||
OSStatus GetFileData (void** inOutData, UInt32 *inOutDataSize);
|
||||
|
||||
void AfterRender ();
|
||||
|
||||
public:
|
||||
static OSStatus FileInputProc (void *inRefCon,
|
||||
AudioUnitRenderActionFlags inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
AudioBuffer *ioData);
|
||||
};
|
||||
|
||||
void delete_AudioFileManager(AudioFileManager *afm);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
602
src/cdrom/macosx/AudioFileReaderThread.c
Normal file
602
src/cdrom/macosx/AudioFileReaderThread.c
Normal file
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
|
||||
This file based on Apple sample code. We haven't changed the file name,
|
||||
so if you want to see the original search for it on apple.com/developer
|
||||
*/
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AudioFileManager.cpp
|
||||
//
|
||||
#include "AudioFilePlayer.h"
|
||||
#include <mach/mach.h> //used for setting policy of thread
|
||||
#include "SDLOSXCAGuard.h"
|
||||
#include <pthread.h>
|
||||
|
||||
//#include <list>
|
||||
|
||||
//typedef void *FileData;
|
||||
typedef struct S_FileData
|
||||
{
|
||||
AudioFileManager *obj;
|
||||
struct S_FileData *next;
|
||||
} FileData;
|
||||
|
||||
|
||||
typedef struct S_FileReaderThread {
|
||||
//public:
|
||||
SDLOSXCAGuard* (*GetGuard)(struct S_FileReaderThread *frt);
|
||||
void (*AddReader)(struct S_FileReaderThread *frt);
|
||||
void (*RemoveReader)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
|
||||
int (*TryNextRead)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
|
||||
|
||||
int mThreadShouldDie;
|
||||
|
||||
//private:
|
||||
//typedef std::list<AudioFileManager*> FileData;
|
||||
|
||||
SDLOSXCAGuard *mGuard;
|
||||
UInt32 mThreadPriority;
|
||||
|
||||
int mNumReaders;
|
||||
FileData *mFileData;
|
||||
|
||||
|
||||
void (*ReadNextChunk)(struct S_FileReaderThread *frt);
|
||||
int (*StartFixedPriorityThread)(struct S_FileReaderThread *frt);
|
||||
//static
|
||||
UInt32 (*GetThreadBasePriority)(pthread_t inThread);
|
||||
//static
|
||||
void* (*DiskReaderEntry)(void *inRefCon);
|
||||
} FileReaderThread;
|
||||
|
||||
|
||||
static SDLOSXCAGuard* FileReaderThread_GetGuard(FileReaderThread *frt)
|
||||
{
|
||||
return frt->mGuard;
|
||||
}
|
||||
|
||||
// returns 1 if succeeded
|
||||
static int FileReaderThread_TryNextRead (FileReaderThread *frt, AudioFileManager* inItem)
|
||||
{
|
||||
int didLock = 0;
|
||||
int succeeded = 0;
|
||||
if (frt->mGuard->Try(frt->mGuard, &didLock))
|
||||
{
|
||||
//frt->mFileData.push_back (inItem);
|
||||
// !!! FIXME: this could be faster with a "tail" member. --ryan.
|
||||
FileData *i = frt->mFileData;
|
||||
FileData *prev = NULL;
|
||||
|
||||
FileData *newfd = (FileData *) malloc(sizeof (FileData));
|
||||
newfd->obj = inItem;
|
||||
newfd->next = NULL;
|
||||
|
||||
while (i != NULL) { prev = i; i = i->next; }
|
||||
if (prev == NULL)
|
||||
frt->mFileData = newfd;
|
||||
else
|
||||
prev->next = newfd;
|
||||
|
||||
frt->mGuard->Notify(frt->mGuard);
|
||||
succeeded = 1;
|
||||
|
||||
if (didLock)
|
||||
frt->mGuard->Unlock(frt->mGuard);
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
static void FileReaderThread_AddReader(FileReaderThread *frt)
|
||||
{
|
||||
if (frt->mNumReaders == 0)
|
||||
{
|
||||
frt->mThreadShouldDie = 0;
|
||||
frt->StartFixedPriorityThread (frt);
|
||||
}
|
||||
frt->mNumReaders++;
|
||||
}
|
||||
|
||||
static void FileReaderThread_RemoveReader (FileReaderThread *frt, AudioFileManager* inItem)
|
||||
{
|
||||
if (frt->mNumReaders > 0)
|
||||
{
|
||||
int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
|
||||
|
||||
//frt->mFileData.remove (inItem);
|
||||
FileData *i = frt->mFileData;
|
||||
FileData *prev = NULL;
|
||||
while (i != NULL)
|
||||
{
|
||||
FileData *next = i->next;
|
||||
if (i->obj != inItem)
|
||||
prev = i;
|
||||
else
|
||||
{
|
||||
if (prev == NULL)
|
||||
frt->mFileData = next;
|
||||
else
|
||||
prev->next = next;
|
||||
free(i);
|
||||
}
|
||||
i = next;
|
||||
}
|
||||
|
||||
if (--frt->mNumReaders == 0) {
|
||||
frt->mThreadShouldDie = 1;
|
||||
frt->mGuard->Notify(frt->mGuard); // wake up thread so it will quit
|
||||
frt->mGuard->Wait(frt->mGuard); // wait for thread to die
|
||||
}
|
||||
|
||||
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
|
||||
}
|
||||
}
|
||||
|
||||
static int FileReaderThread_StartFixedPriorityThread (FileReaderThread *frt)
|
||||
{
|
||||
pthread_attr_t theThreadAttrs;
|
||||
pthread_t pThread;
|
||||
|
||||
OSStatus result = pthread_attr_init(&theThreadAttrs);
|
||||
if (result) return 0; //THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")
|
||||
|
||||
result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
|
||||
if (result) return 0; //THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")
|
||||
|
||||
result = pthread_create (&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt);
|
||||
if (result) return 0; //THROW_RESULT("pthread_create - Create and start the thread.")
|
||||
|
||||
pthread_attr_destroy(&theThreadAttrs);
|
||||
|
||||
// we've now created the thread and started it
|
||||
// we'll now set the priority of the thread to the nominated priority
|
||||
// and we'll also make the thread fixed
|
||||
thread_extended_policy_data_t theFixedPolicy;
|
||||
thread_precedence_policy_data_t thePrecedencePolicy;
|
||||
SInt32 relativePriority;
|
||||
|
||||
// make thread fixed
|
||||
theFixedPolicy.timeshare = 0; // set to 1 for a non-fixed thread
|
||||
result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
|
||||
if (result) return 0; //THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")
|
||||
// set priority
|
||||
// precedency policy's "importance" value is relative to spawning thread's priority
|
||||
relativePriority = frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self());
|
||||
|
||||
thePrecedencePolicy.importance = relativePriority;
|
||||
result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
|
||||
if (result) return 0; //THROW_RESULT("thread_policy - Couldn't set thread priority.")
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static UInt32 FileReaderThread_GetThreadBasePriority (pthread_t inThread)
|
||||
{
|
||||
thread_basic_info_data_t threadInfo;
|
||||
policy_info_data_t thePolicyInfo;
|
||||
unsigned int count;
|
||||
|
||||
// get basic info
|
||||
count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count);
|
||||
|
||||
switch (threadInfo.policy) {
|
||||
case POLICY_TIMESHARE:
|
||||
count = POLICY_TIMESHARE_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
|
||||
return thePolicyInfo.ts.base_priority;
|
||||
break;
|
||||
|
||||
case POLICY_FIFO:
|
||||
count = POLICY_FIFO_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
|
||||
if (thePolicyInfo.fifo.depressed) {
|
||||
return thePolicyInfo.fifo.depress_priority;
|
||||
} else {
|
||||
return thePolicyInfo.fifo.base_priority;
|
||||
}
|
||||
break;
|
||||
|
||||
case POLICY_RR:
|
||||
count = POLICY_RR_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
|
||||
if (thePolicyInfo.rr.depressed) {
|
||||
return thePolicyInfo.rr.depress_priority;
|
||||
} else {
|
||||
return thePolicyInfo.rr.base_priority;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *FileReaderThread_DiskReaderEntry (void *inRefCon)
|
||||
{
|
||||
FileReaderThread *frt = (FileReaderThread *)inRefCon;
|
||||
frt->ReadNextChunk(frt);
|
||||
#if DEBUG
|
||||
printf ("finished with reading file\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void FileReaderThread_ReadNextChunk (FileReaderThread *frt)
|
||||
{
|
||||
OSStatus result;
|
||||
UInt32 dataChunkSize;
|
||||
AudioFileManager* theItem = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
{ // this is a scoped based lock
|
||||
int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
|
||||
|
||||
if (frt->mThreadShouldDie) {
|
||||
frt->mGuard->Notify(frt->mGuard);
|
||||
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
|
||||
return;
|
||||
}
|
||||
|
||||
//if (frt->mFileData.empty())
|
||||
if (frt->mFileData == NULL)
|
||||
{
|
||||
frt->mGuard->Wait(frt->mGuard);
|
||||
}
|
||||
|
||||
// kill thread
|
||||
if (frt->mThreadShouldDie) {
|
||||
|
||||
frt->mGuard->Notify(frt->mGuard);
|
||||
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
|
||||
return;
|
||||
}
|
||||
|
||||
//theItem = frt->mFileData.front();
|
||||
//frt->mFileData.pop_front();
|
||||
theItem = NULL;
|
||||
if (frt->mFileData != NULL)
|
||||
{
|
||||
FileData *next = frt->mFileData->next;
|
||||
theItem = frt->mFileData->obj;
|
||||
free(frt->mFileData);
|
||||
frt->mFileData = next;
|
||||
}
|
||||
|
||||
if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
|
||||
}
|
||||
|
||||
if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
|
||||
dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = theItem->mChunkSize;
|
||||
|
||||
// this is the exit condition for the thread
|
||||
if (dataChunkSize <= 0) {
|
||||
theItem->mFinishedReadingData = 1;
|
||||
continue;
|
||||
}
|
||||
// construct pointer
|
||||
char* writePtr = (char *) (theItem->GetFileBuffer(theItem) +
|
||||
(theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
|
||||
|
||||
// read data
|
||||
result = theItem->Read(theItem, writePtr, &dataChunkSize);
|
||||
if (result != noErr && result != eofErr) {
|
||||
AudioFilePlayer *afp = (AudioFilePlayer *) theItem->GetParent(theItem);
|
||||
afp->DoNotification(afp, result);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataChunkSize != theItem->mChunkSize)
|
||||
{
|
||||
writePtr += dataChunkSize;
|
||||
|
||||
// can't exit yet.. we still have to pass the partial buffer back
|
||||
memset (writePtr, 0, (theItem->mChunkSize - dataChunkSize));
|
||||
}
|
||||
|
||||
theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; // switch buffers
|
||||
|
||||
if (result == eofErr)
|
||||
theItem->mReadFilePosition = theItem->mFileLength;
|
||||
else
|
||||
theItem->mReadFilePosition += dataChunkSize; // increment count
|
||||
}
|
||||
}
|
||||
|
||||
void delete_FileReaderThread(FileReaderThread *frt)
|
||||
{
|
||||
if (frt != NULL)
|
||||
{
|
||||
delete_SDLOSXCAGuard(frt->mGuard);
|
||||
free(frt);
|
||||
}
|
||||
}
|
||||
|
||||
FileReaderThread *new_FileReaderThread ()
|
||||
{
|
||||
FileReaderThread *frt = (FileReaderThread *) malloc(sizeof (FileReaderThread));
|
||||
if (frt == NULL)
|
||||
return NULL;
|
||||
memset(frt, '\0', sizeof (*frt));
|
||||
|
||||
frt->mGuard = new_SDLOSXCAGuard();
|
||||
if (frt->mGuard == NULL)
|
||||
{
|
||||
free(frt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m
|
||||
SET_FILEREADERTHREAD_METHOD(GetGuard);
|
||||
SET_FILEREADERTHREAD_METHOD(AddReader);
|
||||
SET_FILEREADERTHREAD_METHOD(RemoveReader);
|
||||
SET_FILEREADERTHREAD_METHOD(TryNextRead);
|
||||
SET_FILEREADERTHREAD_METHOD(ReadNextChunk);
|
||||
SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread);
|
||||
SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority);
|
||||
SET_FILEREADERTHREAD_METHOD(DiskReaderEntry);
|
||||
#undef SET_FILEREADERTHREAD_METHOD
|
||||
|
||||
frt->mThreadPriority = 62;
|
||||
return frt;
|
||||
}
|
||||
|
||||
|
||||
static FileReaderThread *sReaderThread;
|
||||
|
||||
|
||||
static int AudioFileManager_DoConnect (AudioFileManager *afm)
|
||||
{
|
||||
if (!afm->mIsEngaged)
|
||||
{
|
||||
//afm->mReadFilePosition = 0;
|
||||
afm->mFinishedReadingData = 0;
|
||||
|
||||
afm->mNumTimesAskedSinceFinished = 0;
|
||||
afm->mLockUnsuccessful = 0;
|
||||
|
||||
OSStatus result;
|
||||
UInt32 dataChunkSize;
|
||||
|
||||
if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize)
|
||||
dataChunkSize = afm->mFileLength - afm->mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = afm->mChunkSize;
|
||||
|
||||
result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize);
|
||||
if (result) return 0; //THROW_RESULT("AudioFileManager::DoConnect(): Read")
|
||||
|
||||
afm->mReadFilePosition += dataChunkSize;
|
||||
|
||||
afm->mWriteToFirstBuffer = 0;
|
||||
afm->mReadFromFirstBuffer = 1;
|
||||
|
||||
sReaderThread->AddReader(sReaderThread);
|
||||
|
||||
afm->mIsEngaged = 1;
|
||||
}
|
||||
//else
|
||||
// throw static_cast<OSStatus>(-1); //thread has already been started
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void AudioFileManager_Disconnect (AudioFileManager *afm)
|
||||
{
|
||||
if (afm->mIsEngaged)
|
||||
{
|
||||
sReaderThread->RemoveReader (sReaderThread, afm);
|
||||
afm->mIsEngaged = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static OSStatus AudioFileManager_Read(AudioFileManager *afm, char *buffer, UInt32 *len)
|
||||
{
|
||||
return FSReadFork (afm->mForkRefNum,
|
||||
fsFromStart,
|
||||
afm->mReadFilePosition + afm->mAudioDataOffset,
|
||||
*len,
|
||||
buffer,
|
||||
len);
|
||||
}
|
||||
|
||||
static OSStatus AudioFileManager_GetFileData (AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize)
|
||||
{
|
||||
if (afm->mFinishedReadingData)
|
||||
{
|
||||
++afm->mNumTimesAskedSinceFinished;
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) {
|
||||
#if DEBUG
|
||||
printf ("* * * * * * * Can't keep up with reading file\n");
|
||||
#endif
|
||||
|
||||
afm->mParent->DoNotification (afm->mParent, kAudioFilePlayErr_FilePlayUnderrun);
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
} else {
|
||||
*inOutDataSize = afm->mChunkSize;
|
||||
*inOutData = afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer + afm->mChunkSize);
|
||||
}
|
||||
|
||||
afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
|
||||
|
||||
afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static void AudioFileManager_AfterRender (AudioFileManager *afm)
|
||||
{
|
||||
if (afm->mNumTimesAskedSinceFinished > 0)
|
||||
{
|
||||
int didLock = 0;
|
||||
SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread);
|
||||
if (guard->Try(guard, &didLock)) {
|
||||
afm->mParent->DoNotification (afm->mParent, kAudioFilePlay_FileIsFinished);
|
||||
if (didLock)
|
||||
guard->Unlock(guard);
|
||||
}
|
||||
}
|
||||
|
||||
if (afm->mLockUnsuccessful)
|
||||
afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
|
||||
}
|
||||
|
||||
static void AudioFileManager_SetPosition (AudioFileManager *afm, SInt64 pos)
|
||||
{
|
||||
if (pos < 0 || pos >= afm->mFileLength) {
|
||||
SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n",
|
||||
(unsigned int)pos, (unsigned int)afm->mFileLength);
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
afm->mReadFilePosition = pos;
|
||||
}
|
||||
|
||||
static void AudioFileManager_SetEndOfFile (AudioFileManager *afm, SInt64 pos)
|
||||
{
|
||||
if (pos <= 0 || pos > afm->mFileLength) {
|
||||
SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
|
||||
pos = afm->mFileLength;
|
||||
}
|
||||
|
||||
afm->mFileLength = pos;
|
||||
}
|
||||
|
||||
static const char *AudioFileManager_GetFileBuffer(AudioFileManager *afm)
|
||||
{
|
||||
return afm->mFileBuffer;
|
||||
}
|
||||
|
||||
const AudioFilePlayer *AudioFileManager_GetParent(AudioFileManager *afm)
|
||||
{
|
||||
return afm->mParent;
|
||||
}
|
||||
|
||||
static int AudioFileManager_GetByteCounter(AudioFileManager *afm)
|
||||
{
|
||||
return afm->mByteCounter;
|
||||
}
|
||||
|
||||
|
||||
static OSStatus AudioFileManager_FileInputProc (void *inRefCon,
|
||||
AudioUnitRenderActionFlags inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
AudioBuffer *ioData)
|
||||
{
|
||||
AudioFileManager* afm = (AudioFileManager*)inRefCon;
|
||||
return afm->Render(afm, ioData);
|
||||
}
|
||||
|
||||
static OSStatus AudioFileManager_Render (AudioFileManager *afm, AudioBuffer *ioData)
|
||||
{
|
||||
OSStatus result = noErr;
|
||||
|
||||
if (afm->mBufferOffset >= afm->mBufferSize) {
|
||||
result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize);
|
||||
if (result) {
|
||||
SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
|
||||
afm->mParent->DoNotification(afm->mParent, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
afm->mBufferOffset = 0;
|
||||
}
|
||||
|
||||
if (ioData->mDataByteSize > afm->mBufferSize - afm->mBufferOffset)
|
||||
ioData->mDataByteSize = afm->mBufferSize - afm->mBufferOffset;
|
||||
ioData->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset;
|
||||
afm->mBufferOffset += ioData->mDataByteSize;
|
||||
|
||||
afm->mByteCounter += ioData->mDataByteSize;
|
||||
afm->AfterRender(afm);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void delete_AudioFileManager (AudioFileManager *afm)
|
||||
{
|
||||
if (afm != NULL) {
|
||||
if (afm->mFileBuffer) {
|
||||
free (afm->mFileBuffer);
|
||||
}
|
||||
|
||||
free(afm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AudioFileManager *new_AudioFileManager(AudioFilePlayer *inParent,
|
||||
SInt16 inForkRefNum,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize)
|
||||
{
|
||||
AudioFileManager *afm;
|
||||
|
||||
if (sReaderThread == NULL)
|
||||
{
|
||||
sReaderThread = new_FileReaderThread();
|
||||
if (sReaderThread == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
afm = (AudioFileManager *) malloc(sizeof (AudioFileManager));
|
||||
if (afm == NULL)
|
||||
return NULL;
|
||||
memset(afm, '\0', sizeof (*afm));
|
||||
|
||||
#define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m
|
||||
SET_AUDIOFILEMANAGER_METHOD(Disconnect);
|
||||
SET_AUDIOFILEMANAGER_METHOD(DoConnect);
|
||||
SET_AUDIOFILEMANAGER_METHOD(Read);
|
||||
SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer);
|
||||
SET_AUDIOFILEMANAGER_METHOD(GetParent);
|
||||
SET_AUDIOFILEMANAGER_METHOD(SetPosition);
|
||||
SET_AUDIOFILEMANAGER_METHOD(GetByteCounter);
|
||||
SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile);
|
||||
SET_AUDIOFILEMANAGER_METHOD(Render);
|
||||
SET_AUDIOFILEMANAGER_METHOD(GetFileData);
|
||||
SET_AUDIOFILEMANAGER_METHOD(AfterRender);
|
||||
SET_AUDIOFILEMANAGER_METHOD(FileInputProc);
|
||||
#undef SET_AUDIOFILEMANAGER_METHOD
|
||||
|
||||
afm->mParent = inParent;
|
||||
afm->mForkRefNum = inForkRefNum;
|
||||
afm->mBufferSize = inChunkSize;
|
||||
afm->mBufferOffset = inChunkSize;
|
||||
afm->mChunkSize = inChunkSize;
|
||||
afm->mFileLength = inFileLength;
|
||||
afm->mFileBuffer = (char*) malloc (afm->mChunkSize * 2);
|
||||
FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset);
|
||||
assert (afm->mFileBuffer != NULL);
|
||||
return afm;
|
||||
}
|
||||
|
|
@ -1,422 +0,0 @@
|
|||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
|
||||
This file based on Apple sample code. We haven't changed the file name,
|
||||
so if you want to see the original search for it on apple.com/developer
|
||||
*/
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// AudioFileManager.cpp
|
||||
//
|
||||
#include "AudioFilePlayer.h"
|
||||
#include <mach/mach.h> //used for setting policy of thread
|
||||
#include "CAGuard.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
class FileReaderThread {
|
||||
public:
|
||||
FileReaderThread ();
|
||||
|
||||
CAGuard& GetGuard() { return mGuard; }
|
||||
|
||||
void AddReader();
|
||||
|
||||
void RemoveReader (AudioFileManager* inItem);
|
||||
|
||||
// returns true if succeeded
|
||||
bool TryNextRead (AudioFileManager* inItem)
|
||||
{
|
||||
bool didLock = false;
|
||||
bool succeeded = false;
|
||||
if (mGuard.Try (didLock))
|
||||
{
|
||||
mFileData.push_back (inItem);
|
||||
mGuard.Notify();
|
||||
succeeded = true;
|
||||
|
||||
if (didLock)
|
||||
mGuard.Unlock();
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
int mThreadShouldDie;
|
||||
|
||||
private:
|
||||
typedef std::list<AudioFileManager*> FileData;
|
||||
|
||||
CAGuard mGuard;
|
||||
UInt32 mThreadPriority;
|
||||
|
||||
int mNumReaders;
|
||||
FileData mFileData;
|
||||
|
||||
|
||||
void ReadNextChunk ();
|
||||
|
||||
void StartFixedPriorityThread ();
|
||||
static UInt32 GetThreadBasePriority (pthread_t inThread);
|
||||
|
||||
static void* DiskReaderEntry (void *inRefCon);
|
||||
};
|
||||
|
||||
FileReaderThread::FileReaderThread ()
|
||||
: mThreadPriority (62),
|
||||
mNumReaders (0)
|
||||
{
|
||||
}
|
||||
|
||||
void FileReaderThread::AddReader()
|
||||
{
|
||||
if (mNumReaders == 0)
|
||||
{
|
||||
mThreadShouldDie = false;
|
||||
|
||||
StartFixedPriorityThread ();
|
||||
}
|
||||
mNumReaders++;
|
||||
}
|
||||
|
||||
void FileReaderThread::RemoveReader (AudioFileManager* inItem)
|
||||
{
|
||||
if (mNumReaders > 0)
|
||||
{
|
||||
CAGuard::Locker fileReadLock (mGuard);
|
||||
|
||||
mFileData.remove (inItem);
|
||||
|
||||
if (--mNumReaders == 0) {
|
||||
mThreadShouldDie = true;
|
||||
mGuard.Notify(); // wake up thread so it will quit
|
||||
mGuard.Wait(); // wait for thread to die
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileReaderThread::StartFixedPriorityThread ()
|
||||
{
|
||||
pthread_attr_t theThreadAttrs;
|
||||
pthread_t pThread;
|
||||
|
||||
OSStatus result = pthread_attr_init(&theThreadAttrs);
|
||||
THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")
|
||||
|
||||
result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
|
||||
THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")
|
||||
|
||||
result = pthread_create (&pThread, &theThreadAttrs, DiskReaderEntry, this);
|
||||
THROW_RESULT("pthread_create - Create and start the thread.")
|
||||
|
||||
pthread_attr_destroy(&theThreadAttrs);
|
||||
|
||||
// we've now created the thread and started it
|
||||
// we'll now set the priority of the thread to the nominated priority
|
||||
// and we'll also make the thread fixed
|
||||
thread_extended_policy_data_t theFixedPolicy;
|
||||
thread_precedence_policy_data_t thePrecedencePolicy;
|
||||
SInt32 relativePriority;
|
||||
|
||||
// make thread fixed
|
||||
theFixedPolicy.timeshare = false; // set to true for a non-fixed thread
|
||||
result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
|
||||
THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")
|
||||
// set priority
|
||||
// precedency policy's "importance" value is relative to spawning thread's priority
|
||||
relativePriority = mThreadPriority - FileReaderThread::GetThreadBasePriority (pthread_self());
|
||||
|
||||
thePrecedencePolicy.importance = relativePriority;
|
||||
result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
|
||||
THROW_RESULT("thread_policy - Couldn't set thread priority.")
|
||||
}
|
||||
|
||||
UInt32 FileReaderThread::GetThreadBasePriority (pthread_t inThread)
|
||||
{
|
||||
thread_basic_info_data_t threadInfo;
|
||||
policy_info_data_t thePolicyInfo;
|
||||
unsigned int count;
|
||||
|
||||
// get basic info
|
||||
count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count);
|
||||
|
||||
switch (threadInfo.policy) {
|
||||
case POLICY_TIMESHARE:
|
||||
count = POLICY_TIMESHARE_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
|
||||
return thePolicyInfo.ts.base_priority;
|
||||
break;
|
||||
|
||||
case POLICY_FIFO:
|
||||
count = POLICY_FIFO_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
|
||||
if (thePolicyInfo.fifo.depressed) {
|
||||
return thePolicyInfo.fifo.depress_priority;
|
||||
} else {
|
||||
return thePolicyInfo.fifo.base_priority;
|
||||
}
|
||||
break;
|
||||
|
||||
case POLICY_RR:
|
||||
count = POLICY_RR_INFO_COUNT;
|
||||
thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
|
||||
if (thePolicyInfo.rr.depressed) {
|
||||
return thePolicyInfo.rr.depress_priority;
|
||||
} else {
|
||||
return thePolicyInfo.rr.base_priority;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *FileReaderThread::DiskReaderEntry (void *inRefCon)
|
||||
{
|
||||
FileReaderThread *This = (FileReaderThread *)inRefCon;
|
||||
This->ReadNextChunk();
|
||||
#if DEBUG
|
||||
printf ("finished with reading file\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FileReaderThread::ReadNextChunk ()
|
||||
{
|
||||
OSStatus result;
|
||||
UInt32 dataChunkSize;
|
||||
AudioFileManager* theItem = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
{ // this is a scoped based lock
|
||||
CAGuard::Locker fileReadLock (mGuard);
|
||||
|
||||
if (this->mThreadShouldDie) {
|
||||
|
||||
mGuard.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFileData.empty())
|
||||
{
|
||||
mGuard.Wait();
|
||||
}
|
||||
|
||||
// kill thread
|
||||
if (this->mThreadShouldDie) {
|
||||
|
||||
mGuard.Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
theItem = mFileData.front();
|
||||
mFileData.pop_front();
|
||||
}
|
||||
|
||||
if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
|
||||
dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = theItem->mChunkSize;
|
||||
|
||||
// this is the exit condition for the thread
|
||||
if (dataChunkSize <= 0) {
|
||||
theItem->mFinishedReadingData = true;
|
||||
continue;
|
||||
}
|
||||
// construct pointer
|
||||
char* writePtr = const_cast<char*>(theItem->GetFileBuffer() +
|
||||
(theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
|
||||
|
||||
// read data
|
||||
result = theItem->Read(writePtr, &dataChunkSize);
|
||||
if (result != noErr && result != eofErr) {
|
||||
theItem->GetParent().DoNotification(result);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dataChunkSize != theItem->mChunkSize)
|
||||
{
|
||||
writePtr += dataChunkSize;
|
||||
|
||||
// can't exit yet.. we still have to pass the partial buffer back
|
||||
memset (writePtr, 0, (theItem->mChunkSize - dataChunkSize));
|
||||
}
|
||||
|
||||
theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; // switch buffers
|
||||
|
||||
if (result == eofErr)
|
||||
theItem->mReadFilePosition = theItem->mFileLength;
|
||||
else
|
||||
theItem->mReadFilePosition += dataChunkSize; // increment count
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FileReaderThread sReaderThread;
|
||||
|
||||
AudioFileManager::AudioFileManager (AudioFilePlayer &inParent,
|
||||
SInt16 inForkRefNum,
|
||||
SInt64 inFileLength,
|
||||
UInt32 inChunkSize)
|
||||
: mParent (inParent),
|
||||
mForkRefNum (inForkRefNum),
|
||||
mFileBuffer (0),
|
||||
mByteCounter (0),
|
||||
mLockUnsuccessful (false),
|
||||
mIsEngaged (false),
|
||||
|
||||
mBufferSize (inChunkSize),
|
||||
mBufferOffset (inChunkSize),
|
||||
mChunkSize (inChunkSize),
|
||||
mFileLength (inFileLength),
|
||||
mReadFilePosition (0),
|
||||
mWriteToFirstBuffer (false),
|
||||
mFinishedReadingData (false)
|
||||
|
||||
{
|
||||
mFileBuffer = (char*) malloc (mChunkSize * 2);
|
||||
FSGetForkPosition(mForkRefNum, &mAudioDataOffset);
|
||||
assert (mFileBuffer != NULL);
|
||||
}
|
||||
|
||||
void AudioFileManager::DoConnect ()
|
||||
{
|
||||
if (!mIsEngaged)
|
||||
{
|
||||
//mReadFilePosition = 0;
|
||||
mFinishedReadingData = false;
|
||||
|
||||
mNumTimesAskedSinceFinished = 0;
|
||||
mLockUnsuccessful = false;
|
||||
|
||||
OSStatus result;
|
||||
UInt32 dataChunkSize;
|
||||
|
||||
if ((mFileLength - mReadFilePosition) < mChunkSize)
|
||||
dataChunkSize = mFileLength - mReadFilePosition;
|
||||
else
|
||||
dataChunkSize = mChunkSize;
|
||||
|
||||
result = Read(mFileBuffer, &dataChunkSize);
|
||||
THROW_RESULT("AudioFileManager::DoConnect(): Read")
|
||||
|
||||
mReadFilePosition += dataChunkSize;
|
||||
|
||||
mWriteToFirstBuffer = false;
|
||||
mReadFromFirstBuffer = true;
|
||||
|
||||
sReaderThread.AddReader();
|
||||
|
||||
mIsEngaged = true;
|
||||
}
|
||||
else
|
||||
throw static_cast<OSStatus>(-1); //thread has already been started
|
||||
}
|
||||
|
||||
void AudioFileManager::Disconnect ()
|
||||
{
|
||||
if (mIsEngaged)
|
||||
{
|
||||
sReaderThread.RemoveReader (this);
|
||||
mIsEngaged = false;
|
||||
}
|
||||
}
|
||||
|
||||
OSStatus AudioFileManager::Read(char *buffer, UInt32 *len)
|
||||
{
|
||||
return FSReadFork (mForkRefNum,
|
||||
fsFromStart,
|
||||
mReadFilePosition + mAudioDataOffset,
|
||||
*len,
|
||||
buffer,
|
||||
len);
|
||||
}
|
||||
|
||||
OSStatus AudioFileManager::GetFileData (void** inOutData, UInt32 *inOutDataSize)
|
||||
{
|
||||
if (mFinishedReadingData)
|
||||
{
|
||||
++mNumTimesAskedSinceFinished;
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
if (mReadFromFirstBuffer == mWriteToFirstBuffer) {
|
||||
#if DEBUG
|
||||
printf ("* * * * * * * Can't keep up with reading file\n");
|
||||
#endif
|
||||
|
||||
mParent.DoNotification (kAudioFilePlayErr_FilePlayUnderrun);
|
||||
*inOutDataSize = 0;
|
||||
*inOutData = 0;
|
||||
} else {
|
||||
*inOutDataSize = mChunkSize;
|
||||
*inOutData = mReadFromFirstBuffer ? mFileBuffer : (mFileBuffer + mChunkSize);
|
||||
}
|
||||
|
||||
mLockUnsuccessful = !sReaderThread.TryNextRead (this);
|
||||
|
||||
mReadFromFirstBuffer = !mReadFromFirstBuffer;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void AudioFileManager::AfterRender ()
|
||||
{
|
||||
if (mNumTimesAskedSinceFinished > 0)
|
||||
{
|
||||
bool didLock = false;
|
||||
if (sReaderThread.GetGuard().Try (didLock)) {
|
||||
mParent.DoNotification (kAudioFilePlay_FileIsFinished);
|
||||
if (didLock)
|
||||
sReaderThread.GetGuard().Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (mLockUnsuccessful)
|
||||
mLockUnsuccessful = !sReaderThread.TryNextRead (this);
|
||||
}
|
||||
|
||||
void AudioFileManager::SetPosition (SInt64 pos)
|
||||
{
|
||||
if (pos < 0 || pos >= mFileLength) {
|
||||
SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n",
|
||||
(unsigned int)pos, (unsigned int)mFileLength);
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
mReadFilePosition = pos;
|
||||
}
|
||||
|
||||
void AudioFileManager::SetEndOfFile (SInt64 pos)
|
||||
{
|
||||
if (pos <= 0 || pos > mFileLength) {
|
||||
SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
|
||||
pos = mFileLength;
|
||||
}
|
||||
|
||||
mFileLength = pos;
|
||||
}
|
|
@ -22,10 +22,10 @@
|
|||
|
||||
#include "CDPlayer.h"
|
||||
#include "AudioFilePlayer.h"
|
||||
#include "CAGuard.h"
|
||||
#include "SDLOSXCAGuard.h"
|
||||
|
||||
// we're exporting these functions into C land for SDL_syscdrom.c
|
||||
extern "C" {
|
||||
//extern "C" {
|
||||
|
||||
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||||
// Constants
|
||||
|
@ -52,7 +52,7 @@ extern "C" {
|
|||
|
||||
#pragma mark -- Globals --
|
||||
|
||||
static bool playBackWasInit = false;
|
||||
static int playBackWasInit = 0;
|
||||
static AudioUnit theUnit;
|
||||
static AudioFilePlayer* thePlayer = NULL;
|
||||
static CDPlayerCompletionProc completionProc = NULL;
|
||||
|
@ -411,38 +411,40 @@ int LoadFile (const FSRef *ref, int startFrame, int stopFrame)
|
|||
printf ("LoadFile: %d %d\n", startFrame, stopFrame);
|
||||
#endif
|
||||
|
||||
try {
|
||||
//try {
|
||||
|
||||
// create a new player, and attach to the audio unit
|
||||
|
||||
thePlayer = new AudioFilePlayer(ref);
|
||||
thePlayer = new_AudioFilePlayer(ref);
|
||||
if (thePlayer == NULL) {
|
||||
SDL_SetError ("LoadFile: Could not create player");
|
||||
throw (-3);
|
||||
return -3; //throw (-3);
|
||||
}
|
||||
|
||||
thePlayer->SetDestination(theUnit);
|
||||
if (!thePlayer->SetDestination(thePlayer, &theUnit))
|
||||
goto bail;
|
||||
|
||||
if (startFrame >= 0)
|
||||
thePlayer->SetStartFrame (startFrame);
|
||||
thePlayer->SetStartFrame (thePlayer, startFrame);
|
||||
|
||||
if (stopFrame >= 0 && stopFrame > startFrame)
|
||||
thePlayer->SetStopFrame (stopFrame);
|
||||
thePlayer->SetStopFrame (thePlayer, stopFrame);
|
||||
|
||||
// we set the notifier later
|
||||
//thePlayer->SetNotifier(FilePlayNotificationHandler, NULL);
|
||||
//thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL);
|
||||
|
||||
thePlayer->Connect();
|
||||
if (!thePlayer->Connect(thePlayer))
|
||||
goto bail;
|
||||
|
||||
#if DEBUG_CDROM
|
||||
thePlayer->Print();
|
||||
thePlayer->Print(thePlayer);
|
||||
fflush (stdout);
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
//}
|
||||
//catch (...)
|
||||
//{
|
||||
// goto bail;
|
||||
//}
|
||||
|
||||
error = 0;
|
||||
|
||||
|
@ -458,24 +460,25 @@ int ReleaseFile ()
|
|||
{
|
||||
int error = -1;
|
||||
|
||||
try {
|
||||
// (Don't see any way that the original C++ code could throw here.) --ryan.
|
||||
//try {
|
||||
if (thePlayer != NULL) {
|
||||
|
||||
thePlayer->Disconnect();
|
||||
thePlayer->Disconnect(thePlayer);
|
||||
|
||||
delete thePlayer;
|
||||
delete_AudioFilePlayer(thePlayer);
|
||||
|
||||
thePlayer = NULL;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
//}
|
||||
//catch (...)
|
||||
//{
|
||||
// goto bail;
|
||||
//}
|
||||
|
||||
error = 0;
|
||||
|
||||
bail:
|
||||
// bail:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -490,17 +493,17 @@ int PlayFile ()
|
|||
if (CheckInit () < 0)
|
||||
goto bail;
|
||||
|
||||
try {
|
||||
// try {
|
||||
|
||||
// start processing of the audio unit
|
||||
result = AudioOutputUnitStart (theUnit);
|
||||
THROW_RESULT("PlayFile: AudioOutputUnitStart")
|
||||
if (result) goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart")
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// goto bail;
|
||||
// }
|
||||
|
||||
result = 0;
|
||||
|
||||
|
@ -519,16 +522,16 @@ int PauseFile ()
|
|||
if (CheckInit () < 0)
|
||||
goto bail;
|
||||
|
||||
try {
|
||||
//try {
|
||||
|
||||
// stop processing the audio unit
|
||||
result = AudioOutputUnitStop (theUnit);
|
||||
THROW_RESULT("PauseFile: AudioOutputUnitStop")
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
if (result) goto bail; //THROW_RESULT("PauseFile: AudioOutputUnitStop")
|
||||
//}
|
||||
//catch (...)
|
||||
//{
|
||||
// goto bail;
|
||||
//}
|
||||
|
||||
result = 0;
|
||||
bail:
|
||||
|
@ -545,7 +548,7 @@ void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom)
|
|||
|
||||
theCDROM = cdrom;
|
||||
completionProc = proc;
|
||||
thePlayer->SetNotifier (FilePlayNotificationHandler, cdrom);
|
||||
thePlayer->SetNotifier (thePlayer, FilePlayNotificationHandler, cdrom);
|
||||
}
|
||||
|
||||
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||||
|
@ -559,7 +562,7 @@ int GetCurrentFrame ()
|
|||
if (thePlayer == NULL)
|
||||
frame = 0;
|
||||
else
|
||||
frame = thePlayer->GetCurrentFrame ();
|
||||
frame = thePlayer->GetCurrentFrame (thePlayer);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
@ -580,7 +583,7 @@ static OSStatus CheckInit ()
|
|||
// Start callback thread
|
||||
SDL_CreateThread(RunCallBackThread, NULL);
|
||||
|
||||
try {
|
||||
{ //try {
|
||||
ComponentDescription desc;
|
||||
|
||||
desc.componentType = kAudioUnitComponentType;
|
||||
|
@ -592,23 +595,23 @@ static OSStatus CheckInit ()
|
|||
Component comp = FindNextComponent (NULL, &desc);
|
||||
if (comp == NULL) {
|
||||
SDL_SetError ("CheckInit: FindNextComponent returned NULL");
|
||||
throw(internalComponentErr);
|
||||
if (result) return -1; //throw(internalComponentErr);
|
||||
}
|
||||
|
||||
result = OpenAComponent (comp, &theUnit);
|
||||
THROW_RESULT("CheckInit: OpenAComponent")
|
||||
if (result) return -1; //THROW_RESULT("CheckInit: OpenAComponent")
|
||||
|
||||
// you need to initialize the output unit before you set it as a destination
|
||||
result = AudioUnitInitialize (theUnit);
|
||||
THROW_RESULT("CheckInit: AudioUnitInitialize")
|
||||
if (result) return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize")
|
||||
|
||||
|
||||
playBackWasInit = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
//catch (...)
|
||||
//{
|
||||
// return -1;
|
||||
//}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -657,4 +660,4 @@ static int RunCallBackThread (void *param)
|
|||
return 0;
|
||||
}
|
||||
|
||||
}; // extern "C"
|
||||
//}; // extern "C"
|
|
@ -9,9 +9,8 @@ SRCS = \
|
|||
SDL_syscdrom_c.h \
|
||||
SDL_syscdrom.c \
|
||||
AudioFilePlayer.h \
|
||||
AudioFilePlayer.cpp \
|
||||
AudioFileReaderThread.cpp \
|
||||
CAGuard.h \
|
||||
CAGuard.cpp \
|
||||
AudioFilePlayer.c \
|
||||
AudioFileReaderThread.c \
|
||||
SDLOSXCAGuard.c \
|
||||
CDPlayer.h \
|
||||
CDPlayer.cpp
|
||||
CDPlayer.c
|
||||
|
|
|
@ -69,92 +69,114 @@
|
|||
//=============================================================================
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define NDEBUG 1
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#include "CAGuard.h"
|
||||
#include "SDLOSXCAGuard.h"
|
||||
|
||||
//#warning Need a try-based Locker too
|
||||
//=============================================================================
|
||||
// CAGuard
|
||||
// SDLOSXCAGuard
|
||||
//=============================================================================
|
||||
|
||||
CAGuard::CAGuard()
|
||||
static int SDLOSXCAGuard_Lock(SDLOSXCAGuard *cag)
|
||||
{
|
||||
OSStatus theError = pthread_mutex_init(&mMutex, NULL);
|
||||
assert(theError == 0);
|
||||
int theAnswer = 0;
|
||||
|
||||
theError = pthread_cond_init(&mCondVar, NULL);
|
||||
assert(theError == 0);
|
||||
|
||||
mOwner = 0;
|
||||
}
|
||||
|
||||
CAGuard::~CAGuard()
|
||||
{
|
||||
pthread_mutex_destroy(&mMutex);
|
||||
pthread_cond_destroy(&mCondVar);
|
||||
}
|
||||
|
||||
bool CAGuard::Lock()
|
||||
{
|
||||
bool theAnswer = false;
|
||||
|
||||
if(pthread_self() != mOwner)
|
||||
if(pthread_self() != cag->mOwner)
|
||||
{
|
||||
OSStatus theError = pthread_mutex_lock(&mMutex);
|
||||
OSStatus theError = pthread_mutex_lock(&cag->mMutex);
|
||||
assert(theError == 0);
|
||||
mOwner = pthread_self();
|
||||
theAnswer = true;
|
||||
cag->mOwner = pthread_self();
|
||||
theAnswer = 1;
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAGuard::Unlock()
|
||||
static void SDLOSXCAGuard_Unlock(SDLOSXCAGuard *cag)
|
||||
{
|
||||
assert(pthread_self() == mOwner);
|
||||
assert(pthread_self() == cag->mOwner);
|
||||
|
||||
mOwner = 0;
|
||||
OSStatus theError = pthread_mutex_unlock(&mMutex);
|
||||
cag->mOwner = 0;
|
||||
OSStatus theError = pthread_mutex_unlock(&cag->mMutex);
|
||||
assert(theError == 0);
|
||||
}
|
||||
|
||||
bool CAGuard::Try (bool& outWasLocked)
|
||||
static int SDLOSXCAGuard_Try (SDLOSXCAGuard *cag, int *outWasLocked)
|
||||
{
|
||||
bool theAnswer = false;
|
||||
outWasLocked = false;
|
||||
int theAnswer = 0;
|
||||
*outWasLocked = 0;
|
||||
|
||||
if (pthread_self() == mOwner) {
|
||||
theAnswer = true;
|
||||
outWasLocked = false;
|
||||
if (pthread_self() == cag->mOwner) {
|
||||
theAnswer = 1;
|
||||
*outWasLocked = 0;
|
||||
} else {
|
||||
OSStatus theError = pthread_mutex_trylock(&mMutex);
|
||||
OSStatus theError = pthread_mutex_trylock(&cag->mMutex);
|
||||
if (theError == 0) {
|
||||
mOwner = pthread_self();
|
||||
theAnswer = true;
|
||||
outWasLocked = true;
|
||||
cag->mOwner = pthread_self();
|
||||
theAnswer = 1;
|
||||
*outWasLocked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return theAnswer;
|
||||
}
|
||||
|
||||
void CAGuard::Wait()
|
||||
static void SDLOSXCAGuard_Wait(SDLOSXCAGuard *cag)
|
||||
{
|
||||
assert(pthread_self() == mOwner);
|
||||
assert(pthread_self() == cag->mOwner);
|
||||
|
||||
mOwner = 0;
|
||||
cag->mOwner = 0;
|
||||
|
||||
OSStatus theError = pthread_cond_wait(&mCondVar, &mMutex);
|
||||
OSStatus theError = pthread_cond_wait(&cag->mCondVar, &cag->mMutex);
|
||||
assert(theError == 0);
|
||||
mOwner = pthread_self();
|
||||
cag->mOwner = pthread_self();
|
||||
}
|
||||
|
||||
void CAGuard::Notify()
|
||||
static void SDLOSXCAGuard_Notify(SDLOSXCAGuard *cag)
|
||||
{
|
||||
OSStatus theError = pthread_cond_signal(&mCondVar);
|
||||
OSStatus theError = pthread_cond_signal(&cag->mCondVar);
|
||||
assert(theError == 0);
|
||||
}
|
||||
|
||||
|
||||
SDLOSXCAGuard *new_SDLOSXCAGuard(void)
|
||||
{
|
||||
SDLOSXCAGuard *cag = (SDLOSXCAGuard *) malloc(sizeof (SDLOSXCAGuard));
|
||||
if (cag == NULL)
|
||||
return NULL;
|
||||
memset(cag, '\0', sizeof (*cag));
|
||||
|
||||
#define SET_SDLOSXCAGUARD_METHOD(m) cag->m = SDLOSXCAGuard_##m
|
||||
SET_SDLOSXCAGUARD_METHOD(Lock);
|
||||
SET_SDLOSXCAGUARD_METHOD(Unlock);
|
||||
SET_SDLOSXCAGUARD_METHOD(Try);
|
||||
SET_SDLOSXCAGUARD_METHOD(Wait);
|
||||
SET_SDLOSXCAGUARD_METHOD(Notify);
|
||||
#undef SET_SDLOSXCAGUARD_METHOD
|
||||
|
||||
OSStatus theError = pthread_mutex_init(&cag->mMutex, NULL);
|
||||
assert(theError == 0);
|
||||
|
||||
theError = pthread_cond_init(&cag->mCondVar, NULL);
|
||||
assert(theError == 0);
|
||||
|
||||
cag->mOwner = 0;
|
||||
return cag;
|
||||
}
|
||||
|
||||
void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag)
|
||||
{
|
||||
if (cag != NULL)
|
||||
{
|
||||
pthread_mutex_destroy(&cag->mMutex);
|
||||
pthread_cond_destroy(&cag->mCondVar);
|
||||
free(cag);
|
||||
}
|
||||
}
|
||||
|
|
@ -87,57 +87,28 @@
|
|||
// return false if they receive notification any other way.
|
||||
//=============================================================================
|
||||
|
||||
class CAGuard
|
||||
typedef struct S_SDLOSXCAGuard
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
CAGuard();
|
||||
virtual ~CAGuard();
|
||||
|
||||
//public:
|
||||
// Actions
|
||||
public:
|
||||
virtual bool Lock();
|
||||
virtual void Unlock();
|
||||
virtual bool Try(bool& outWasLocked); // returns true if lock is free, false if not
|
||||
|
||||
virtual void Wait();
|
||||
|
||||
virtual void Notify();
|
||||
//public:
|
||||
int (*Lock)(struct S_SDLOSXCAGuard *cag);
|
||||
void (*Unlock)(struct S_SDLOSXCAGuard *cag);
|
||||
int (*Try)(struct S_SDLOSXCAGuard *cag, int *outWasLocked); // returns true if lock is free, false if not
|
||||
void (*Wait)(struct S_SDLOSXCAGuard *cag);
|
||||
void (*Notify)(struct S_SDLOSXCAGuard *cag);
|
||||
|
||||
// Implementation
|
||||
protected:
|
||||
//protected:
|
||||
pthread_mutex_t mMutex;
|
||||
pthread_cond_t mCondVar;
|
||||
pthread_t mOwner;
|
||||
|
||||
// Helper class to manage taking and releasing recursively
|
||||
public:
|
||||
class Locker
|
||||
{
|
||||
|
||||
// Construction/Destruction
|
||||
public:
|
||||
Locker(CAGuard& inGuard) : mGuard(inGuard), mNeedsRelease(false) { mNeedsRelease = mGuard.Lock(); }
|
||||
~Locker() { if(mNeedsRelease) { mGuard.Unlock(); } }
|
||||
|
||||
private:
|
||||
Locker(const Locker&);
|
||||
Locker& operator=(const Locker&);
|
||||
|
||||
// Actions
|
||||
public:
|
||||
void Wait() { mGuard.Wait(); }
|
||||
|
||||
void Notify() { mGuard.Notify(); }
|
||||
} SDLOSXCAGuard;
|
||||
|
||||
// Implementation
|
||||
private:
|
||||
CAGuard& mGuard;
|
||||
bool mNeedsRelease;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
SDLOSXCAGuard *new_SDLOSXCAGuard(void);
|
||||
void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag);
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue