diff --git a/src/cdrom/macosx/AudioFilePlayer.c b/src/cdrom/macosx/AudioFilePlayer.c new file mode 100644 index 000000000..8e3b895a1 --- /dev/null +++ b/src/cdrom/macosx/AudioFilePlayer.c @@ -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(-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; +} + diff --git a/src/cdrom/macosx/AudioFilePlayer.cpp b/src/cdrom/macosx/AudioFilePlayer.cpp deleted file mode 100644 index 96ccd07ec..000000000 --- a/src/cdrom/macosx/AudioFilePlayer.cpp +++ /dev/null @@ -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(-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(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; -} diff --git a/src/cdrom/macosx/AudioFilePlayer.h b/src/cdrom/macosx/AudioFilePlayer.h index f45b7faf7..3b1c37a5c 100644 --- a/src/cdrom/macosx/AudioFilePlayer.h +++ b/src/cdrom/macosx/AudioFilePlayer.h @@ -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 + diff --git a/src/cdrom/macosx/AudioFileReaderThread.c b/src/cdrom/macosx/AudioFileReaderThread.c new file mode 100644 index 000000000..5e7d98a6e --- /dev/null +++ b/src/cdrom/macosx/AudioFileReaderThread.c @@ -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 //used for setting policy of thread +#include "SDLOSXCAGuard.h" +#include + +//#include + +//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 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(-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; +} + diff --git a/src/cdrom/macosx/AudioFileReaderThread.cpp b/src/cdrom/macosx/AudioFileReaderThread.cpp deleted file mode 100644 index f9b6c58ef..000000000 --- a/src/cdrom/macosx/AudioFileReaderThread.cpp +++ /dev/null @@ -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 //used for setting policy of thread -#include "CAGuard.h" -#include - -#include - -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 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(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(-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; -} diff --git a/src/cdrom/macosx/CDPlayer.cpp b/src/cdrom/macosx/CDPlayer.c similarity index 91% rename from src/cdrom/macosx/CDPlayer.cpp rename to src/cdrom/macosx/CDPlayer.c index 61bdc9f16..8a5a22f2c 100644 --- a/src/cdrom/macosx/CDPlayer.cpp +++ b/src/cdrom/macosx/CDPlayer.c @@ -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" diff --git a/src/cdrom/macosx/Makefile.am b/src/cdrom/macosx/Makefile.am index 0fa0b0672..062c2d19b 100644 --- a/src/cdrom/macosx/Makefile.am +++ b/src/cdrom/macosx/Makefile.am @@ -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 diff --git a/src/cdrom/macosx/CAGuard.cpp b/src/cdrom/macosx/SDLOSXCAGuard.c similarity index 69% rename from src/cdrom/macosx/CAGuard.cpp rename to src/cdrom/macosx/SDLOSXCAGuard.c index b7574127b..fff923e1f 100644 --- a/src/cdrom/macosx/CAGuard.cpp +++ b/src/cdrom/macosx/SDLOSXCAGuard.c @@ -69,92 +69,114 @@ //============================================================================= #include +#include +#include //#define NDEBUG 1 #include -#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); + } +} + diff --git a/src/cdrom/macosx/CAGuard.h b/src/cdrom/macosx/SDLOSXCAGuard.h similarity index 82% rename from src/cdrom/macosx/CAGuard.h rename to src/cdrom/macosx/SDLOSXCAGuard.h index d99c7959e..d5e5b164e 100644 --- a/src/cdrom/macosx/CAGuard.h +++ b/src/cdrom/macosx/SDLOSXCAGuard.h @@ -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 +