aboutsummaryrefslogtreecommitdiffstats
path: root/distrib/sdl-1.2.15/src/cdrom/macosx
diff options
context:
space:
mode:
Diffstat (limited to 'distrib/sdl-1.2.15/src/cdrom/macosx')
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c360
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.h178
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/AudioFileReaderThread.c610
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.c636
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.h69
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.c199
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.h116
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom.c514
-rw-r--r--distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom_c.h136
9 files changed, 2818 insertions, 0 deletions
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c
new file mode 100644
index 0000000..97cb9b2
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.c
@@ -0,0 +1,360 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+#include "SDL_endian.h"
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 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 ;
+
+ SDL_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 != kAudioUnitType_Output) {
+ 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) {
+ FSCloseFork (afp->mForkRefNum);
+ afp->mForkRefNum = 0;
+ }
+ SDL_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_SetRenderCallback,
+ 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_SetRenderCallback,
+ 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 (SDL_SwapBE32(chunkHeader.ckID) != 'FORM') {
+ result = -1;
+ if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");*/
+ }
+
+ if (SDL_SwapBE32(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")*/
+
+ chunk.ckID = SDL_SwapBE32(chunk.ckID);
+ chunk.ckSize = SDL_SwapBE32(chunk.ckSize);
+
+ /* 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")*/
+
+ ssndData.offset = SDL_SwapBE32(ssndData.offset);
+
+ 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 *) SDL_malloc(sizeof (AudioFilePlayer));
+ if (afp == NULL)
+ return NULL;
+ SDL_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))
+ {
+ SDL_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/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.h b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.h
new file mode 100644
index 0000000..886d017
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFilePlayer.h
@@ -0,0 +1,178 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ AudioFilePlayer.h
+*/
+#ifndef __AudioFilePlayer_H__
+#define __AudioFilePlayer_H__
+
+#include <CoreServices/CoreServices.h>
+
+#include <AudioUnit/AudioUnit.h>
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
+#include <AudioUnit/AUNTComponent.h>
+#endif
+
+#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1050)
+typedef SInt16 FSIORefNum;
+#endif
+
+#include "SDL_error.h"
+
+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);
+
+enum {
+ kAudioFilePlayErr_FilePlayUnderrun = -10000,
+ kAudioFilePlay_FileIsFinished = -10001,
+ kAudioFilePlay_PlayerIsUninitialized = -10002
+};
+
+
+struct S_AudioFileManager;
+
+#pragma mark __________ AudioFilePlayer
+typedef struct S_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);
+
+/*private:*/
+ AudioUnit mPlayUnit;
+ FSIORefNum mForkRefNum;
+
+ AURenderCallbackStruct mInputCallback;
+
+ AudioStreamBasicDescription mFileDescription;
+
+ int mConnected;
+
+ struct S_AudioFileManager* mAudioFileManager;
+
+ AudioFilePlayNotifier mNotifier;
+ void* mRefCon;
+
+ int mStartFrame;
+
+#pragma mark __________ Private_Methods
+
+ 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
+typedef struct S_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)(struct S_AudioFileManager *afm);
+ int (*DoConnect)(struct S_AudioFileManager *afm);
+ OSStatus (*Read)(struct S_AudioFileManager *afm, char *buffer, ByteCount *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;
+ SInt16 mForkRefNum;
+ SInt64 mAudioDataOffset;
+
+ char* mFileBuffer;
+
+ int mByteCounter;
+
+ int mReadFromFirstBuffer;
+ int mLockUnsuccessful;
+ int mIsEngaged;
+
+ int mNumTimesAskedSinceFinished;
+
+
+ void* mTmpBuffer;
+ UInt32 mBufferSize;
+ UInt32 mBufferOffset;
+/*public:*/
+ UInt32 mChunkSize;
+ SInt64 mFileLength;
+ SInt64 mReadFilePosition;
+ int mWriteToFirstBuffer;
+ int mFinishedReadingData;
+
+/*protected:*/
+ OSStatus (*Render)(struct S_AudioFileManager *afm, AudioBufferList *ioData);
+ OSStatus (*GetFileData)(struct S_AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize);
+ void (*AfterRender)(struct S_AudioFileManager *afm);
+
+/*public:*/
+ /*static*/
+ OSStatus (*FileInputProc)(void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData);
+} AudioFileManager;
+
+
+AudioFileManager *new_AudioFileManager (AudioFilePlayer *inParent,
+ SInt16 inForkRefNum,
+ SInt64 inFileLength,
+ UInt32 inChunkSize);
+
+void delete_AudioFileManager(AudioFileManager *afm);
+
+#endif
+
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFileReaderThread.c b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFileReaderThread.c
new file mode 100644
index 0000000..0007c07
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/AudioFileReaderThread.c
@@ -0,0 +1,610 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 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 *) SDL_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;
+ SDL_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;
+ ByteCount 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;
+ SDL_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 */
+ SDL_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);
+ SDL_free(frt);
+ }
+}
+
+FileReaderThread *new_FileReaderThread ()
+{
+ FileReaderThread *frt = (FileReaderThread *) SDL_malloc(sizeof (FileReaderThread));
+ if (frt == NULL)
+ return NULL;
+ SDL_memset(frt, '\0', sizeof (*frt));
+
+ frt->mGuard = new_SDLOSXCAGuard();
+ if (frt->mGuard == NULL)
+ {
+ SDL_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)
+ {
+ OSStatus result;
+
+ /*afm->mReadFilePosition = 0;*/
+ afm->mFinishedReadingData = 0;
+
+ afm->mNumTimesAskedSinceFinished = 0;
+ afm->mLockUnsuccessful = 0;
+
+ ByteCount 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, ByteCount *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 *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData)
+{
+ AudioFileManager* afm = (AudioFileManager*)inRefCon;
+ return afm->Render(afm, ioData);
+}
+
+static OSStatus AudioFileManager_Render (AudioFileManager *afm, AudioBufferList *ioData)
+{
+ OSStatus result = noErr;
+ AudioBuffer *abuf;
+ UInt32 i;
+
+ for (i = 0; i < ioData->mNumberBuffers; i++) {
+ abuf = &ioData->mBuffers[i];
+ 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 (abuf->mDataByteSize > afm->mBufferSize - afm->mBufferOffset)
+ abuf->mDataByteSize = afm->mBufferSize - afm->mBufferOffset;
+ abuf->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset;
+ afm->mBufferOffset += abuf->mDataByteSize;
+
+ afm->mByteCounter += abuf->mDataByteSize;
+ afm->AfterRender(afm);
+ }
+ return result;
+}
+
+
+void delete_AudioFileManager (AudioFileManager *afm)
+{
+ if (afm != NULL) {
+ if (afm->mFileBuffer) {
+ free(afm->mFileBuffer);
+ }
+
+ SDL_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 *) SDL_malloc(sizeof (AudioFileManager));
+ if (afm == NULL)
+ return NULL;
+ SDL_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*) SDL_malloc(afm->mChunkSize * 2);
+ FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset);
+ assert (afm->mFileBuffer != NULL);
+ return afm;
+}
+
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.c b/distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.c
new file mode 100644
index 0000000..beb87cd
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.c
@@ -0,0 +1,636 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+
+#include "CDPlayer.h"
+#include "AudioFilePlayer.h"
+#include "SDLOSXCAGuard.h"
+
+/* we're exporting these functions into C land for SDL_syscdrom.c */
+/*extern "C" {*/
+
+/*///////////////////////////////////////////////////////////////////////////
+ Constants
+ //////////////////////////////////////////////////////////////////////////*/
+
+#define kAudioCDFilesystemID (UInt16)(('J' << 8) | 'H') /* 'JH'; this avoids compiler warning */
+
+/* XML PList keys */
+#define kRawTOCDataString "Format 0x02 TOC Data"
+#define kSessionsString "Sessions"
+#define kSessionTypeString "Session Type"
+#define kTrackArrayString "Track Array"
+#define kFirstTrackInSessionString "First Track"
+#define kLastTrackInSessionString "Last Track"
+#define kLeadoutBlockString "Leadout Block"
+#define kDataKeyString "Data"
+#define kPointKeyString "Point"
+#define kSessionNumberKeyString "Session Number"
+#define kStartBlockKeyString "Start Block"
+
+/*///////////////////////////////////////////////////////////////////////////
+ Globals
+ //////////////////////////////////////////////////////////////////////////*/
+
+#pragma mark -- Globals --
+
+static int playBackWasInit = 0;
+static AudioUnit theUnit;
+static AudioFilePlayer* thePlayer = NULL;
+static CDPlayerCompletionProc completionProc = NULL;
+static SDL_mutex *apiMutex = NULL;
+static SDL_sem *callbackSem;
+static SDL_CD* theCDROM;
+
+/*///////////////////////////////////////////////////////////////////////////
+ Prototypes
+ //////////////////////////////////////////////////////////////////////////*/
+
+#pragma mark -- Prototypes --
+
+static OSStatus CheckInit ();
+
+static void FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus);
+
+static int RunCallBackThread (void* inRefCon);
+
+
+#pragma mark -- Public Functions --
+
+void Lock ()
+{
+ if (!apiMutex) {
+ apiMutex = SDL_CreateMutex();
+ }
+ SDL_mutexP(apiMutex);
+}
+
+void Unlock ()
+{
+ SDL_mutexV(apiMutex);
+}
+
+int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes)
+{
+ int volumeIndex;
+ int cdVolumeCount = 0;
+ OSStatus result = noErr;
+
+ for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++)
+ {
+ FSVolumeRefNum actualVolume;
+ FSVolumeInfo volumeInfo;
+
+ memset (&volumeInfo, 0, sizeof(volumeInfo));
+
+ result = FSGetVolumeInfo (kFSInvalidVolumeRefNum,
+ volumeIndex,
+ &actualVolume,
+ kFSVolInfoFSInfo,
+ &volumeInfo,
+ NULL,
+ NULL);
+
+ if (result == noErr)
+ {
+ if (volumeInfo.filesystemID == kAudioCDFilesystemID) /* It's an audio CD */
+ {
+ if (volumes != NULL && cdVolumeCount < numVolumes)
+ volumes[cdVolumeCount] = actualVolume;
+
+ cdVolumeCount++;
+ }
+ }
+ else
+ {
+ /* I'm commenting this out because it seems to be harmless */
+ /*SDL_SetError ("DetectAudioCDVolumes: FSGetVolumeInfo returned %d", result);*/
+ }
+ }
+
+ return cdVolumeCount;
+}
+
+int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD)
+{
+ HFSUniStr255 dataForkName;
+ OSStatus theErr;
+ FSIORefNum forkRefNum;
+ SInt64 forkSize;
+ Ptr forkData = 0;
+ ByteCount actualRead;
+ CFDataRef dataRef = 0;
+ CFPropertyListRef propertyListRef = 0;
+ FSRefParam fsRefPB;
+ FSRef tocPlistFSRef;
+ FSRef rootRef;
+ const char* error = "Unspecified Error";
+ const UniChar uniName[] = { '.','T','O','C','.','p','l','i','s','t' };
+
+ theErr = FSGetVolumeInfo(theVolume, 0, 0, kFSVolInfoNone, 0, 0, &rootRef);
+ if(theErr != noErr) {
+ error = "FSGetVolumeInfo";
+ goto bail;
+ }
+
+ SDL_memset(&fsRefPB, '\0', sizeof (fsRefPB));
+
+ /* get stuff from .TOC.plist */
+ fsRefPB.ref = &rootRef;
+ fsRefPB.newRef = &tocPlistFSRef;
+ fsRefPB.nameLength = sizeof (uniName) / sizeof (uniName[0]);
+ fsRefPB.name = uniName;
+ fsRefPB.textEncodingHint = kTextEncodingUnknown;
+
+ theErr = PBMakeFSRefUnicodeSync (&fsRefPB);
+ if(theErr != noErr) {
+ error = "PBMakeFSRefUnicodeSync";
+ goto bail;
+ }
+
+ /* Load and parse the TOC XML data */
+
+ theErr = FSGetDataForkName (&dataForkName);
+ if (theErr != noErr) {
+ error = "FSGetDataForkName";
+ goto bail;
+ }
+
+ theErr = FSOpenFork (&tocPlistFSRef, dataForkName.length, dataForkName.unicode, fsRdPerm, &forkRefNum);
+ if (theErr != noErr) {
+ error = "FSOpenFork";
+ goto bail;
+ }
+
+ theErr = FSGetForkSize (forkRefNum, &forkSize);
+ if (theErr != noErr) {
+ error = "FSGetForkSize";
+ goto bail;
+ }
+
+ /* Allocate some memory for the XML data */
+ forkData = NewPtr (forkSize);
+ if(forkData == NULL) {
+ error = "NewPtr";
+ goto bail;
+ }
+
+ theErr = FSReadFork (forkRefNum, fsFromStart, 0 /* offset location */, forkSize, forkData, &actualRead);
+ if(theErr != noErr) {
+ error = "FSReadFork";
+ goto bail;
+ }
+
+ dataRef = CFDataCreate (kCFAllocatorDefault, (UInt8 *)forkData, forkSize);
+ if(dataRef == 0) {
+ error = "CFDataCreate";
+ goto bail;
+ }
+
+ propertyListRef = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
+ dataRef,
+ kCFPropertyListImmutable,
+ NULL);
+ if (propertyListRef == NULL) {
+ error = "CFPropertyListCreateFromXMLData";
+ goto bail;
+ }
+
+ /* Now we got the Property List in memory. Parse it. */
+
+ /* First, make sure the root item is a CFDictionary. If not, release and bail. */
+ if(CFGetTypeID(propertyListRef)== CFDictionaryGetTypeID())
+ {
+ CFDictionaryRef dictRef = (CFDictionaryRef)propertyListRef;
+
+ CFDataRef theRawTOCDataRef;
+ CFArrayRef theSessionArrayRef;
+ CFIndex numSessions;
+ CFIndex index;
+
+ /* This is how we get the Raw TOC Data */
+ theRawTOCDataRef = (CFDataRef)CFDictionaryGetValue (dictRef, CFSTR(kRawTOCDataString));
+
+ /* Get the session array info. */
+ theSessionArrayRef = (CFArrayRef)CFDictionaryGetValue (dictRef, CFSTR(kSessionsString));
+
+ /* Find out how many sessions there are. */
+ numSessions = CFArrayGetCount (theSessionArrayRef);
+
+ /* Initialize the total number of tracks to 0 */
+ theCD->numtracks = 0;
+
+ /* Iterate over all sessions, collecting the track data */
+ for(index = 0; index < numSessions; index++)
+ {
+ CFDictionaryRef theSessionDict;
+ CFNumberRef leadoutBlock;
+ CFArrayRef trackArray;
+ CFIndex numTracks;
+ CFIndex trackIndex;
+ UInt32 value = 0;
+
+ theSessionDict = (CFDictionaryRef) CFArrayGetValueAtIndex (theSessionArrayRef, index);
+ leadoutBlock = (CFNumberRef) CFDictionaryGetValue (theSessionDict, CFSTR(kLeadoutBlockString));
+
+ trackArray = (CFArrayRef)CFDictionaryGetValue (theSessionDict, CFSTR(kTrackArrayString));
+
+ numTracks = CFArrayGetCount (trackArray);
+
+ for(trackIndex = 0; trackIndex < numTracks; trackIndex++) {
+
+ CFDictionaryRef theTrackDict;
+ CFNumberRef trackNumber;
+ CFNumberRef sessionNumber;
+ CFNumberRef startBlock;
+ CFBooleanRef isDataTrack;
+ UInt32 value;
+
+ theTrackDict = (CFDictionaryRef) CFArrayGetValueAtIndex (trackArray, trackIndex);
+
+ trackNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kPointKeyString));
+ sessionNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kSessionNumberKeyString));
+ startBlock = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kStartBlockKeyString));
+ isDataTrack = (CFBooleanRef) CFDictionaryGetValue (theTrackDict, CFSTR(kDataKeyString));
+
+ /* Fill in the SDL_CD struct */
+ int idx = theCD->numtracks++;
+
+ CFNumberGetValue (trackNumber, kCFNumberSInt32Type, &value);
+ theCD->track[idx].id = value;
+
+ CFNumberGetValue (startBlock, kCFNumberSInt32Type, &value);
+ theCD->track[idx].offset = value;
+
+ theCD->track[idx].type = (isDataTrack == kCFBooleanTrue) ? SDL_DATA_TRACK : SDL_AUDIO_TRACK;
+
+ /* Since the track lengths are not stored in .TOC.plist we compute them. */
+ if (trackIndex > 0) {
+ theCD->track[idx-1].length = theCD->track[idx].offset - theCD->track[idx-1].offset;
+ }
+ }
+
+ /* Compute the length of the last track */
+ CFNumberGetValue (leadoutBlock, kCFNumberSInt32Type, &value);
+
+ theCD->track[theCD->numtracks-1].length =
+ value - theCD->track[theCD->numtracks-1].offset;
+
+ /* Set offset to leadout track */
+ theCD->track[theCD->numtracks].offset = value;
+ }
+
+ }
+
+ theErr = 0;
+ goto cleanup;
+bail:
+ SDL_SetError ("ReadTOCData: %s returned %d", error, theErr);
+ theErr = -1;
+cleanup:
+
+ if (propertyListRef != NULL)
+ CFRelease(propertyListRef);
+ if (dataRef != NULL)
+ CFRelease(dataRef);
+ if (forkData != NULL)
+ DisposePtr(forkData);
+
+ FSCloseFork (forkRefNum);
+
+ return theErr;
+}
+
+int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks)
+{
+ OSStatus result = -1;
+ FSIterator iterator;
+ ItemCount actualObjects;
+ FSRef rootDirectory;
+ FSRef ref;
+ HFSUniStr255 nameStr;
+
+ result = FSGetVolumeInfo (theVolume,
+ 0,
+ NULL,
+ kFSVolInfoFSInfo,
+ NULL,
+ NULL,
+ &rootDirectory);
+
+ if (result != noErr) {
+ SDL_SetError ("ListTrackFiles: FSGetVolumeInfo returned %d", result);
+ return result;
+ }
+
+ result = FSOpenIterator (&rootDirectory, kFSIterateFlat, &iterator);
+ if (result == noErr) {
+ do
+ {
+ result = FSGetCatalogInfoBulk (iterator, 1, &actualObjects,
+ NULL, kFSCatInfoNone, NULL, &ref, NULL, &nameStr);
+ if (result == noErr) {
+
+ CFStringRef name;
+ name = CFStringCreateWithCharacters (NULL, nameStr.unicode, nameStr.length);
+
+ /* Look for .aiff extension */
+ if (CFStringHasSuffix (name, CFSTR(".aiff")) ||
+ CFStringHasSuffix (name, CFSTR(".cdda"))) {
+
+ /* Extract the track id from the filename */
+ int trackID = 0, i = 0;
+ while (i < nameStr.length && !isdigit(nameStr.unicode[i])) {
+ ++i;
+ }
+ while (i < nameStr.length && isdigit(nameStr.unicode[i])) {
+ trackID = 10 * trackID +(nameStr.unicode[i] - '0');
+ ++i;
+ }
+
+ #if DEBUG_CDROM
+ printf("Found AIFF for track %d: '%s'\n", trackID,
+ CFStringGetCStringPtr (name, CFStringGetSystemEncoding()));
+ #endif
+
+ /* Track ID's start at 1, but we want to start at 0 */
+ trackID--;
+
+ assert(0 <= trackID && trackID <= SDL_MAX_TRACKS);
+
+ if (trackID < numTracks)
+ memcpy (&trackFiles[trackID], &ref, sizeof(FSRef));
+ }
+ CFRelease (name);
+ }
+ } while(noErr == result);
+ FSCloseIterator (iterator);
+ }
+
+ return 0;
+}
+
+int LoadFile (const FSRef *ref, int startFrame, int stopFrame)
+{
+ int error = -1;
+
+ if (CheckInit () < 0)
+ goto bail;
+
+ /* release any currently playing file */
+ if (ReleaseFile () < 0)
+ goto bail;
+
+ #if DEBUG_CDROM
+ printf ("LoadFile: %d %d\n", startFrame, stopFrame);
+ #endif
+
+ /*try {*/
+
+ /* create a new player, and attach to the audio unit */
+
+ thePlayer = new_AudioFilePlayer(ref);
+ if (thePlayer == NULL) {
+ SDL_SetError ("LoadFile: Could not create player");
+ return -3; /*throw (-3);*/
+ }
+
+ if (!thePlayer->SetDestination(thePlayer, &theUnit))
+ goto bail;
+
+ if (startFrame >= 0)
+ thePlayer->SetStartFrame (thePlayer, startFrame);
+
+ if (stopFrame >= 0 && stopFrame > startFrame)
+ thePlayer->SetStopFrame (thePlayer, stopFrame);
+
+ /* we set the notifier later */
+ /*thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL);*/
+
+ if (!thePlayer->Connect(thePlayer))
+ goto bail;
+
+ #if DEBUG_CDROM
+ thePlayer->Print(thePlayer);
+ fflush (stdout);
+ #endif
+ /*}
+ catch (...)
+ {
+ goto bail;
+ }*/
+
+ error = 0;
+
+ bail:
+ return error;
+}
+
+int ReleaseFile ()
+{
+ int error = -1;
+
+ /* (Don't see any way that the original C++ code could throw here.) --ryan. */
+ /*try {*/
+ if (thePlayer != NULL) {
+
+ thePlayer->Disconnect(thePlayer);
+
+ delete_AudioFilePlayer(thePlayer);
+
+ thePlayer = NULL;
+ }
+ /*}
+ catch (...)
+ {
+ goto bail;
+ }*/
+
+ error = 0;
+
+/* bail: */
+ return error;
+}
+
+int PlayFile ()
+{
+ OSStatus result = -1;
+
+ if (CheckInit () < 0)
+ goto bail;
+
+ /*try {*/
+
+ // start processing of the audio unit
+ result = AudioOutputUnitStart (theUnit);
+ if (result) goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart")
+
+ /*}
+ catch (...)
+ {
+ goto bail;
+ }*/
+
+ result = 0;
+
+bail:
+ return result;
+}
+
+int PauseFile ()
+{
+ OSStatus result = -1;
+
+ if (CheckInit () < 0)
+ goto bail;
+
+ /*try {*/
+
+ /* stop processing the audio unit */
+ result = AudioOutputUnitStop (theUnit);
+ if (result) goto bail; /*THROW_RESULT("PauseFile: AudioOutputUnitStop")*/
+ /*}
+ catch (...)
+ {
+ goto bail;
+ }*/
+
+ result = 0;
+bail:
+ return result;
+}
+
+void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom)
+{
+ assert(thePlayer != NULL);
+
+ theCDROM = cdrom;
+ completionProc = proc;
+ thePlayer->SetNotifier (thePlayer, FilePlayNotificationHandler, cdrom);
+}
+
+int GetCurrentFrame ()
+{
+ int frame;
+
+ if (thePlayer == NULL)
+ frame = 0;
+ else
+ frame = thePlayer->GetCurrentFrame (thePlayer);
+
+ return frame;
+}
+
+
+#pragma mark -- Private Functions --
+
+static OSStatus CheckInit ()
+{
+ if (playBackWasInit)
+ return 0;
+
+ OSStatus result = noErr;
+
+ /* Create the callback semaphore */
+ callbackSem = SDL_CreateSemaphore(0);
+
+ /* Start callback thread */
+ SDL_CreateThread(RunCallBackThread, NULL);
+
+ { /*try {*/
+ ComponentDescription desc;
+
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+
+ Component comp = FindNextComponent (NULL, &desc);
+ if (comp == NULL) {
+ SDL_SetError ("CheckInit: FindNextComponent returned NULL");
+ if (result) return -1; //throw(internalComponentErr);
+ }
+
+ result = OpenAComponent (comp, &theUnit);
+ 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);
+ if (result) return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize")
+
+
+ playBackWasInit = true;
+ }
+ /*catch (...)
+ {
+ return -1;
+ }*/
+
+ return 0;
+}
+
+static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus)
+{
+ if (inStatus == kAudioFilePlay_FileIsFinished) {
+
+ /* notify non-CA thread to perform the callback */
+ SDL_SemPost(callbackSem);
+
+ } else if (inStatus == kAudioFilePlayErr_FilePlayUnderrun) {
+
+ SDL_SetError ("CDPlayer Notification: buffer underrun");
+ } else if (inStatus == kAudioFilePlay_PlayerIsUninitialized) {
+
+ SDL_SetError ("CDPlayer Notification: player is uninitialized");
+ } else {
+
+ SDL_SetError ("CDPlayer Notification: unknown error %ld", inStatus);
+ }
+}
+
+static int RunCallBackThread (void *param)
+{
+ for (;;) {
+
+ SDL_SemWait(callbackSem);
+
+ if (completionProc && theCDROM) {
+ #if DEBUG_CDROM
+ printf ("callback!\n");
+ #endif
+ (*completionProc)(theCDROM);
+ } else {
+ #if DEBUG_CDROM
+ printf ("callback?\n");
+ #endif
+ }
+ }
+
+ #if DEBUG_CDROM
+ printf ("thread dying now...\n");
+ #endif
+
+ return 0;
+}
+
+/*}; // extern "C" */
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.h b/distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.h
new file mode 100644
index 0000000..be1ac18
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/CDPlayer.h
@@ -0,0 +1,69 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+
+#ifndef __CDPlayer__H__
+#define __CDPlayer__H__ 1
+
+#include <string.h>
+
+#include <Carbon/Carbon.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <AudioUnit/AudioUnit.h>
+
+#include "SDL.h"
+#include "SDL_thread.h"
+#include "SDL_mutex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*CDPlayerCompletionProc)(SDL_CD *cdrom) ;
+
+void Lock ();
+
+void Unlock();
+
+int LoadFile (const FSRef *ref, int startFrame, int endFrame); /* pass -1 to do nothing */
+
+int ReleaseFile ();
+
+int PlayFile ();
+
+int PauseFile ();
+
+void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom);
+
+int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD);
+
+int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks);
+
+int DetectAudioCDVolumes (FSVolumeRefNum *volumes, int numVolumes);
+
+int GetCurrentFrame ();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __CD_Player__H__ */
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.c b/distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.c
new file mode 100644
index 0000000..e8caf1b
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.c
@@ -0,0 +1,199 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+
+/*
+ Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
+
+ Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CAGuard.cp
+
+=============================================================================*/
+
+/*=============================================================================
+ Includes
+ =============================================================================*/
+
+/*
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+*/
+#include "SDL_stdinc.h"
+
+/*#define NDEBUG 1*/
+/*
+#include <assert.h>
+*/
+#define assert(X)
+
+
+#include "SDLOSXCAGuard.h"
+
+/*#warning Need a try-based Locker too*/
+/*=============================================================================
+ SDLOSXCAGuard
+ =============================================================================*/
+
+static int SDLOSXCAGuard_Lock(SDLOSXCAGuard *cag)
+{
+ int theAnswer = 0;
+
+ if(pthread_self() != cag->mOwner)
+ {
+ OSStatus theError = pthread_mutex_lock(&cag->mMutex);
+ (void)theError;
+ assert(theError == 0);
+ cag->mOwner = pthread_self();
+ theAnswer = 1;
+ }
+
+ return theAnswer;
+}
+
+static void SDLOSXCAGuard_Unlock(SDLOSXCAGuard *cag)
+{
+ OSStatus theError;
+ assert(pthread_self() == cag->mOwner);
+
+ cag->mOwner = 0;
+ theError = pthread_mutex_unlock(&cag->mMutex);
+ (void)theError;
+ assert(theError == 0);
+}
+
+static int SDLOSXCAGuard_Try (SDLOSXCAGuard *cag, int *outWasLocked)
+{
+ int theAnswer = 0;
+ *outWasLocked = 0;
+
+ if (pthread_self() == cag->mOwner) {
+ theAnswer = 1;
+ *outWasLocked = 0;
+ } else {
+ OSStatus theError = pthread_mutex_trylock(&cag->mMutex);
+ if (theError == 0) {
+ cag->mOwner = pthread_self();
+ theAnswer = 1;
+ *outWasLocked = 1;
+ }
+ }
+
+ return theAnswer;
+}
+
+static void SDLOSXCAGuard_Wait(SDLOSXCAGuard *cag)
+{
+ OSStatus theError;
+ assert(pthread_self() == cag->mOwner);
+
+ cag->mOwner = 0;
+
+ theError = pthread_cond_wait(&cag->mCondVar, &cag->mMutex);
+ (void)theError;
+ assert(theError == 0);
+ cag->mOwner = pthread_self();
+}
+
+static void SDLOSXCAGuard_Notify(SDLOSXCAGuard *cag)
+{
+ OSStatus theError = pthread_cond_signal(&cag->mCondVar);
+ (void)theError;
+ assert(theError == 0);
+}
+
+
+SDLOSXCAGuard *new_SDLOSXCAGuard(void)
+{
+ OSStatus theError;
+ SDLOSXCAGuard *cag = (SDLOSXCAGuard *) SDL_malloc(sizeof (SDLOSXCAGuard));
+ if (cag == NULL)
+ return NULL;
+ SDL_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
+
+ theError = pthread_mutex_init(&cag->mMutex, NULL);
+ (void)theError;
+ assert(theError == 0);
+
+ theError = pthread_cond_init(&cag->mCondVar, NULL);
+ (void)theError;
+ 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);
+ SDL_free(cag);
+ }
+}
+
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.h b/distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.h
new file mode 100644
index 0000000..f22c695
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/SDLOSXCAGuard.h
@@ -0,0 +1,116 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+
+/*
+ Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
+
+
+ Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*=============================================================================
+ CAGuard.h
+
+=============================================================================*/
+#if !defined(__CAGuard_h__)
+#define __CAGuard_h__
+
+/*=============================================================================
+ Includes
+ =============================================================================*/
+
+#include <CoreAudio/CoreAudioTypes.h>
+#include <pthread.h>
+
+
+/*=============================================================================
+ CAGuard
+
+ This is your typical mutex with signalling implemented via pthreads.
+ Lock() will return true if and only if the guard is locked on that call.
+ A thread that already has the guard will receive 'false' if it locks it
+ again. Use of the stack-based CAGuard::Locker class is highly recommended
+ to properly manage the recursive nesting. The Wait calls with timeouts
+ will return true if and only if the timeout period expired. They will
+ return false if they receive notification any other way.
+ =============================================================================*/
+
+typedef struct S_SDLOSXCAGuard
+{
+
+/* Construction/Destruction */
+/*public:*/
+/* Actions */
+/*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:*/
+ pthread_mutex_t mMutex;
+ pthread_cond_t mCondVar;
+ pthread_t mOwner;
+} SDLOSXCAGuard;
+
+SDLOSXCAGuard *new_SDLOSXCAGuard(void);
+void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag);
+
+#endif
+
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom.c b/distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom.c
new file mode 100644
index 0000000..5018750
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom.c
@@ -0,0 +1,514 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifdef SDL_CDROM_MACOSX
+
+#include "SDL_syscdrom_c.h"
+
+#pragma mark -- Globals --
+
+static FSRef** tracks;
+static FSVolumeRefNum* volumes;
+static CDstatus status;
+static int nextTrackFrame;
+static int nextTrackFramesRemaining;
+static int fakeCD;
+static int currentTrack;
+static int didReadTOC;
+static int cacheTOCNumTracks;
+static int currentDrive; /* Only allow 1 drive in use at a time */
+
+#pragma mark -- Prototypes --
+
+static const char *SDL_SYS_CDName (int drive);
+static int SDL_SYS_CDOpen (int drive);
+static int SDL_SYS_CDGetTOC (SDL_CD *cdrom);
+static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position);
+static int SDL_SYS_CDPlay (SDL_CD *cdrom, int start, int length);
+static int SDL_SYS_CDPause (SDL_CD *cdrom);
+static int SDL_SYS_CDResume (SDL_CD *cdrom);
+static int SDL_SYS_CDStop (SDL_CD *cdrom);
+static int SDL_SYS_CDEject (SDL_CD *cdrom);
+static void SDL_SYS_CDClose (SDL_CD *cdrom);
+
+#pragma mark -- Helper Functions --
+
+/* Read a list of tracks from the volume */
+static int LoadTracks (SDL_CD *cdrom)
+{
+ /* Check if tracks are already loaded */
+ if ( tracks[cdrom->id] != NULL )
+ return 0;
+
+ /* Allocate memory for tracks */
+ tracks[cdrom->id] = (FSRef*) SDL_calloc (1, sizeof(**tracks) * cdrom->numtracks);
+ if (tracks[cdrom->id] == NULL) {
+ SDL_OutOfMemory ();
+ return -1;
+ }
+
+ /* Load tracks */
+ if (ListTrackFiles (volumes[cdrom->id], tracks[cdrom->id], cdrom->numtracks) < 0)
+ return -1;
+
+ return 0;
+}
+
+/* Find a file for a given start frame and length */
+static FSRef* GetFileForOffset (SDL_CD *cdrom, int start, int length, int *outStartFrame, int *outStopFrame)
+{
+ int i;
+
+ for (i = 0; i < cdrom->numtracks; i++) {
+
+ if (cdrom->track[i].offset <= start &&
+ start < (cdrom->track[i].offset + cdrom->track[i].length))
+ break;
+ }
+
+ if (i == cdrom->numtracks)
+ return NULL;
+
+ currentTrack = i;
+
+ *outStartFrame = start - cdrom->track[i].offset;
+
+ if ((*outStartFrame + length) < cdrom->track[i].length) {
+ *outStopFrame = *outStartFrame + length;
+ length = 0;
+ nextTrackFrame = -1;
+ nextTrackFramesRemaining = -1;
+ }
+ else {
+ *outStopFrame = -1;
+ length -= cdrom->track[i].length - *outStartFrame;
+ nextTrackFrame = cdrom->track[i+1].offset;
+ nextTrackFramesRemaining = length;
+ }
+
+ return &tracks[cdrom->id][i];
+}
+
+/* Setup another file for playback, or stop playback (called from another thread) */
+static void CompletionProc (SDL_CD *cdrom)
+{
+
+ Lock ();
+
+ if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
+
+ /* Load the next file to play */
+ int startFrame, stopFrame;
+ FSRef *file;
+
+ PauseFile ();
+ ReleaseFile ();
+
+ file = GetFileForOffset (cdrom, nextTrackFrame,
+ nextTrackFramesRemaining, &startFrame, &stopFrame);
+
+ if (file == NULL) {
+ status = CD_STOPPED;
+ Unlock ();
+ return;
+ }
+
+ LoadFile (file, startFrame, stopFrame);
+
+ SetCompletionProc (CompletionProc, cdrom);
+
+ PlayFile ();
+ }
+ else {
+
+ /* Release the current file */
+ PauseFile ();
+ ReleaseFile ();
+ status = CD_STOPPED;
+ }
+
+ Unlock ();
+}
+
+
+#pragma mark -- Driver Functions --
+
+/* Initialize */
+int SDL_SYS_CDInit (void)
+{
+ /* Initialize globals */
+ volumes = NULL;
+ tracks = NULL;
+ status = CD_STOPPED;
+ nextTrackFrame = -1;
+ nextTrackFramesRemaining = -1;
+ fakeCD = SDL_FALSE;
+ currentTrack = -1;
+ didReadTOC = SDL_FALSE;
+ cacheTOCNumTracks = -1;
+ currentDrive = -1;
+
+ /* Fill in function pointers */
+ SDL_CDcaps.Name = SDL_SYS_CDName;
+ SDL_CDcaps.Open = SDL_SYS_CDOpen;
+ SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
+ SDL_CDcaps.Status = SDL_SYS_CDStatus;
+ SDL_CDcaps.Play = SDL_SYS_CDPlay;
+ SDL_CDcaps.Pause = SDL_SYS_CDPause;
+ SDL_CDcaps.Resume = SDL_SYS_CDResume;
+ SDL_CDcaps.Stop = SDL_SYS_CDStop;
+ SDL_CDcaps.Eject = SDL_SYS_CDEject;
+ SDL_CDcaps.Close = SDL_SYS_CDClose;
+
+ /*
+ Read the list of "drives"
+
+ This is currently a hack that infers drives from
+ mounted audio CD volumes, rather than
+ actual CD-ROM devices - which means it may not
+ act as expected sometimes.
+ */
+
+ /* Find out how many cd volumes are mounted */
+ SDL_numcds = DetectAudioCDVolumes (NULL, 0);
+
+ /*
+ If there are no volumes, fake a cd device
+ so tray empty can be reported.
+ */
+ if (SDL_numcds == 0) {
+
+ fakeCD = SDL_TRUE;
+ SDL_numcds = 1;
+ status = CD_TRAYEMPTY;
+
+ return 0;
+ }
+
+ /* Allocate space for volumes */
+ volumes = (FSVolumeRefNum*) SDL_calloc (1, sizeof(*volumes) * SDL_numcds);
+ if (volumes == NULL) {
+ SDL_OutOfMemory ();
+ return -1;
+ }
+
+ /* Allocate space for tracks */
+ tracks = (FSRef**) SDL_calloc (1, sizeof(*tracks) * (SDL_numcds + 1));
+ if (tracks == NULL) {
+ SDL_OutOfMemory ();
+ return -1;
+ }
+
+ /* Mark the end of the tracks array */
+ tracks[ SDL_numcds ] = (FSRef*)-1;
+
+ /*
+ Redetect, now save all volumes for later
+ Update SDL_numcds just in case it changed
+ */
+ {
+ int numVolumes = SDL_numcds;
+
+ SDL_numcds = DetectAudioCDVolumes (volumes, numVolumes);
+
+ /* If more cds suddenly show up, ignore them */
+ if (SDL_numcds > numVolumes) {
+ SDL_SetError ("Some CD's were added but they will be ignored");
+ SDL_numcds = numVolumes;
+ }
+ }
+
+ return 0;
+}
+
+/* Shutdown and cleanup */
+void SDL_SYS_CDQuit(void)
+{
+ ReleaseFile();
+
+ if (volumes != NULL)
+ free (volumes);
+
+ if (tracks != NULL) {
+
+ FSRef **ptr;
+ for (ptr = tracks; *ptr != (FSRef*)-1; ptr++)
+ if (*ptr != NULL)
+ free (*ptr);
+
+ free (tracks);
+ }
+}
+
+/* Get the Unix disk name of the volume */
+static const char *SDL_SYS_CDName (int drive)
+{
+ /*
+ * !!! FIXME: PBHGetVolParmsSync() is gone in 10.6,
+ * !!! FIXME: replaced with FSGetVolumeParms(), which
+ * !!! FIXME: isn't available before 10.5. :/
+ */
+ return "Mac OS X CD-ROM Device";
+
+#if 0
+ OSStatus err = noErr;
+ HParamBlockRec pb;
+ GetVolParmsInfoBuffer volParmsInfo;
+
+ if (fakeCD)
+ return "Fake CD-ROM Device";
+
+ pb.ioParam.ioNamePtr = NULL;
+ pb.ioParam.ioVRefNum = volumes[drive];
+ pb.ioParam.ioBuffer = (Ptr)&volParmsInfo;
+ pb.ioParam.ioReqCount = (SInt32)sizeof(volParmsInfo);
+ err = PBHGetVolParmsSync(&pb);
+
+ if (err != noErr) {
+ SDL_SetError ("PBHGetVolParmsSync returned %d", err);
+ return NULL;
+ }
+
+ return volParmsInfo.vMDeviceID;
+#endif
+}
+
+/* Open the "device" */
+static int SDL_SYS_CDOpen (int drive)
+{
+ /* Only allow 1 device to be open */
+ if (currentDrive >= 0) {
+ SDL_SetError ("Only one cdrom is supported");
+ return -1;
+ }
+ else
+ currentDrive = drive;
+
+ return drive;
+}
+
+/* Get the table of contents */
+static int SDL_SYS_CDGetTOC (SDL_CD *cdrom)
+{
+ if (fakeCD) {
+ SDL_SetError (kErrorFakeDevice);
+ return -1;
+ }
+
+ if (didReadTOC) {
+ cdrom->numtracks = cacheTOCNumTracks;
+ return 0;
+ }
+
+
+ ReadTOCData (volumes[cdrom->id], cdrom);
+ didReadTOC = SDL_TRUE;
+ cacheTOCNumTracks = cdrom->numtracks;
+
+ return 0;
+}
+
+/* Get CD-ROM status */
+static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position)
+{
+ if (position) {
+ int trackFrame;
+
+ Lock ();
+ trackFrame = GetCurrentFrame ();
+ Unlock ();
+
+ *position = cdrom->track[currentTrack].offset + trackFrame;
+ }
+
+ return status;
+}
+
+/* Start playback */
+static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
+{
+ int startFrame, stopFrame;
+ FSRef *ref;
+
+ if (fakeCD) {
+ SDL_SetError (kErrorFakeDevice);
+ return -1;
+ }
+
+ Lock();
+
+ if (LoadTracks (cdrom) < 0)
+ return -2;
+
+ if (PauseFile () < 0)
+ return -3;
+
+ if (ReleaseFile () < 0)
+ return -4;
+
+ ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame);
+ if (ref == NULL) {
+ SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d", start, length);
+ return -5;
+ }
+
+ if (LoadFile (ref, startFrame, stopFrame) < 0)
+ return -6;
+
+ SetCompletionProc (CompletionProc, cdrom);
+
+ if (PlayFile () < 0)
+ return -7;
+
+ status = CD_PLAYING;
+
+ Unlock();
+
+ return 0;
+}
+
+/* Pause playback */
+static int SDL_SYS_CDPause(SDL_CD *cdrom)
+{
+ if (fakeCD) {
+ SDL_SetError (kErrorFakeDevice);
+ return -1;
+ }
+
+ Lock ();
+
+ if (PauseFile () < 0) {
+ Unlock ();
+ return -2;
+ }
+
+ status = CD_PAUSED;
+
+ Unlock ();
+
+ return 0;
+}
+
+/* Resume playback */
+static int SDL_SYS_CDResume(SDL_CD *cdrom)
+{
+ if (fakeCD) {
+ SDL_SetError (kErrorFakeDevice);
+ return -1;
+ }
+
+ Lock ();
+
+ if (PlayFile () < 0) {
+ Unlock ();
+ return -2;
+ }
+
+ status = CD_PLAYING;
+
+ Unlock ();
+
+ return 0;
+}
+
+/* Stop playback */
+static int SDL_SYS_CDStop(SDL_CD *cdrom)
+{
+ if (fakeCD) {
+ SDL_SetError (kErrorFakeDevice);
+ return -1;
+ }
+
+ Lock ();
+
+ if (PauseFile () < 0) {
+ Unlock ();
+ return -2;
+ }
+
+ if (ReleaseFile () < 0) {
+ Unlock ();
+ return -3;
+ }
+
+ status = CD_STOPPED;
+
+ Unlock ();
+
+ return 0;
+}
+
+/* Eject the CD-ROM (Unmount the volume) */
+static int SDL_SYS_CDEject(SDL_CD *cdrom)
+{
+ OSStatus err;
+ pid_t dissenter;
+
+ if (fakeCD) {
+ SDL_SetError (kErrorFakeDevice);
+ return -1;
+ }
+
+ Lock ();
+
+ if (PauseFile () < 0) {
+ Unlock ();
+ return -2;
+ }
+
+ if (ReleaseFile () < 0) {
+ Unlock ();
+ return -3;
+ }
+
+ status = CD_STOPPED;
+
+ /* Eject the volume */
+ err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter);
+
+ if (err != noErr) {
+ Unlock ();
+ SDL_SetError ("PBUnmountVol returned %d", err);
+ return -4;
+ }
+
+ status = CD_TRAYEMPTY;
+
+ /* Invalidate volume and track info */
+ volumes[cdrom->id] = 0;
+ free (tracks[cdrom->id]);
+ tracks[cdrom->id] = NULL;
+
+ Unlock ();
+
+ return 0;
+}
+
+/* Close the CD-ROM */
+static void SDL_SYS_CDClose(SDL_CD *cdrom)
+{
+ currentDrive = -1;
+ return;
+}
+
+#endif /* SDL_CDROM_MACOSX */
diff --git a/distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom_c.h b/distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom_c.h
new file mode 100644
index 0000000..589c589
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/cdrom/macosx/SDL_syscdrom_c.h
@@ -0,0 +1,136 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+*/
+#include "SDL_config.h"
+
+/* This is the Mac OS X / CoreAudio specific header for the SDL CD-ROM API
+ Contributed by Darrell Walisser and Max Horn
+ */
+
+/***********************************************************************************
+ Implementation Notes
+ *********************
+
+ This code has several limitations currently (all of which are proabaly fixable):
+
+ 1. A CD-ROM device is inferred from a mounted cdfs volume, so device 0 is
+ not necessarily the first CD-ROM device on the system. (Somewhat easy to fix
+ by useing the device name from the volume id's to reorder the volumes)
+
+ 2. You can only open and control 1 CD-ROM device at a time. (Challenging to fix,
+ due to extensive code restructuring)
+
+ 3. The status reported by SDL_CDStatus only changes to from CD_PLAYING to CD_STOPPED in
+ 1-second intervals (because the audio is buffered in 1-second chunks) If
+ the audio data is less than 1 second, the remainder is filled with silence.
+
+ If you need to play sequences back-to-back that are less that 1 second long,
+ use the frame position to determine when to play the next sequence, instead
+ of SDL_CDStatus.
+
+ This may be possible to fix with a clever usage of the AudioUnit API.
+
+ 4. When new volumes are inserted, our volume information is not updated. The only way
+ to refresh this information is to reinit the CD-ROM subsystem of SDL. To fix this,
+ one would probably have to fix point 1 above first, then figure out how to register
+ for a notification when new media is mounted in order to perform an automatic
+ rescan for cdfs volumes.
+
+
+
+ So, here comes a description of how this all works.
+
+ < Initializing >
+
+ To get things rolling, we have to locate mounted volumes that contain
+ audio (since nearly all Macs don't have analog audio-in on the sound card).
+ That's easy, since these volumes have a flag that indicates this special
+ filesystem. See DetectAudioCDVolumes() in CDPlayer.cpp for this code.
+
+ Next, we parse the invisible .TOC.plist in the root of the volume, which gets us
+ the track information (number, offset, length, leadout, etc). See ReadTOCData() in
+ CDPlayer.cpp for the skinny on this.
+
+
+ < The Playback Loop >
+
+ Now come the tricky parts. Let's start with basic audio playback. When a frame
+ range to play is requested, we must first find the .aiff files on the volume,
+ hopefully in the right order. Since these files all begin with a number "1 Audio Track",
+ etc, this is used to determine the correct track order.
+
+ Once all files are determined, we have to find what file corresponds to the start
+ and length parameter to SDL_SYS_CDPlay(). Again, this is quite simple by walking the
+ cdrom's track list. At this point, we also save the offset to the next track and frames
+ remaining, if we're going to have to play another file after the first one. See
+ GetFileForOffset() for this code.
+
+ At this point we have all info needed to start playback, so we hand off to the LoadFile()
+ function, which proceeds to do its magic and plays back the file.
+
+ When the file is finished playing, CompletionProc() is invoked, at which time we can
+ play the next file if the previously saved next track and frames remaining
+ indicates that we should.
+
+
+ < Magic >
+
+ OK, so it's not really magic, but since I don't fully understand all the hidden details it
+ seems like it to me ;-) The API's involved are the AudioUnit and AudioFile API's. These
+ appear to be an extension of CoreAudio for creating modular playback and f/x entities.
+ The important thing is that CPU usage is very low and reliability is very high. You'd
+ be hard-pressed to find a way to stutter the playback with other CPU-intensive tasks.
+
+ One part of this magic is that it uses multiple threads, which carries the usual potential
+ for disaster if not handled carefully. Playback currently requires 4 additional threads:
+ 1. The coreaudio runloop thread
+ 2. The coreaudio device i/o thread
+ 3. The file streaming thread
+ 4. The notification/callback thread
+
+ The first 2 threads are necessary evil - CoreAudio creates this no matter what the situation
+ is (even the SDL sound implementation creates theses suckers). The last two are are created
+ by us.
+
+ The file is streamed from disk using a threaded double-buffer approach.
+ This way, the high latency operation of reading from disk can be performed without interrupting
+ the real-time device thread (which amounts to avoiding dropouts). The device thread grabs the
+ buffer that isn't being read and sends it to the CoreAudio mixer where it eventually gets
+ to the sound card.
+
+ The device thread posts a notification when the file streaming thread is out of data. This
+ notification must be handled in a separate thread to avoid potential deadlock in the
+ device thread. That's where the notification thread comes in. This thread is signaled
+ whenever a notification needs to be processed, so another file can be played back if need be.
+
+ The API in CDPlayer.cpp contains synchronization because otherwise both the notification thread
+ and main thread (or another other thread using the SDL CD api) can potentially call it at the same time.
+
+************************************************************************************/
+
+
+#include "SDL_cdrom.h"
+#include "../SDL_syscdrom.h"
+
+#include "CDPlayer.h"
+
+#define kErrorFakeDevice "Error: Cannot proceed since we're faking a CD-ROM device. Reinit the CD-ROM subsystem to scan for new volumes."
+