summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/src/cdrom/macosx
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/src/cdrom/macosx')
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c360
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.h178
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/AudioFileReaderThread.c610
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/CDPlayer.c636
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/CDPlayer.h69
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.c199
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.h116
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom.c514
-rw-r--r--apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom_c.h136
9 files changed, 0 insertions, 2818 deletions
diff --git a/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c
deleted file mode 100644
index 97cb9b2874..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.c
+++ /dev/null
@@ -1,360 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21
22 This file based on Apple sample code. We haven't changed the file name,
23 so if you want to see the original search for it on apple.com/developer
24*/
25#include "SDL_config.h"
26#include "SDL_endian.h"
27
28/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 AudioFilePlayer.cpp
30*/
31#include "AudioFilePlayer.h"
32
33/*
34void ThrowResult (OSStatus result, const char* str)
35{
36 SDL_SetError ("Error: %s %d", str, result);
37 throw result;
38}
39*/
40
41#if DEBUG
42static void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
43{
44 if (!inDesc) {
45 printf ("Can't print a NULL desc!\n");
46 return;
47 }
48
49 printf ("- - - - - - - - - - - - - - - - - - - -\n");
50 printf (" Sample Rate:%f\n", inDesc->mSampleRate);
51 printf (" Format ID:%s\n", (char*)&inDesc->mFormatID);
52 printf (" Format Flags:%lX\n", inDesc->mFormatFlags);
53 printf (" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
54 printf (" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
55 printf (" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
56 printf (" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
57 printf (" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
58 printf ("- - - - - - - - - - - - - - - - - - - -\n");
59}
60#endif
61
62
63static int AudioFilePlayer_SetDestination (AudioFilePlayer *afp, AudioUnit *inDestUnit)
64{
65 /*if (afp->mConnected) throw static_cast<OSStatus>(-1);*/ /* can't set dest if already engaged */
66 if (afp->mConnected)
67 return 0 ;
68
69 SDL_memcpy(&afp->mPlayUnit, inDestUnit, sizeof (afp->mPlayUnit));
70
71 OSStatus result = noErr;
72
73
74 /* we can "down" cast a component instance to a component */
75 ComponentDescription desc;
76 result = GetComponentInfo ((Component)*inDestUnit, &desc, 0, 0, 0);
77 if (result) return 0; /*THROW_RESULT("GetComponentInfo")*/
78
79 /* we're going to use this to know which convert routine to call
80 a v1 audio unit will have a type of 'aunt'
81 a v2 audio unit will have one of several different types. */
82 if (desc.componentType != kAudioUnitType_Output) {
83 result = badComponentInstance;
84 /*THROW_RESULT("BAD COMPONENT")*/
85 if (result) return 0;
86 }
87
88 /* Set the input format of the audio unit. */
89 result = AudioUnitSetProperty (*inDestUnit,
90 kAudioUnitProperty_StreamFormat,
91 kAudioUnitScope_Input,
92 0,
93 &afp->mFileDescription,
94 sizeof (afp->mFileDescription));
95 /*THROW_RESULT("AudioUnitSetProperty")*/
96 if (result) return 0;
97 return 1;
98}
99
100static void AudioFilePlayer_SetNotifier(AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon)
101{
102 afp->mNotifier = inNotifier;
103 afp->mRefCon = inRefCon;
104}
105
106static int AudioFilePlayer_IsConnected(AudioFilePlayer *afp)
107{
108 return afp->mConnected;
109}
110
111static AudioUnit AudioFilePlayer_GetDestUnit(AudioFilePlayer *afp)
112{
113 return afp->mPlayUnit;
114}
115
116static void AudioFilePlayer_Print(AudioFilePlayer *afp)
117{
118#if DEBUG
119 printf ("Is Connected:%s\n", (IsConnected() ? "true" : "false"));
120 printf ("- - - - - - - - - - - - - - \n");
121#endif
122}
123
124static void AudioFilePlayer_SetStartFrame (AudioFilePlayer *afp, int frame)
125{
126 SInt64 position = frame * 2352;
127
128 afp->mStartFrame = frame;
129 afp->mAudioFileManager->SetPosition (afp->mAudioFileManager, position);
130}
131
132
133static int AudioFilePlayer_GetCurrentFrame (AudioFilePlayer *afp)
134{
135 return afp->mStartFrame + (afp->mAudioFileManager->GetByteCounter(afp->mAudioFileManager) / 2352);
136}
137
138static void AudioFilePlayer_SetStopFrame (AudioFilePlayer *afp, int frame)
139{
140 SInt64 position = frame * 2352;
141
142 afp->mAudioFileManager->SetEndOfFile (afp->mAudioFileManager, position);
143}
144
145void delete_AudioFilePlayer(AudioFilePlayer *afp)
146{
147 if (afp != NULL)
148 {
149 afp->Disconnect(afp);
150
151 if (afp->mAudioFileManager) {
152 delete_AudioFileManager(afp->mAudioFileManager);
153 afp->mAudioFileManager = 0;
154 }
155
156 if (afp->mForkRefNum) {
157 FSCloseFork (afp->mForkRefNum);
158 afp->mForkRefNum = 0;
159 }
160 SDL_free(afp);
161 }
162}
163
164static int AudioFilePlayer_Connect(AudioFilePlayer *afp)
165{
166#if DEBUG
167 printf ("Connect:%x, engaged=%d\n", (int)afp->mPlayUnit, (afp->mConnected ? 1 : 0));
168#endif
169 if (!afp->mConnected)
170 {
171 if (!afp->mAudioFileManager->DoConnect(afp->mAudioFileManager))
172 return 0;
173
174 /* set the render callback for the file data to be supplied to the sound converter AU */
175 afp->mInputCallback.inputProc = afp->mAudioFileManager->FileInputProc;
176 afp->mInputCallback.inputProcRefCon = afp->mAudioFileManager;
177
178 OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
179 kAudioUnitProperty_SetRenderCallback,
180 kAudioUnitScope_Input,
181 0,
182 &afp->mInputCallback,
183 sizeof(afp->mInputCallback));
184 if (result) return 0; /*THROW_RESULT("AudioUnitSetProperty")*/
185 afp->mConnected = 1;
186 }
187
188 return 1;
189}
190
191/* warning noted, now please go away ;-) */
192/* #warning This should redirect the calling of notification code to some other thread */
193static void AudioFilePlayer_DoNotification (AudioFilePlayer *afp, OSStatus inStatus)
194{
195 if (afp->mNotifier) {
196 (*afp->mNotifier) (afp->mRefCon, inStatus);
197 } else {
198 SDL_SetError ("Notification posted with no notifier in place");
199
200 if (inStatus == kAudioFilePlay_FileIsFinished)
201 afp->Disconnect(afp);
202 else if (inStatus != kAudioFilePlayErr_FilePlayUnderrun)
203 afp->Disconnect(afp);
204 }
205}
206
207static void AudioFilePlayer_Disconnect (AudioFilePlayer *afp)
208{
209#if DEBUG
210 printf ("Disconnect:%x,%ld, engaged=%d\n", (int)afp->mPlayUnit, 0, (afp->mConnected ? 1 : 0));
211#endif
212 if (afp->mConnected)
213 {
214 afp->mConnected = 0;
215
216 afp->mInputCallback.inputProc = 0;
217 afp->mInputCallback.inputProcRefCon = 0;
218 OSStatus result = AudioUnitSetProperty (afp->mPlayUnit,
219 kAudioUnitProperty_SetRenderCallback,
220 kAudioUnitScope_Input,
221 0,
222 &afp->mInputCallback,
223 sizeof(afp->mInputCallback));
224 if (result)
225 SDL_SetError ("AudioUnitSetProperty:RemoveInputCallback:%ld", result);
226
227 afp->mAudioFileManager->Disconnect(afp->mAudioFileManager);
228 }
229}
230
231typedef struct {
232 UInt32 offset;
233 UInt32 blockSize;
234} SSNDData;
235
236static int AudioFilePlayer_OpenFile (AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileDataSize)
237{
238 ContainerChunk chunkHeader;
239 ChunkHeader chunk;
240 SSNDData ssndData;
241
242 OSErr result;
243 HFSUniStr255 dfName;
244 ByteCount actual;
245 SInt64 offset;
246
247 /* Open the data fork of the input file */
248 result = FSGetDataForkName(&dfName);
249 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSGetDataForkName")*/
250
251 result = FSOpenFork(inRef, dfName.length, dfName.unicode, fsRdPerm, &afp->mForkRefNum);
252 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSOpenFork")*/
253
254 /* Read the file header, and check if it's indeed an AIFC file */
255 result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(chunkHeader), &chunkHeader, &actual);
256 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/
257
258 if (SDL_SwapBE32(chunkHeader.ckID) != 'FORM') {
259 result = -1;
260 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): chunk id is not 'FORM'");*/
261 }
262
263 if (SDL_SwapBE32(chunkHeader.formType) != 'AIFC') {
264 result = -1;
265 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): file format is not 'AIFC'");*/
266 }
267
268 /* Search for the SSND chunk. We ignore all compression etc. information
269 in other chunks. Of course that is kind of evil, but for now we are lazy
270 and rely on the cdfs to always give us the same fixed format.
271 TODO: Parse the COMM chunk we currently skip to fill in mFileDescription.
272 */
273 offset = 0;
274 do {
275 result = FSReadFork(afp->mForkRefNum, fsFromMark, offset, sizeof(chunk), &chunk, &actual);
276 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/
277
278 chunk.ckID = SDL_SwapBE32(chunk.ckID);
279 chunk.ckSize = SDL_SwapBE32(chunk.ckSize);
280
281 /* Skip the chunk data */
282 offset = chunk.ckSize;
283 } while (chunk.ckID != 'SSND');
284
285 /* Read the header of the SSND chunk. After this, we are positioned right
286 at the start of the audio data. */
287 result = FSReadFork(afp->mForkRefNum, fsAtMark, 0, sizeof(ssndData), &ssndData, &actual);
288 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSReadFork")*/
289
290 ssndData.offset = SDL_SwapBE32(ssndData.offset);
291
292 result = FSSetForkPosition(afp->mForkRefNum, fsFromMark, ssndData.offset);
293 if (result) return 0; /*THROW_RESULT("AudioFilePlayer::OpenFile(): FSSetForkPosition")*/
294
295 /* Data size */
296 *outFileDataSize = chunk.ckSize - ssndData.offset - 8;
297
298 /* File format */
299 afp->mFileDescription.mSampleRate = 44100;
300 afp->mFileDescription.mFormatID = kAudioFormatLinearPCM;
301 afp->mFileDescription.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
302 afp->mFileDescription.mBytesPerPacket = 4;
303 afp->mFileDescription.mFramesPerPacket = 1;
304 afp->mFileDescription.mBytesPerFrame = 4;
305 afp->mFileDescription.mChannelsPerFrame = 2;
306 afp->mFileDescription.mBitsPerChannel = 16;
307
308 return 1;
309}
310
311AudioFilePlayer *new_AudioFilePlayer (const FSRef *inFileRef)
312{
313 SInt64 fileDataSize = 0;
314
315 AudioFilePlayer *afp = (AudioFilePlayer *) SDL_malloc(sizeof (AudioFilePlayer));
316 if (afp == NULL)
317 return NULL;
318 SDL_memset(afp, '\0', sizeof (*afp));
319
320 #define SET_AUDIOFILEPLAYER_METHOD(m) afp->m = AudioFilePlayer_##m
321 SET_AUDIOFILEPLAYER_METHOD(SetDestination);
322 SET_AUDIOFILEPLAYER_METHOD(SetNotifier);
323 SET_AUDIOFILEPLAYER_METHOD(SetStartFrame);
324 SET_AUDIOFILEPLAYER_METHOD(GetCurrentFrame);
325 SET_AUDIOFILEPLAYER_METHOD(SetStopFrame);
326 SET_AUDIOFILEPLAYER_METHOD(Connect);
327 SET_AUDIOFILEPLAYER_METHOD(Disconnect);
328 SET_AUDIOFILEPLAYER_METHOD(DoNotification);
329 SET_AUDIOFILEPLAYER_METHOD(IsConnected);
330 SET_AUDIOFILEPLAYER_METHOD(GetDestUnit);
331 SET_AUDIOFILEPLAYER_METHOD(Print);
332 SET_AUDIOFILEPLAYER_METHOD(OpenFile);
333 #undef SET_AUDIOFILEPLAYER_METHOD
334
335 if (!afp->OpenFile (afp, inFileRef, &fileDataSize))
336 {
337 SDL_free(afp);
338 return NULL;
339 }
340
341 /* we want about 4 seconds worth of data for the buffer */
342 int bytesPerSecond = (UInt32) (4 * afp->mFileDescription.mSampleRate * afp->mFileDescription.mBytesPerFrame);
343
344#if DEBUG
345 printf("File format:\n");
346 PrintStreamDesc (&afp->mFileDescription);
347#endif
348
349 afp->mAudioFileManager = new_AudioFileManager(afp, afp->mForkRefNum,
350 fileDataSize,
351 bytesPerSecond);
352 if (afp->mAudioFileManager == NULL)
353 {
354 delete_AudioFilePlayer(afp);
355 return NULL;
356 }
357
358 return afp;
359}
360
diff --git a/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.h b/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.h
deleted file mode 100644
index 886d017a59..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/AudioFilePlayer.h
+++ /dev/null
@@ -1,178 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21
22 This file based on Apple sample code. We haven't changed the file name,
23 so if you want to see the original search for it on apple.com/developer
24*/
25#include "SDL_config.h"
26
27/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 AudioFilePlayer.h
29*/
30#ifndef __AudioFilePlayer_H__
31#define __AudioFilePlayer_H__
32
33#include <CoreServices/CoreServices.h>
34
35#include <AudioUnit/AudioUnit.h>
36#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
37#include <AudioUnit/AUNTComponent.h>
38#endif
39
40#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1050)
41typedef SInt16 FSIORefNum;
42#endif
43
44#include "SDL_error.h"
45
46const char* AudioFilePlayerErrorStr (OSStatus error);
47
48/*
49void ThrowResult (OSStatus result, const char *str);
50
51#define THROW_RESULT(str) \
52 if (result) { \
53 ThrowResult (result, str); \
54 }
55*/
56
57typedef void (*AudioFilePlayNotifier)(void *inRefCon,
58 OSStatus inStatus);
59
60enum {
61 kAudioFilePlayErr_FilePlayUnderrun = -10000,
62 kAudioFilePlay_FileIsFinished = -10001,
63 kAudioFilePlay_PlayerIsUninitialized = -10002
64};
65
66
67struct S_AudioFileManager;
68
69#pragma mark __________ AudioFilePlayer
70typedef struct S_AudioFilePlayer
71{
72/*public:*/
73 int (*SetDestination)(struct S_AudioFilePlayer *afp, AudioUnit *inDestUnit);
74 void (*SetNotifier)(struct S_AudioFilePlayer *afp, AudioFilePlayNotifier inNotifier, void *inRefCon);
75 void (*SetStartFrame)(struct S_AudioFilePlayer *afp, int frame); /* seek in the file */
76 int (*GetCurrentFrame)(struct S_AudioFilePlayer *afp); /* get the current frame position */
77 void (*SetStopFrame)(struct S_AudioFilePlayer *afp, int frame); /* set limit in the file */
78 int (*Connect)(struct S_AudioFilePlayer *afp);
79 void (*Disconnect)(struct S_AudioFilePlayer *afp);
80 void (*DoNotification)(struct S_AudioFilePlayer *afp, OSStatus inError);
81 int (*IsConnected)(struct S_AudioFilePlayer *afp);
82 AudioUnit (*GetDestUnit)(struct S_AudioFilePlayer *afp);
83 void (*Print)(struct S_AudioFilePlayer *afp);
84
85/*private:*/
86 AudioUnit mPlayUnit;
87 FSIORefNum mForkRefNum;
88
89 AURenderCallbackStruct mInputCallback;
90
91 AudioStreamBasicDescription mFileDescription;
92
93 int mConnected;
94
95 struct S_AudioFileManager* mAudioFileManager;
96
97 AudioFilePlayNotifier mNotifier;
98 void* mRefCon;
99
100 int mStartFrame;
101
102#pragma mark __________ Private_Methods
103
104 int (*OpenFile)(struct S_AudioFilePlayer *afp, const FSRef *inRef, SInt64 *outFileSize);
105} AudioFilePlayer;
106
107
108AudioFilePlayer *new_AudioFilePlayer(const FSRef *inFileRef);
109void delete_AudioFilePlayer(AudioFilePlayer *afp);
110
111
112
113#pragma mark __________ AudioFileManager
114typedef struct S_AudioFileManager
115{
116/*public:*/
117 /* this method should NOT be called by an object of this class
118 as it is called by the parent's Disconnect() method */
119 void (*Disconnect)(struct S_AudioFileManager *afm);
120 int (*DoConnect)(struct S_AudioFileManager *afm);
121 OSStatus (*Read)(struct S_AudioFileManager *afm, char *buffer, ByteCount *len);
122 const char* (*GetFileBuffer)(struct S_AudioFileManager *afm);
123 const AudioFilePlayer *(*GetParent)(struct S_AudioFileManager *afm);
124 void (*SetPosition)(struct S_AudioFileManager *afm, SInt64 pos); /* seek/rewind in the file */
125 int (*GetByteCounter)(struct S_AudioFileManager *afm); /* return actual bytes streamed to audio hardware */
126 void (*SetEndOfFile)(struct S_AudioFileManager *afm, SInt64 pos); /* set the "EOF" (will behave just like it reached eof) */
127
128/*protected:*/
129 AudioFilePlayer* mParent;
130 SInt16 mForkRefNum;
131 SInt64 mAudioDataOffset;
132
133 char* mFileBuffer;
134
135 int mByteCounter;
136
137 int mReadFromFirstBuffer;
138 int mLockUnsuccessful;
139 int mIsEngaged;
140
141 int mNumTimesAskedSinceFinished;
142
143
144 void* mTmpBuffer;
145 UInt32 mBufferSize;
146 UInt32 mBufferOffset;
147/*public:*/
148 UInt32 mChunkSize;
149 SInt64 mFileLength;
150 SInt64 mReadFilePosition;
151 int mWriteToFirstBuffer;
152 int mFinishedReadingData;
153
154/*protected:*/
155 OSStatus (*Render)(struct S_AudioFileManager *afm, AudioBufferList *ioData);
156 OSStatus (*GetFileData)(struct S_AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize);
157 void (*AfterRender)(struct S_AudioFileManager *afm);
158
159/*public:*/
160 /*static*/
161 OSStatus (*FileInputProc)(void *inRefCon,
162 AudioUnitRenderActionFlags *ioActionFlags,
163 const AudioTimeStamp *inTimeStamp,
164 UInt32 inBusNumber,
165 UInt32 inNumberFrames,
166 AudioBufferList *ioData);
167} AudioFileManager;
168
169
170AudioFileManager *new_AudioFileManager (AudioFilePlayer *inParent,
171 SInt16 inForkRefNum,
172 SInt64 inFileLength,
173 UInt32 inChunkSize);
174
175void delete_AudioFileManager(AudioFileManager *afm);
176
177#endif
178
diff --git a/apps/plugins/sdl/src/cdrom/macosx/AudioFileReaderThread.c b/apps/plugins/sdl/src/cdrom/macosx/AudioFileReaderThread.c
deleted file mode 100644
index 0007c07f61..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/AudioFileReaderThread.c
+++ /dev/null
@@ -1,610 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21
22 This file based on Apple sample code. We haven't changed the file name,
23 so if you want to see the original search for it on apple.com/developer
24*/
25#include "SDL_config.h"
26
27/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 AudioFileManager.cpp
29*/
30#include "AudioFilePlayer.h"
31#include <mach/mach.h> /* used for setting policy of thread */
32#include "SDLOSXCAGuard.h"
33#include <pthread.h>
34
35/*#include <list>*/
36
37/*typedef void *FileData;*/
38typedef struct S_FileData
39{
40 AudioFileManager *obj;
41 struct S_FileData *next;
42} FileData;
43
44
45typedef struct S_FileReaderThread {
46/*public:*/
47 SDLOSXCAGuard* (*GetGuard)(struct S_FileReaderThread *frt);
48 void (*AddReader)(struct S_FileReaderThread *frt);
49 void (*RemoveReader)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
50 int (*TryNextRead)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
51
52 int mThreadShouldDie;
53
54/*private:*/
55 /*typedef std::list<AudioFileManager*> FileData;*/
56
57 SDLOSXCAGuard *mGuard;
58 UInt32 mThreadPriority;
59
60 int mNumReaders;
61 FileData *mFileData;
62
63
64 void (*ReadNextChunk)(struct S_FileReaderThread *frt);
65 int (*StartFixedPriorityThread)(struct S_FileReaderThread *frt);
66 /*static*/
67 UInt32 (*GetThreadBasePriority)(pthread_t inThread);
68 /*static*/
69 void* (*DiskReaderEntry)(void *inRefCon);
70} FileReaderThread;
71
72
73static SDLOSXCAGuard* FileReaderThread_GetGuard(FileReaderThread *frt)
74{
75 return frt->mGuard;
76}
77
78/* returns 1 if succeeded */
79static int FileReaderThread_TryNextRead (FileReaderThread *frt, AudioFileManager* inItem)
80{
81 int didLock = 0;
82 int succeeded = 0;
83 if (frt->mGuard->Try(frt->mGuard, &didLock))
84 {
85 /*frt->mFileData.push_back (inItem);*/
86 /* !!! FIXME: this could be faster with a "tail" member. --ryan. */
87 FileData *i = frt->mFileData;
88 FileData *prev = NULL;
89
90 FileData *newfd = (FileData *) SDL_malloc(sizeof (FileData));
91 newfd->obj = inItem;
92 newfd->next = NULL;
93
94 while (i != NULL) { prev = i; i = i->next; }
95 if (prev == NULL)
96 frt->mFileData = newfd;
97 else
98 prev->next = newfd;
99
100 frt->mGuard->Notify(frt->mGuard);
101 succeeded = 1;
102
103 if (didLock)
104 frt->mGuard->Unlock(frt->mGuard);
105 }
106
107 return succeeded;
108}
109
110static void FileReaderThread_AddReader(FileReaderThread *frt)
111{
112 if (frt->mNumReaders == 0)
113 {
114 frt->mThreadShouldDie = 0;
115 frt->StartFixedPriorityThread (frt);
116 }
117 frt->mNumReaders++;
118}
119
120static void FileReaderThread_RemoveReader (FileReaderThread *frt, AudioFileManager* inItem)
121{
122 if (frt->mNumReaders > 0)
123 {
124 int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
125
126 /*frt->mFileData.remove (inItem);*/
127 FileData *i = frt->mFileData;
128 FileData *prev = NULL;
129 while (i != NULL)
130 {
131 FileData *next = i->next;
132 if (i->obj != inItem)
133 prev = i;
134 else
135 {
136 if (prev == NULL)
137 frt->mFileData = next;
138 else
139 prev->next = next;
140 SDL_free(i);
141 }
142 i = next;
143 }
144
145 if (--frt->mNumReaders == 0) {
146 frt->mThreadShouldDie = 1;
147 frt->mGuard->Notify(frt->mGuard); /* wake up thread so it will quit */
148 frt->mGuard->Wait(frt->mGuard); /* wait for thread to die */
149 }
150
151 if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
152 }
153}
154
155static int FileReaderThread_StartFixedPriorityThread (FileReaderThread *frt)
156{
157 pthread_attr_t theThreadAttrs;
158 pthread_t pThread;
159
160 OSStatus result = pthread_attr_init(&theThreadAttrs);
161 if (result) return 0; /*THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")*/
162
163 result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
164 if (result) return 0; /*THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")*/
165
166 result = pthread_create (&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt);
167 if (result) return 0; /*THROW_RESULT("pthread_create - Create and start the thread.")*/
168
169 pthread_attr_destroy(&theThreadAttrs);
170
171 /* we've now created the thread and started it
172 we'll now set the priority of the thread to the nominated priority
173 and we'll also make the thread fixed */
174 thread_extended_policy_data_t theFixedPolicy;
175 thread_precedence_policy_data_t thePrecedencePolicy;
176 SInt32 relativePriority;
177
178 /* make thread fixed */
179 theFixedPolicy.timeshare = 0; /* set to 1 for a non-fixed thread */
180 result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
181 if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")*/
182 /* set priority */
183 /* precedency policy's "importance" value is relative to spawning thread's priority */
184 relativePriority = frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self());
185
186 thePrecedencePolicy.importance = relativePriority;
187 result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
188 if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread priority.")*/
189
190 return 1;
191}
192
193static UInt32 FileReaderThread_GetThreadBasePriority (pthread_t inThread)
194{
195 thread_basic_info_data_t threadInfo;
196 policy_info_data_t thePolicyInfo;
197 unsigned int count;
198
199 /* get basic info */
200 count = THREAD_BASIC_INFO_COUNT;
201 thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count);
202
203 switch (threadInfo.policy) {
204 case POLICY_TIMESHARE:
205 count = POLICY_TIMESHARE_INFO_COUNT;
206 thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
207 return thePolicyInfo.ts.base_priority;
208 break;
209
210 case POLICY_FIFO:
211 count = POLICY_FIFO_INFO_COUNT;
212 thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
213 if (thePolicyInfo.fifo.depressed) {
214 return thePolicyInfo.fifo.depress_priority;
215 } else {
216 return thePolicyInfo.fifo.base_priority;
217 }
218 break;
219
220 case POLICY_RR:
221 count = POLICY_RR_INFO_COUNT;
222 thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
223 if (thePolicyInfo.rr.depressed) {
224 return thePolicyInfo.rr.depress_priority;
225 } else {
226 return thePolicyInfo.rr.base_priority;
227 }
228 break;
229 }
230
231 return 0;
232}
233
234static void *FileReaderThread_DiskReaderEntry (void *inRefCon)
235{
236 FileReaderThread *frt = (FileReaderThread *)inRefCon;
237 frt->ReadNextChunk(frt);
238 #if DEBUG
239 printf ("finished with reading file\n");
240 #endif
241
242 return 0;
243}
244
245static void FileReaderThread_ReadNextChunk (FileReaderThread *frt)
246{
247 OSStatus result;
248 ByteCount dataChunkSize;
249 AudioFileManager* theItem = 0;
250
251 for (;;)
252 {
253 { /* this is a scoped based lock */
254 int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
255
256 if (frt->mThreadShouldDie) {
257 frt->mGuard->Notify(frt->mGuard);
258 if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
259 return;
260 }
261
262 /*if (frt->mFileData.empty())*/
263 if (frt->mFileData == NULL)
264 {
265 frt->mGuard->Wait(frt->mGuard);
266 }
267
268 /* kill thread */
269 if (frt->mThreadShouldDie) {
270
271 frt->mGuard->Notify(frt->mGuard);
272 if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
273 return;
274 }
275
276 /*theItem = frt->mFileData.front();*/
277 /*frt->mFileData.pop_front();*/
278 theItem = NULL;
279 if (frt->mFileData != NULL)
280 {
281 FileData *next = frt->mFileData->next;
282 theItem = frt->mFileData->obj;
283 SDL_free(frt->mFileData);
284 frt->mFileData = next;
285 }
286
287 if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
288 }
289
290 if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
291 dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
292 else
293 dataChunkSize = theItem->mChunkSize;
294
295 /* this is the exit condition for the thread */
296 if (dataChunkSize <= 0) {
297 theItem->mFinishedReadingData = 1;
298 continue;
299 }
300 /* construct pointer */
301 char* writePtr = (char *) (theItem->GetFileBuffer(theItem) +
302 (theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
303
304 /* read data */
305 result = theItem->Read(theItem, writePtr, &dataChunkSize);
306 if (result != noErr && result != eofErr) {
307 AudioFilePlayer *afp = (AudioFilePlayer *) theItem->GetParent(theItem);
308 afp->DoNotification(afp, result);
309 continue;
310 }
311
312 if (dataChunkSize != theItem->mChunkSize)
313 {
314 writePtr += dataChunkSize;
315
316 /* can't exit yet.. we still have to pass the partial buffer back */
317 SDL_memset(writePtr, 0, (theItem->mChunkSize - dataChunkSize));
318 }
319
320 theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer; /* switch buffers */
321
322 if (result == eofErr)
323 theItem->mReadFilePosition = theItem->mFileLength;
324 else
325 theItem->mReadFilePosition += dataChunkSize; /* increment count */
326 }
327}
328
329void delete_FileReaderThread(FileReaderThread *frt)
330{
331 if (frt != NULL)
332 {
333 delete_SDLOSXCAGuard(frt->mGuard);
334 SDL_free(frt);
335 }
336}
337
338FileReaderThread *new_FileReaderThread ()
339{
340 FileReaderThread *frt = (FileReaderThread *) SDL_malloc(sizeof (FileReaderThread));
341 if (frt == NULL)
342 return NULL;
343 SDL_memset(frt, '\0', sizeof (*frt));
344
345 frt->mGuard = new_SDLOSXCAGuard();
346 if (frt->mGuard == NULL)
347 {
348 SDL_free(frt);
349 return NULL;
350 }
351
352 #define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m
353 SET_FILEREADERTHREAD_METHOD(GetGuard);
354 SET_FILEREADERTHREAD_METHOD(AddReader);
355 SET_FILEREADERTHREAD_METHOD(RemoveReader);
356 SET_FILEREADERTHREAD_METHOD(TryNextRead);
357 SET_FILEREADERTHREAD_METHOD(ReadNextChunk);
358 SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread);
359 SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority);
360 SET_FILEREADERTHREAD_METHOD(DiskReaderEntry);
361 #undef SET_FILEREADERTHREAD_METHOD
362
363 frt->mThreadPriority = 62;
364 return frt;
365}
366
367
368static FileReaderThread *sReaderThread;
369
370
371static int AudioFileManager_DoConnect (AudioFileManager *afm)
372{
373 if (!afm->mIsEngaged)
374 {
375 OSStatus result;
376
377 /*afm->mReadFilePosition = 0;*/
378 afm->mFinishedReadingData = 0;
379
380 afm->mNumTimesAskedSinceFinished = 0;
381 afm->mLockUnsuccessful = 0;
382
383 ByteCount dataChunkSize;
384
385 if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize)
386 dataChunkSize = afm->mFileLength - afm->mReadFilePosition;
387 else
388 dataChunkSize = afm->mChunkSize;
389
390 result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize);
391 if (result) return 0; /*THROW_RESULT("AudioFileManager::DoConnect(): Read")*/
392
393 afm->mReadFilePosition += dataChunkSize;
394
395 afm->mWriteToFirstBuffer = 0;
396 afm->mReadFromFirstBuffer = 1;
397
398 sReaderThread->AddReader(sReaderThread);
399
400 afm->mIsEngaged = 1;
401 }
402 /*
403 else
404 throw static_cast<OSStatus>(-1); */ /* thread has already been started */
405
406 return 1;
407}
408
409static void AudioFileManager_Disconnect (AudioFileManager *afm)
410{
411 if (afm->mIsEngaged)
412 {
413 sReaderThread->RemoveReader (sReaderThread, afm);
414 afm->mIsEngaged = 0;
415 }
416}
417
418static OSStatus AudioFileManager_Read(AudioFileManager *afm, char *buffer, ByteCount *len)
419{
420 return FSReadFork (afm->mForkRefNum,
421 fsFromStart,
422 afm->mReadFilePosition + afm->mAudioDataOffset,
423 *len,
424 buffer,
425 len);
426}
427
428static OSStatus AudioFileManager_GetFileData (AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize)
429{
430 if (afm->mFinishedReadingData)
431 {
432 ++afm->mNumTimesAskedSinceFinished;
433 *inOutDataSize = 0;
434 *inOutData = 0;
435 return noErr;
436 }
437
438 if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) {
439 #if DEBUG
440 printf ("* * * * * * * Can't keep up with reading file\n");
441 #endif
442
443 afm->mParent->DoNotification (afm->mParent, kAudioFilePlayErr_FilePlayUnderrun);
444 *inOutDataSize = 0;
445 *inOutData = 0;
446 } else {
447 *inOutDataSize = afm->mChunkSize;
448 *inOutData = afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer + afm->mChunkSize);
449 }
450
451 afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
452
453 afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer;
454
455 return noErr;
456}
457
458static void AudioFileManager_AfterRender (AudioFileManager *afm)
459{
460 if (afm->mNumTimesAskedSinceFinished > 0)
461 {
462 int didLock = 0;
463 SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread);
464 if (guard->Try(guard, &didLock)) {
465 afm->mParent->DoNotification (afm->mParent, kAudioFilePlay_FileIsFinished);
466 if (didLock)
467 guard->Unlock(guard);
468 }
469 }
470
471 if (afm->mLockUnsuccessful)
472 afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
473}
474
475static void AudioFileManager_SetPosition (AudioFileManager *afm, SInt64 pos)
476{
477 if (pos < 0 || pos >= afm->mFileLength) {
478 SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n",
479 (unsigned int)pos, (unsigned int)afm->mFileLength);
480 pos = 0;
481 }
482
483 afm->mReadFilePosition = pos;
484}
485
486static void AudioFileManager_SetEndOfFile (AudioFileManager *afm, SInt64 pos)
487{
488 if (pos <= 0 || pos > afm->mFileLength) {
489 SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
490 pos = afm->mFileLength;
491 }
492
493 afm->mFileLength = pos;
494}
495
496static const char *AudioFileManager_GetFileBuffer(AudioFileManager *afm)
497{
498 return afm->mFileBuffer;
499}
500
501const AudioFilePlayer *AudioFileManager_GetParent(AudioFileManager *afm)
502{
503 return afm->mParent;
504}
505
506static int AudioFileManager_GetByteCounter(AudioFileManager *afm)
507{
508 return afm->mByteCounter;
509}
510
511static OSStatus AudioFileManager_FileInputProc (void *inRefCon,
512 AudioUnitRenderActionFlags *ioActionFlags,
513 const AudioTimeStamp *inTimeStamp,
514 UInt32 inBusNumber,
515 UInt32 inNumberFrames,
516 AudioBufferList *ioData)
517{
518 AudioFileManager* afm = (AudioFileManager*)inRefCon;
519 return afm->Render(afm, ioData);
520}
521
522static OSStatus AudioFileManager_Render (AudioFileManager *afm, AudioBufferList *ioData)
523{
524 OSStatus result = noErr;
525 AudioBuffer *abuf;
526 UInt32 i;
527
528 for (i = 0; i < ioData->mNumberBuffers; i++) {
529 abuf = &ioData->mBuffers[i];
530 if (afm->mBufferOffset >= afm->mBufferSize) {
531 result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize);
532 if (result) {
533 SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
534 afm->mParent->DoNotification(afm->mParent, result);
535 return result;
536 }
537
538 afm->mBufferOffset = 0;
539 }
540
541 if (abuf->mDataByteSize > afm->mBufferSize - afm->mBufferOffset)
542 abuf->mDataByteSize = afm->mBufferSize - afm->mBufferOffset;
543 abuf->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset;
544 afm->mBufferOffset += abuf->mDataByteSize;
545
546 afm->mByteCounter += abuf->mDataByteSize;
547 afm->AfterRender(afm);
548 }
549 return result;
550}
551
552
553void delete_AudioFileManager (AudioFileManager *afm)
554{
555 if (afm != NULL) {
556 if (afm->mFileBuffer) {
557 free(afm->mFileBuffer);
558 }
559
560 SDL_free(afm);
561 }
562}
563
564
565AudioFileManager *new_AudioFileManager(AudioFilePlayer *inParent,
566 SInt16 inForkRefNum,
567 SInt64 inFileLength,
568 UInt32 inChunkSize)
569{
570 AudioFileManager *afm;
571
572 if (sReaderThread == NULL)
573 {
574 sReaderThread = new_FileReaderThread();
575 if (sReaderThread == NULL)
576 return NULL;
577 }
578
579 afm = (AudioFileManager *) SDL_malloc(sizeof (AudioFileManager));
580 if (afm == NULL)
581 return NULL;
582 SDL_memset(afm, '\0', sizeof (*afm));
583
584 #define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m
585 SET_AUDIOFILEMANAGER_METHOD(Disconnect);
586 SET_AUDIOFILEMANAGER_METHOD(DoConnect);
587 SET_AUDIOFILEMANAGER_METHOD(Read);
588 SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer);
589 SET_AUDIOFILEMANAGER_METHOD(GetParent);
590 SET_AUDIOFILEMANAGER_METHOD(SetPosition);
591 SET_AUDIOFILEMANAGER_METHOD(GetByteCounter);
592 SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile);
593 SET_AUDIOFILEMANAGER_METHOD(Render);
594 SET_AUDIOFILEMANAGER_METHOD(GetFileData);
595 SET_AUDIOFILEMANAGER_METHOD(AfterRender);
596 SET_AUDIOFILEMANAGER_METHOD(FileInputProc);
597 #undef SET_AUDIOFILEMANAGER_METHOD
598
599 afm->mParent = inParent;
600 afm->mForkRefNum = inForkRefNum;
601 afm->mBufferSize = inChunkSize;
602 afm->mBufferOffset = inChunkSize;
603 afm->mChunkSize = inChunkSize;
604 afm->mFileLength = inFileLength;
605 afm->mFileBuffer = (char*) SDL_malloc(afm->mChunkSize * 2);
606 FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset);
607 assert (afm->mFileBuffer != NULL);
608 return afm;
609}
610
diff --git a/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.c b/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.c
deleted file mode 100644
index beb87cd85b..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.c
+++ /dev/null
@@ -1,636 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#include "CDPlayer.h"
25#include "AudioFilePlayer.h"
26#include "SDLOSXCAGuard.h"
27
28/* we're exporting these functions into C land for SDL_syscdrom.c */
29/*extern "C" {*/
30
31/*///////////////////////////////////////////////////////////////////////////
32 Constants
33 //////////////////////////////////////////////////////////////////////////*/
34
35#define kAudioCDFilesystemID (UInt16)(('J' << 8) | 'H') /* 'JH'; this avoids compiler warning */
36
37/* XML PList keys */
38#define kRawTOCDataString "Format 0x02 TOC Data"
39#define kSessionsString "Sessions"
40#define kSessionTypeString "Session Type"
41#define kTrackArrayString "Track Array"
42#define kFirstTrackInSessionString "First Track"
43#define kLastTrackInSessionString "Last Track"
44#define kLeadoutBlockString "Leadout Block"
45#define kDataKeyString "Data"
46#define kPointKeyString "Point"
47#define kSessionNumberKeyString "Session Number"
48#define kStartBlockKeyString "Start Block"
49
50/*///////////////////////////////////////////////////////////////////////////
51 Globals
52 //////////////////////////////////////////////////////////////////////////*/
53
54#pragma mark -- Globals --
55
56static int playBackWasInit = 0;
57static AudioUnit theUnit;
58static AudioFilePlayer* thePlayer = NULL;
59static CDPlayerCompletionProc completionProc = NULL;
60static SDL_mutex *apiMutex = NULL;
61static SDL_sem *callbackSem;
62static SDL_CD* theCDROM;
63
64/*///////////////////////////////////////////////////////////////////////////
65 Prototypes
66 //////////////////////////////////////////////////////////////////////////*/
67
68#pragma mark -- Prototypes --
69
70static OSStatus CheckInit ();
71
72static void FilePlayNotificationHandler (void* inRefCon, OSStatus inStatus);
73
74static int RunCallBackThread (void* inRefCon);
75
76
77#pragma mark -- Public Functions --
78
79void Lock ()
80{
81 if (!apiMutex) {
82 apiMutex = SDL_CreateMutex();
83 }
84 SDL_mutexP(apiMutex);
85}
86
87void Unlock ()
88{
89 SDL_mutexV(apiMutex);
90}
91
92int DetectAudioCDVolumes(FSVolumeRefNum *volumes, int numVolumes)
93{
94 int volumeIndex;
95 int cdVolumeCount = 0;
96 OSStatus result = noErr;
97
98 for (volumeIndex = 1; result == noErr || result != nsvErr; volumeIndex++)
99 {
100 FSVolumeRefNum actualVolume;
101 FSVolumeInfo volumeInfo;
102
103 memset (&volumeInfo, 0, sizeof(volumeInfo));
104
105 result = FSGetVolumeInfo (kFSInvalidVolumeRefNum,
106 volumeIndex,
107 &actualVolume,
108 kFSVolInfoFSInfo,
109 &volumeInfo,
110 NULL,
111 NULL);
112
113 if (result == noErr)
114 {
115 if (volumeInfo.filesystemID == kAudioCDFilesystemID) /* It's an audio CD */
116 {
117 if (volumes != NULL && cdVolumeCount < numVolumes)
118 volumes[cdVolumeCount] = actualVolume;
119
120 cdVolumeCount++;
121 }
122 }
123 else
124 {
125 /* I'm commenting this out because it seems to be harmless */
126 /*SDL_SetError ("DetectAudioCDVolumes: FSGetVolumeInfo returned %d", result);*/
127 }
128 }
129
130 return cdVolumeCount;
131}
132
133int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD)
134{
135 HFSUniStr255 dataForkName;
136 OSStatus theErr;
137 FSIORefNum forkRefNum;
138 SInt64 forkSize;
139 Ptr forkData = 0;
140 ByteCount actualRead;
141 CFDataRef dataRef = 0;
142 CFPropertyListRef propertyListRef = 0;
143 FSRefParam fsRefPB;
144 FSRef tocPlistFSRef;
145 FSRef rootRef;
146 const char* error = "Unspecified Error";
147 const UniChar uniName[] = { '.','T','O','C','.','p','l','i','s','t' };
148
149 theErr = FSGetVolumeInfo(theVolume, 0, 0, kFSVolInfoNone, 0, 0, &rootRef);
150 if(theErr != noErr) {
151 error = "FSGetVolumeInfo";
152 goto bail;
153 }
154
155 SDL_memset(&fsRefPB, '\0', sizeof (fsRefPB));
156
157 /* get stuff from .TOC.plist */
158 fsRefPB.ref = &rootRef;
159 fsRefPB.newRef = &tocPlistFSRef;
160 fsRefPB.nameLength = sizeof (uniName) / sizeof (uniName[0]);
161 fsRefPB.name = uniName;
162 fsRefPB.textEncodingHint = kTextEncodingUnknown;
163
164 theErr = PBMakeFSRefUnicodeSync (&fsRefPB);
165 if(theErr != noErr) {
166 error = "PBMakeFSRefUnicodeSync";
167 goto bail;
168 }
169
170 /* Load and parse the TOC XML data */
171
172 theErr = FSGetDataForkName (&dataForkName);
173 if (theErr != noErr) {
174 error = "FSGetDataForkName";
175 goto bail;
176 }
177
178 theErr = FSOpenFork (&tocPlistFSRef, dataForkName.length, dataForkName.unicode, fsRdPerm, &forkRefNum);
179 if (theErr != noErr) {
180 error = "FSOpenFork";
181 goto bail;
182 }
183
184 theErr = FSGetForkSize (forkRefNum, &forkSize);
185 if (theErr != noErr) {
186 error = "FSGetForkSize";
187 goto bail;
188 }
189
190 /* Allocate some memory for the XML data */
191 forkData = NewPtr (forkSize);
192 if(forkData == NULL) {
193 error = "NewPtr";
194 goto bail;
195 }
196
197 theErr = FSReadFork (forkRefNum, fsFromStart, 0 /* offset location */, forkSize, forkData, &actualRead);
198 if(theErr != noErr) {
199 error = "FSReadFork";
200 goto bail;
201 }
202
203 dataRef = CFDataCreate (kCFAllocatorDefault, (UInt8 *)forkData, forkSize);
204 if(dataRef == 0) {
205 error = "CFDataCreate";
206 goto bail;
207 }
208
209 propertyListRef = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
210 dataRef,
211 kCFPropertyListImmutable,
212 NULL);
213 if (propertyListRef == NULL) {
214 error = "CFPropertyListCreateFromXMLData";
215 goto bail;
216 }
217
218 /* Now we got the Property List in memory. Parse it. */
219
220 /* First, make sure the root item is a CFDictionary. If not, release and bail. */
221 if(CFGetTypeID(propertyListRef)== CFDictionaryGetTypeID())
222 {
223 CFDictionaryRef dictRef = (CFDictionaryRef)propertyListRef;
224
225 CFDataRef theRawTOCDataRef;
226 CFArrayRef theSessionArrayRef;
227 CFIndex numSessions;
228 CFIndex index;
229
230 /* This is how we get the Raw TOC Data */
231 theRawTOCDataRef = (CFDataRef)CFDictionaryGetValue (dictRef, CFSTR(kRawTOCDataString));
232
233 /* Get the session array info. */
234 theSessionArrayRef = (CFArrayRef)CFDictionaryGetValue (dictRef, CFSTR(kSessionsString));
235
236 /* Find out how many sessions there are. */
237 numSessions = CFArrayGetCount (theSessionArrayRef);
238
239 /* Initialize the total number of tracks to 0 */
240 theCD->numtracks = 0;
241
242 /* Iterate over all sessions, collecting the track data */
243 for(index = 0; index < numSessions; index++)
244 {
245 CFDictionaryRef theSessionDict;
246 CFNumberRef leadoutBlock;
247 CFArrayRef trackArray;
248 CFIndex numTracks;
249 CFIndex trackIndex;
250 UInt32 value = 0;
251
252 theSessionDict = (CFDictionaryRef) CFArrayGetValueAtIndex (theSessionArrayRef, index);
253 leadoutBlock = (CFNumberRef) CFDictionaryGetValue (theSessionDict, CFSTR(kLeadoutBlockString));
254
255 trackArray = (CFArrayRef)CFDictionaryGetValue (theSessionDict, CFSTR(kTrackArrayString));
256
257 numTracks = CFArrayGetCount (trackArray);
258
259 for(trackIndex = 0; trackIndex < numTracks; trackIndex++) {
260
261 CFDictionaryRef theTrackDict;
262 CFNumberRef trackNumber;
263 CFNumberRef sessionNumber;
264 CFNumberRef startBlock;
265 CFBooleanRef isDataTrack;
266 UInt32 value;
267
268 theTrackDict = (CFDictionaryRef) CFArrayGetValueAtIndex (trackArray, trackIndex);
269
270 trackNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kPointKeyString));
271 sessionNumber = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kSessionNumberKeyString));
272 startBlock = (CFNumberRef) CFDictionaryGetValue (theTrackDict, CFSTR(kStartBlockKeyString));
273 isDataTrack = (CFBooleanRef) CFDictionaryGetValue (theTrackDict, CFSTR(kDataKeyString));
274
275 /* Fill in the SDL_CD struct */
276 int idx = theCD->numtracks++;
277
278 CFNumberGetValue (trackNumber, kCFNumberSInt32Type, &value);
279 theCD->track[idx].id = value;
280
281 CFNumberGetValue (startBlock, kCFNumberSInt32Type, &value);
282 theCD->track[idx].offset = value;
283
284 theCD->track[idx].type = (isDataTrack == kCFBooleanTrue) ? SDL_DATA_TRACK : SDL_AUDIO_TRACK;
285
286 /* Since the track lengths are not stored in .TOC.plist we compute them. */
287 if (trackIndex > 0) {
288 theCD->track[idx-1].length = theCD->track[idx].offset - theCD->track[idx-1].offset;
289 }
290 }
291
292 /* Compute the length of the last track */
293 CFNumberGetValue (leadoutBlock, kCFNumberSInt32Type, &value);
294
295 theCD->track[theCD->numtracks-1].length =
296 value - theCD->track[theCD->numtracks-1].offset;
297
298 /* Set offset to leadout track */
299 theCD->track[theCD->numtracks].offset = value;
300 }
301
302 }
303
304 theErr = 0;
305 goto cleanup;
306bail:
307 SDL_SetError ("ReadTOCData: %s returned %d", error, theErr);
308 theErr = -1;
309cleanup:
310
311 if (propertyListRef != NULL)
312 CFRelease(propertyListRef);
313 if (dataRef != NULL)
314 CFRelease(dataRef);
315 if (forkData != NULL)
316 DisposePtr(forkData);
317
318 FSCloseFork (forkRefNum);
319
320 return theErr;
321}
322
323int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks)
324{
325 OSStatus result = -1;
326 FSIterator iterator;
327 ItemCount actualObjects;
328 FSRef rootDirectory;
329 FSRef ref;
330 HFSUniStr255 nameStr;
331
332 result = FSGetVolumeInfo (theVolume,
333 0,
334 NULL,
335 kFSVolInfoFSInfo,
336 NULL,
337 NULL,
338 &rootDirectory);
339
340 if (result != noErr) {
341 SDL_SetError ("ListTrackFiles: FSGetVolumeInfo returned %d", result);
342 return result;
343 }
344
345 result = FSOpenIterator (&rootDirectory, kFSIterateFlat, &iterator);
346 if (result == noErr) {
347 do
348 {
349 result = FSGetCatalogInfoBulk (iterator, 1, &actualObjects,
350 NULL, kFSCatInfoNone, NULL, &ref, NULL, &nameStr);
351 if (result == noErr) {
352
353 CFStringRef name;
354 name = CFStringCreateWithCharacters (NULL, nameStr.unicode, nameStr.length);
355
356 /* Look for .aiff extension */
357 if (CFStringHasSuffix (name, CFSTR(".aiff")) ||
358 CFStringHasSuffix (name, CFSTR(".cdda"))) {
359
360 /* Extract the track id from the filename */
361 int trackID = 0, i = 0;
362 while (i < nameStr.length && !isdigit(nameStr.unicode[i])) {
363 ++i;
364 }
365 while (i < nameStr.length && isdigit(nameStr.unicode[i])) {
366 trackID = 10 * trackID +(nameStr.unicode[i] - '0');
367 ++i;
368 }
369
370 #if DEBUG_CDROM
371 printf("Found AIFF for track %d: '%s'\n", trackID,
372 CFStringGetCStringPtr (name, CFStringGetSystemEncoding()));
373 #endif
374
375 /* Track ID's start at 1, but we want to start at 0 */
376 trackID--;
377
378 assert(0 <= trackID && trackID <= SDL_MAX_TRACKS);
379
380 if (trackID < numTracks)
381 memcpy (&trackFiles[trackID], &ref, sizeof(FSRef));
382 }
383 CFRelease (name);
384 }
385 } while(noErr == result);
386 FSCloseIterator (iterator);
387 }
388
389 return 0;
390}
391
392int LoadFile (const FSRef *ref, int startFrame, int stopFrame)
393{
394 int error = -1;
395
396 if (CheckInit () < 0)
397 goto bail;
398
399 /* release any currently playing file */
400 if (ReleaseFile () < 0)
401 goto bail;
402
403 #if DEBUG_CDROM
404 printf ("LoadFile: %d %d\n", startFrame, stopFrame);
405 #endif
406
407 /*try {*/
408
409 /* create a new player, and attach to the audio unit */
410
411 thePlayer = new_AudioFilePlayer(ref);
412 if (thePlayer == NULL) {
413 SDL_SetError ("LoadFile: Could not create player");
414 return -3; /*throw (-3);*/
415 }
416
417 if (!thePlayer->SetDestination(thePlayer, &theUnit))
418 goto bail;
419
420 if (startFrame >= 0)
421 thePlayer->SetStartFrame (thePlayer, startFrame);
422
423 if (stopFrame >= 0 && stopFrame > startFrame)
424 thePlayer->SetStopFrame (thePlayer, stopFrame);
425
426 /* we set the notifier later */
427 /*thePlayer->SetNotifier(thePlayer, FilePlayNotificationHandler, NULL);*/
428
429 if (!thePlayer->Connect(thePlayer))
430 goto bail;
431
432 #if DEBUG_CDROM
433 thePlayer->Print(thePlayer);
434 fflush (stdout);
435 #endif
436 /*}
437 catch (...)
438 {
439 goto bail;
440 }*/
441
442 error = 0;
443
444 bail:
445 return error;
446}
447
448int ReleaseFile ()
449{
450 int error = -1;
451
452 /* (Don't see any way that the original C++ code could throw here.) --ryan. */
453 /*try {*/
454 if (thePlayer != NULL) {
455
456 thePlayer->Disconnect(thePlayer);
457
458 delete_AudioFilePlayer(thePlayer);
459
460 thePlayer = NULL;
461 }
462 /*}
463 catch (...)
464 {
465 goto bail;
466 }*/
467
468 error = 0;
469
470/* bail: */
471 return error;
472}
473
474int PlayFile ()
475{
476 OSStatus result = -1;
477
478 if (CheckInit () < 0)
479 goto bail;
480
481 /*try {*/
482
483 // start processing of the audio unit
484 result = AudioOutputUnitStart (theUnit);
485 if (result) goto bail; //THROW_RESULT("PlayFile: AudioOutputUnitStart")
486
487 /*}
488 catch (...)
489 {
490 goto bail;
491 }*/
492
493 result = 0;
494
495bail:
496 return result;
497}
498
499int PauseFile ()
500{
501 OSStatus result = -1;
502
503 if (CheckInit () < 0)
504 goto bail;
505
506 /*try {*/
507
508 /* stop processing the audio unit */
509 result = AudioOutputUnitStop (theUnit);
510 if (result) goto bail; /*THROW_RESULT("PauseFile: AudioOutputUnitStop")*/
511 /*}
512 catch (...)
513 {
514 goto bail;
515 }*/
516
517 result = 0;
518bail:
519 return result;
520}
521
522void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom)
523{
524 assert(thePlayer != NULL);
525
526 theCDROM = cdrom;
527 completionProc = proc;
528 thePlayer->SetNotifier (thePlayer, FilePlayNotificationHandler, cdrom);
529}
530
531int GetCurrentFrame ()
532{
533 int frame;
534
535 if (thePlayer == NULL)
536 frame = 0;
537 else
538 frame = thePlayer->GetCurrentFrame (thePlayer);
539
540 return frame;
541}
542
543
544#pragma mark -- Private Functions --
545
546static OSStatus CheckInit ()
547{
548 if (playBackWasInit)
549 return 0;
550
551 OSStatus result = noErr;
552
553 /* Create the callback semaphore */
554 callbackSem = SDL_CreateSemaphore(0);
555
556 /* Start callback thread */
557 SDL_CreateThread(RunCallBackThread, NULL);
558
559 { /*try {*/
560 ComponentDescription desc;
561
562 desc.componentType = kAudioUnitType_Output;
563 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
564 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
565 desc.componentFlags = 0;
566 desc.componentFlagsMask = 0;
567
568 Component comp = FindNextComponent (NULL, &desc);
569 if (comp == NULL) {
570 SDL_SetError ("CheckInit: FindNextComponent returned NULL");
571 if (result) return -1; //throw(internalComponentErr);
572 }
573
574 result = OpenAComponent (comp, &theUnit);
575 if (result) return -1; //THROW_RESULT("CheckInit: OpenAComponent")
576
577 // you need to initialize the output unit before you set it as a destination
578 result = AudioUnitInitialize (theUnit);
579 if (result) return -1; //THROW_RESULT("CheckInit: AudioUnitInitialize")
580
581
582 playBackWasInit = true;
583 }
584 /*catch (...)
585 {
586 return -1;
587 }*/
588
589 return 0;
590}
591
592static void FilePlayNotificationHandler(void * inRefCon, OSStatus inStatus)
593{
594 if (inStatus == kAudioFilePlay_FileIsFinished) {
595
596 /* notify non-CA thread to perform the callback */
597 SDL_SemPost(callbackSem);
598
599 } else if (inStatus == kAudioFilePlayErr_FilePlayUnderrun) {
600
601 SDL_SetError ("CDPlayer Notification: buffer underrun");
602 } else if (inStatus == kAudioFilePlay_PlayerIsUninitialized) {
603
604 SDL_SetError ("CDPlayer Notification: player is uninitialized");
605 } else {
606
607 SDL_SetError ("CDPlayer Notification: unknown error %ld", inStatus);
608 }
609}
610
611static int RunCallBackThread (void *param)
612{
613 for (;;) {
614
615 SDL_SemWait(callbackSem);
616
617 if (completionProc && theCDROM) {
618 #if DEBUG_CDROM
619 printf ("callback!\n");
620 #endif
621 (*completionProc)(theCDROM);
622 } else {
623 #if DEBUG_CDROM
624 printf ("callback?\n");
625 #endif
626 }
627 }
628
629 #if DEBUG_CDROM
630 printf ("thread dying now...\n");
631 #endif
632
633 return 0;
634}
635
636/*}; // extern "C" */
diff --git a/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.h b/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.h
deleted file mode 100644
index be1ac1826a..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/CDPlayer.h
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#ifndef __CDPlayer__H__
25#define __CDPlayer__H__ 1
26
27#include <string.h>
28
29#include <Carbon/Carbon.h>
30#include <CoreFoundation/CoreFoundation.h>
31#include <AudioUnit/AudioUnit.h>
32
33#include "SDL.h"
34#include "SDL_thread.h"
35#include "SDL_mutex.h"
36
37#ifdef __cplusplus
38extern "C" {
39#endif
40
41typedef void (*CDPlayerCompletionProc)(SDL_CD *cdrom) ;
42
43void Lock ();
44
45void Unlock();
46
47int LoadFile (const FSRef *ref, int startFrame, int endFrame); /* pass -1 to do nothing */
48
49int ReleaseFile ();
50
51int PlayFile ();
52
53int PauseFile ();
54
55void SetCompletionProc (CDPlayerCompletionProc proc, SDL_CD *cdrom);
56
57int ReadTOCData (FSVolumeRefNum theVolume, SDL_CD *theCD);
58
59int ListTrackFiles (FSVolumeRefNum theVolume, FSRef *trackFiles, int numTracks);
60
61int DetectAudioCDVolumes (FSVolumeRefNum *volumes, int numVolumes);
62
63int GetCurrentFrame ();
64
65#ifdef __cplusplus
66};
67#endif
68
69#endif /* __CD_Player__H__ */
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.c b/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.c
deleted file mode 100644
index e8caf1bf10..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.c
+++ /dev/null
@@ -1,199 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/*
25 Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
26
27 Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
28
29 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
30 ("Apple") in consideration of your agreement to the following terms, and your
31 use, installation, modification or redistribution of this Apple software
32 constitutes acceptance of these terms. If you do not agree with these terms,
33 please do not use, install, modify or redistribute this Apple software.
34
35 In consideration of your agreement to abide by the following terms, and subject
36 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
37 copyrights in this original Apple software (the "Apple Software"), to use,
38 reproduce, modify and redistribute the Apple Software, with or without
39 modifications, in source and/or binary forms; provided that if you redistribute
40 the Apple Software in its entirety and without modifications, you must retain
41 this notice and the following text and disclaimers in all such redistributions of
42 the Apple Software. Neither the name, trademarks, service marks or logos of
43 Apple Computer, Inc. may be used to endorse or promote products derived from the
44 Apple Software without specific prior written permission from Apple. Except as
45 expressly stated in this notice, no other rights or licenses, express or implied,
46 are granted by Apple herein, including but not limited to any patent rights that
47 may be infringed by your derivative works or by other works in which the Apple
48 Software may be incorporated.
49
50 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
51 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
52 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
54 COMBINATION WITH YOUR PRODUCTS.
55
56 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
57 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
58 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
60 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
61 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
62 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63*/
64/*=============================================================================
65 CAGuard.cp
66
67=============================================================================*/
68
69/*=============================================================================
70 Includes
71 =============================================================================*/
72
73/*
74#include <stdio.h>
75#include <stdlib.h>
76#include <string.h>
77*/
78#include "SDL_stdinc.h"
79
80/*#define NDEBUG 1*/
81/*
82#include <assert.h>
83*/
84#define assert(X)
85
86
87#include "SDLOSXCAGuard.h"
88
89/*#warning Need a try-based Locker too*/
90/*=============================================================================
91 SDLOSXCAGuard
92 =============================================================================*/
93
94static int SDLOSXCAGuard_Lock(SDLOSXCAGuard *cag)
95{
96 int theAnswer = 0;
97
98 if(pthread_self() != cag->mOwner)
99 {
100 OSStatus theError = pthread_mutex_lock(&cag->mMutex);
101 (void)theError;
102 assert(theError == 0);
103 cag->mOwner = pthread_self();
104 theAnswer = 1;
105 }
106
107 return theAnswer;
108}
109
110static void SDLOSXCAGuard_Unlock(SDLOSXCAGuard *cag)
111{
112 OSStatus theError;
113 assert(pthread_self() == cag->mOwner);
114
115 cag->mOwner = 0;
116 theError = pthread_mutex_unlock(&cag->mMutex);
117 (void)theError;
118 assert(theError == 0);
119}
120
121static int SDLOSXCAGuard_Try (SDLOSXCAGuard *cag, int *outWasLocked)
122{
123 int theAnswer = 0;
124 *outWasLocked = 0;
125
126 if (pthread_self() == cag->mOwner) {
127 theAnswer = 1;
128 *outWasLocked = 0;
129 } else {
130 OSStatus theError = pthread_mutex_trylock(&cag->mMutex);
131 if (theError == 0) {
132 cag->mOwner = pthread_self();
133 theAnswer = 1;
134 *outWasLocked = 1;
135 }
136 }
137
138 return theAnswer;
139}
140
141static void SDLOSXCAGuard_Wait(SDLOSXCAGuard *cag)
142{
143 OSStatus theError;
144 assert(pthread_self() == cag->mOwner);
145
146 cag->mOwner = 0;
147
148 theError = pthread_cond_wait(&cag->mCondVar, &cag->mMutex);
149 (void)theError;
150 assert(theError == 0);
151 cag->mOwner = pthread_self();
152}
153
154static void SDLOSXCAGuard_Notify(SDLOSXCAGuard *cag)
155{
156 OSStatus theError = pthread_cond_signal(&cag->mCondVar);
157 (void)theError;
158 assert(theError == 0);
159}
160
161
162SDLOSXCAGuard *new_SDLOSXCAGuard(void)
163{
164 OSStatus theError;
165 SDLOSXCAGuard *cag = (SDLOSXCAGuard *) SDL_malloc(sizeof (SDLOSXCAGuard));
166 if (cag == NULL)
167 return NULL;
168 SDL_memset(cag, '\0', sizeof (*cag));
169
170 #define SET_SDLOSXCAGUARD_METHOD(m) cag->m = SDLOSXCAGuard_##m
171 SET_SDLOSXCAGUARD_METHOD(Lock);
172 SET_SDLOSXCAGUARD_METHOD(Unlock);
173 SET_SDLOSXCAGUARD_METHOD(Try);
174 SET_SDLOSXCAGUARD_METHOD(Wait);
175 SET_SDLOSXCAGUARD_METHOD(Notify);
176 #undef SET_SDLOSXCAGUARD_METHOD
177
178 theError = pthread_mutex_init(&cag->mMutex, NULL);
179 (void)theError;
180 assert(theError == 0);
181
182 theError = pthread_cond_init(&cag->mCondVar, NULL);
183 (void)theError;
184 assert(theError == 0);
185
186 cag->mOwner = 0;
187 return cag;
188}
189
190void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag)
191{
192 if (cag != NULL)
193 {
194 pthread_mutex_destroy(&cag->mMutex);
195 pthread_cond_destroy(&cag->mCondVar);
196 SDL_free(cag);
197 }
198}
199
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.h b/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.h
deleted file mode 100644
index f22c6956fe..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/SDLOSXCAGuard.h
+++ /dev/null
@@ -1,116 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/*
25 Note: This file hasn't been modified so technically we have to keep the disclaimer :-(
26
27
28 Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
29
30 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
31 ("Apple") in consideration of your agreement to the following terms, and your
32 use, installation, modification or redistribution of this Apple software
33 constitutes acceptance of these terms. If you do not agree with these terms,
34 please do not use, install, modify or redistribute this Apple software.
35
36 In consideration of your agreement to abide by the following terms, and subject
37 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
38 copyrights in this original Apple software (the "Apple Software"), to use,
39 reproduce, modify and redistribute the Apple Software, with or without
40 modifications, in source and/or binary forms; provided that if you redistribute
41 the Apple Software in its entirety and without modifications, you must retain
42 this notice and the following text and disclaimers in all such redistributions of
43 the Apple Software. Neither the name, trademarks, service marks or logos of
44 Apple Computer, Inc. may be used to endorse or promote products derived from the
45 Apple Software without specific prior written permission from Apple. Except as
46 expressly stated in this notice, no other rights or licenses, express or implied,
47 are granted by Apple herein, including but not limited to any patent rights that
48 may be infringed by your derivative works or by other works in which the Apple
49 Software may be incorporated.
50
51 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
52 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
53 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
55 COMBINATION WITH YOUR PRODUCTS.
56
57 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
58 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
59 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
61 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
62 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
63 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64*/
65/*=============================================================================
66 CAGuard.h
67
68=============================================================================*/
69#if !defined(__CAGuard_h__)
70#define __CAGuard_h__
71
72/*=============================================================================
73 Includes
74 =============================================================================*/
75
76#include <CoreAudio/CoreAudioTypes.h>
77#include <pthread.h>
78
79
80/*=============================================================================
81 CAGuard
82
83 This is your typical mutex with signalling implemented via pthreads.
84 Lock() will return true if and only if the guard is locked on that call.
85 A thread that already has the guard will receive 'false' if it locks it
86 again. Use of the stack-based CAGuard::Locker class is highly recommended
87 to properly manage the recursive nesting. The Wait calls with timeouts
88 will return true if and only if the timeout period expired. They will
89 return false if they receive notification any other way.
90 =============================================================================*/
91
92typedef struct S_SDLOSXCAGuard
93{
94
95/* Construction/Destruction */
96/*public:*/
97/* Actions */
98/*public:*/
99 int (*Lock)(struct S_SDLOSXCAGuard *cag);
100 void (*Unlock)(struct S_SDLOSXCAGuard *cag);
101 int (*Try)(struct S_SDLOSXCAGuard *cag, int *outWasLocked); /* returns true if lock is free, false if not */
102 void (*Wait)(struct S_SDLOSXCAGuard *cag);
103 void (*Notify)(struct S_SDLOSXCAGuard *cag);
104
105/* Implementation */
106/*protected:*/
107 pthread_mutex_t mMutex;
108 pthread_cond_t mCondVar;
109 pthread_t mOwner;
110} SDLOSXCAGuard;
111
112SDLOSXCAGuard *new_SDLOSXCAGuard(void);
113void delete_SDLOSXCAGuard(SDLOSXCAGuard *cag);
114
115#endif
116
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom.c b/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom.c
deleted file mode 100644
index 5018750222..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom.c
+++ /dev/null
@@ -1,514 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#ifdef SDL_CDROM_MACOSX
25
26#include "SDL_syscdrom_c.h"
27
28#pragma mark -- Globals --
29
30static FSRef** tracks;
31static FSVolumeRefNum* volumes;
32static CDstatus status;
33static int nextTrackFrame;
34static int nextTrackFramesRemaining;
35static int fakeCD;
36static int currentTrack;
37static int didReadTOC;
38static int cacheTOCNumTracks;
39static int currentDrive; /* Only allow 1 drive in use at a time */
40
41#pragma mark -- Prototypes --
42
43static const char *SDL_SYS_CDName (int drive);
44static int SDL_SYS_CDOpen (int drive);
45static int SDL_SYS_CDGetTOC (SDL_CD *cdrom);
46static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position);
47static int SDL_SYS_CDPlay (SDL_CD *cdrom, int start, int length);
48static int SDL_SYS_CDPause (SDL_CD *cdrom);
49static int SDL_SYS_CDResume (SDL_CD *cdrom);
50static int SDL_SYS_CDStop (SDL_CD *cdrom);
51static int SDL_SYS_CDEject (SDL_CD *cdrom);
52static void SDL_SYS_CDClose (SDL_CD *cdrom);
53
54#pragma mark -- Helper Functions --
55
56/* Read a list of tracks from the volume */
57static int LoadTracks (SDL_CD *cdrom)
58{
59 /* Check if tracks are already loaded */
60 if ( tracks[cdrom->id] != NULL )
61 return 0;
62
63 /* Allocate memory for tracks */
64 tracks[cdrom->id] = (FSRef*) SDL_calloc (1, sizeof(**tracks) * cdrom->numtracks);
65 if (tracks[cdrom->id] == NULL) {
66 SDL_OutOfMemory ();
67 return -1;
68 }
69
70 /* Load tracks */
71 if (ListTrackFiles (volumes[cdrom->id], tracks[cdrom->id], cdrom->numtracks) < 0)
72 return -1;
73
74 return 0;
75}
76
77/* Find a file for a given start frame and length */
78static FSRef* GetFileForOffset (SDL_CD *cdrom, int start, int length, int *outStartFrame, int *outStopFrame)
79{
80 int i;
81
82 for (i = 0; i < cdrom->numtracks; i++) {
83
84 if (cdrom->track[i].offset <= start &&
85 start < (cdrom->track[i].offset + cdrom->track[i].length))
86 break;
87 }
88
89 if (i == cdrom->numtracks)
90 return NULL;
91
92 currentTrack = i;
93
94 *outStartFrame = start - cdrom->track[i].offset;
95
96 if ((*outStartFrame + length) < cdrom->track[i].length) {
97 *outStopFrame = *outStartFrame + length;
98 length = 0;
99 nextTrackFrame = -1;
100 nextTrackFramesRemaining = -1;
101 }
102 else {
103 *outStopFrame = -1;
104 length -= cdrom->track[i].length - *outStartFrame;
105 nextTrackFrame = cdrom->track[i+1].offset;
106 nextTrackFramesRemaining = length;
107 }
108
109 return &tracks[cdrom->id][i];
110}
111
112/* Setup another file for playback, or stop playback (called from another thread) */
113static void CompletionProc (SDL_CD *cdrom)
114{
115
116 Lock ();
117
118 if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
119
120 /* Load the next file to play */
121 int startFrame, stopFrame;
122 FSRef *file;
123
124 PauseFile ();
125 ReleaseFile ();
126
127 file = GetFileForOffset (cdrom, nextTrackFrame,
128 nextTrackFramesRemaining, &startFrame, &stopFrame);
129
130 if (file == NULL) {
131 status = CD_STOPPED;
132 Unlock ();
133 return;
134 }
135
136 LoadFile (file, startFrame, stopFrame);
137
138 SetCompletionProc (CompletionProc, cdrom);
139
140 PlayFile ();
141 }
142 else {
143
144 /* Release the current file */
145 PauseFile ();
146 ReleaseFile ();
147 status = CD_STOPPED;
148 }
149
150 Unlock ();
151}
152
153
154#pragma mark -- Driver Functions --
155
156/* Initialize */
157int SDL_SYS_CDInit (void)
158{
159 /* Initialize globals */
160 volumes = NULL;
161 tracks = NULL;
162 status = CD_STOPPED;
163 nextTrackFrame = -1;
164 nextTrackFramesRemaining = -1;
165 fakeCD = SDL_FALSE;
166 currentTrack = -1;
167 didReadTOC = SDL_FALSE;
168 cacheTOCNumTracks = -1;
169 currentDrive = -1;
170
171 /* Fill in function pointers */
172 SDL_CDcaps.Name = SDL_SYS_CDName;
173 SDL_CDcaps.Open = SDL_SYS_CDOpen;
174 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
175 SDL_CDcaps.Status = SDL_SYS_CDStatus;
176 SDL_CDcaps.Play = SDL_SYS_CDPlay;
177 SDL_CDcaps.Pause = SDL_SYS_CDPause;
178 SDL_CDcaps.Resume = SDL_SYS_CDResume;
179 SDL_CDcaps.Stop = SDL_SYS_CDStop;
180 SDL_CDcaps.Eject = SDL_SYS_CDEject;
181 SDL_CDcaps.Close = SDL_SYS_CDClose;
182
183 /*
184 Read the list of "drives"
185
186 This is currently a hack that infers drives from
187 mounted audio CD volumes, rather than
188 actual CD-ROM devices - which means it may not
189 act as expected sometimes.
190 */
191
192 /* Find out how many cd volumes are mounted */
193 SDL_numcds = DetectAudioCDVolumes (NULL, 0);
194
195 /*
196 If there are no volumes, fake a cd device
197 so tray empty can be reported.
198 */
199 if (SDL_numcds == 0) {
200
201 fakeCD = SDL_TRUE;
202 SDL_numcds = 1;
203 status = CD_TRAYEMPTY;
204
205 return 0;
206 }
207
208 /* Allocate space for volumes */
209 volumes = (FSVolumeRefNum*) SDL_calloc (1, sizeof(*volumes) * SDL_numcds);
210 if (volumes == NULL) {
211 SDL_OutOfMemory ();
212 return -1;
213 }
214
215 /* Allocate space for tracks */
216 tracks = (FSRef**) SDL_calloc (1, sizeof(*tracks) * (SDL_numcds + 1));
217 if (tracks == NULL) {
218 SDL_OutOfMemory ();
219 return -1;
220 }
221
222 /* Mark the end of the tracks array */
223 tracks[ SDL_numcds ] = (FSRef*)-1;
224
225 /*
226 Redetect, now save all volumes for later
227 Update SDL_numcds just in case it changed
228 */
229 {
230 int numVolumes = SDL_numcds;
231
232 SDL_numcds = DetectAudioCDVolumes (volumes, numVolumes);
233
234 /* If more cds suddenly show up, ignore them */
235 if (SDL_numcds > numVolumes) {
236 SDL_SetError ("Some CD's were added but they will be ignored");
237 SDL_numcds = numVolumes;
238 }
239 }
240
241 return 0;
242}
243
244/* Shutdown and cleanup */
245void SDL_SYS_CDQuit(void)
246{
247 ReleaseFile();
248
249 if (volumes != NULL)
250 free (volumes);
251
252 if (tracks != NULL) {
253
254 FSRef **ptr;
255 for (ptr = tracks; *ptr != (FSRef*)-1; ptr++)
256 if (*ptr != NULL)
257 free (*ptr);
258
259 free (tracks);
260 }
261}
262
263/* Get the Unix disk name of the volume */
264static const char *SDL_SYS_CDName (int drive)
265{
266 /*
267 * !!! FIXME: PBHGetVolParmsSync() is gone in 10.6,
268 * !!! FIXME: replaced with FSGetVolumeParms(), which
269 * !!! FIXME: isn't available before 10.5. :/
270 */
271 return "Mac OS X CD-ROM Device";
272
273#if 0
274 OSStatus err = noErr;
275 HParamBlockRec pb;
276 GetVolParmsInfoBuffer volParmsInfo;
277
278 if (fakeCD)
279 return "Fake CD-ROM Device";
280
281 pb.ioParam.ioNamePtr = NULL;
282 pb.ioParam.ioVRefNum = volumes[drive];
283 pb.ioParam.ioBuffer = (Ptr)&volParmsInfo;
284 pb.ioParam.ioReqCount = (SInt32)sizeof(volParmsInfo);
285 err = PBHGetVolParmsSync(&pb);
286
287 if (err != noErr) {
288 SDL_SetError ("PBHGetVolParmsSync returned %d", err);
289 return NULL;
290 }
291
292 return volParmsInfo.vMDeviceID;
293#endif
294}
295
296/* Open the "device" */
297static int SDL_SYS_CDOpen (int drive)
298{
299 /* Only allow 1 device to be open */
300 if (currentDrive >= 0) {
301 SDL_SetError ("Only one cdrom is supported");
302 return -1;
303 }
304 else
305 currentDrive = drive;
306
307 return drive;
308}
309
310/* Get the table of contents */
311static int SDL_SYS_CDGetTOC (SDL_CD *cdrom)
312{
313 if (fakeCD) {
314 SDL_SetError (kErrorFakeDevice);
315 return -1;
316 }
317
318 if (didReadTOC) {
319 cdrom->numtracks = cacheTOCNumTracks;
320 return 0;
321 }
322
323
324 ReadTOCData (volumes[cdrom->id], cdrom);
325 didReadTOC = SDL_TRUE;
326 cacheTOCNumTracks = cdrom->numtracks;
327
328 return 0;
329}
330
331/* Get CD-ROM status */
332static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position)
333{
334 if (position) {
335 int trackFrame;
336
337 Lock ();
338 trackFrame = GetCurrentFrame ();
339 Unlock ();
340
341 *position = cdrom->track[currentTrack].offset + trackFrame;
342 }
343
344 return status;
345}
346
347/* Start playback */
348static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
349{
350 int startFrame, stopFrame;
351 FSRef *ref;
352
353 if (fakeCD) {
354 SDL_SetError (kErrorFakeDevice);
355 return -1;
356 }
357
358 Lock();
359
360 if (LoadTracks (cdrom) < 0)
361 return -2;
362
363 if (PauseFile () < 0)
364 return -3;
365
366 if (ReleaseFile () < 0)
367 return -4;
368
369 ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame);
370 if (ref == NULL) {
371 SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d", start, length);
372 return -5;
373 }
374
375 if (LoadFile (ref, startFrame, stopFrame) < 0)
376 return -6;
377
378 SetCompletionProc (CompletionProc, cdrom);
379
380 if (PlayFile () < 0)
381 return -7;
382
383 status = CD_PLAYING;
384
385 Unlock();
386
387 return 0;
388}
389
390/* Pause playback */
391static int SDL_SYS_CDPause(SDL_CD *cdrom)
392{
393 if (fakeCD) {
394 SDL_SetError (kErrorFakeDevice);
395 return -1;
396 }
397
398 Lock ();
399
400 if (PauseFile () < 0) {
401 Unlock ();
402 return -2;
403 }
404
405 status = CD_PAUSED;
406
407 Unlock ();
408
409 return 0;
410}
411
412/* Resume playback */
413static int SDL_SYS_CDResume(SDL_CD *cdrom)
414{
415 if (fakeCD) {
416 SDL_SetError (kErrorFakeDevice);
417 return -1;
418 }
419
420 Lock ();
421
422 if (PlayFile () < 0) {
423 Unlock ();
424 return -2;
425 }
426
427 status = CD_PLAYING;
428
429 Unlock ();
430
431 return 0;
432}
433
434/* Stop playback */
435static int SDL_SYS_CDStop(SDL_CD *cdrom)
436{
437 if (fakeCD) {
438 SDL_SetError (kErrorFakeDevice);
439 return -1;
440 }
441
442 Lock ();
443
444 if (PauseFile () < 0) {
445 Unlock ();
446 return -2;
447 }
448
449 if (ReleaseFile () < 0) {
450 Unlock ();
451 return -3;
452 }
453
454 status = CD_STOPPED;
455
456 Unlock ();
457
458 return 0;
459}
460
461/* Eject the CD-ROM (Unmount the volume) */
462static int SDL_SYS_CDEject(SDL_CD *cdrom)
463{
464 OSStatus err;
465 pid_t dissenter;
466
467 if (fakeCD) {
468 SDL_SetError (kErrorFakeDevice);
469 return -1;
470 }
471
472 Lock ();
473
474 if (PauseFile () < 0) {
475 Unlock ();
476 return -2;
477 }
478
479 if (ReleaseFile () < 0) {
480 Unlock ();
481 return -3;
482 }
483
484 status = CD_STOPPED;
485
486 /* Eject the volume */
487 err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter);
488
489 if (err != noErr) {
490 Unlock ();
491 SDL_SetError ("PBUnmountVol returned %d", err);
492 return -4;
493 }
494
495 status = CD_TRAYEMPTY;
496
497 /* Invalidate volume and track info */
498 volumes[cdrom->id] = 0;
499 free (tracks[cdrom->id]);
500 tracks[cdrom->id] = NULL;
501
502 Unlock ();
503
504 return 0;
505}
506
507/* Close the CD-ROM */
508static void SDL_SYS_CDClose(SDL_CD *cdrom)
509{
510 currentDrive = -1;
511 return;
512}
513
514#endif /* SDL_CDROM_MACOSX */
diff --git a/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom_c.h b/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom_c.h
deleted file mode 100644
index 589c5897e6..0000000000
--- a/apps/plugins/sdl/src/cdrom/macosx/SDL_syscdrom_c.h
+++ /dev/null
@@ -1,136 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/* This is the Mac OS X / CoreAudio specific header for the SDL CD-ROM API
25 Contributed by Darrell Walisser and Max Horn
26 */
27
28/***********************************************************************************
29 Implementation Notes
30 *********************
31
32 This code has several limitations currently (all of which are proabaly fixable):
33
34 1. A CD-ROM device is inferred from a mounted cdfs volume, so device 0 is
35 not necessarily the first CD-ROM device on the system. (Somewhat easy to fix
36 by useing the device name from the volume id's to reorder the volumes)
37
38 2. You can only open and control 1 CD-ROM device at a time. (Challenging to fix,
39 due to extensive code restructuring)
40
41 3. The status reported by SDL_CDStatus only changes to from CD_PLAYING to CD_STOPPED in
42 1-second intervals (because the audio is buffered in 1-second chunks) If
43 the audio data is less than 1 second, the remainder is filled with silence.
44
45 If you need to play sequences back-to-back that are less that 1 second long,
46 use the frame position to determine when to play the next sequence, instead
47 of SDL_CDStatus.
48
49 This may be possible to fix with a clever usage of the AudioUnit API.
50
51 4. When new volumes are inserted, our volume information is not updated. The only way
52 to refresh this information is to reinit the CD-ROM subsystem of SDL. To fix this,
53 one would probably have to fix point 1 above first, then figure out how to register
54 for a notification when new media is mounted in order to perform an automatic
55 rescan for cdfs volumes.
56
57
58
59 So, here comes a description of how this all works.
60
61 < Initializing >
62
63 To get things rolling, we have to locate mounted volumes that contain
64 audio (since nearly all Macs don't have analog audio-in on the sound card).
65 That's easy, since these volumes have a flag that indicates this special
66 filesystem. See DetectAudioCDVolumes() in CDPlayer.cpp for this code.
67
68 Next, we parse the invisible .TOC.plist in the root of the volume, which gets us
69 the track information (number, offset, length, leadout, etc). See ReadTOCData() in
70 CDPlayer.cpp for the skinny on this.
71
72
73 < The Playback Loop >
74
75 Now come the tricky parts. Let's start with basic audio playback. When a frame
76 range to play is requested, we must first find the .aiff files on the volume,
77 hopefully in the right order. Since these files all begin with a number "1 Audio Track",
78 etc, this is used to determine the correct track order.
79
80 Once all files are determined, we have to find what file corresponds to the start
81 and length parameter to SDL_SYS_CDPlay(). Again, this is quite simple by walking the
82 cdrom's track list. At this point, we also save the offset to the next track and frames
83 remaining, if we're going to have to play another file after the first one. See
84 GetFileForOffset() for this code.
85
86 At this point we have all info needed to start playback, so we hand off to the LoadFile()
87 function, which proceeds to do its magic and plays back the file.
88
89 When the file is finished playing, CompletionProc() is invoked, at which time we can
90 play the next file if the previously saved next track and frames remaining
91 indicates that we should.
92
93
94 < Magic >
95
96 OK, so it's not really magic, but since I don't fully understand all the hidden details it
97 seems like it to me ;-) The API's involved are the AudioUnit and AudioFile API's. These
98 appear to be an extension of CoreAudio for creating modular playback and f/x entities.
99 The important thing is that CPU usage is very low and reliability is very high. You'd
100 be hard-pressed to find a way to stutter the playback with other CPU-intensive tasks.
101
102 One part of this magic is that it uses multiple threads, which carries the usual potential
103 for disaster if not handled carefully. Playback currently requires 4 additional threads:
104 1. The coreaudio runloop thread
105 2. The coreaudio device i/o thread
106 3. The file streaming thread
107 4. The notification/callback thread
108
109 The first 2 threads are necessary evil - CoreAudio creates this no matter what the situation
110 is (even the SDL sound implementation creates theses suckers). The last two are are created
111 by us.
112
113 The file is streamed from disk using a threaded double-buffer approach.
114 This way, the high latency operation of reading from disk can be performed without interrupting
115 the real-time device thread (which amounts to avoiding dropouts). The device thread grabs the
116 buffer that isn't being read and sends it to the CoreAudio mixer where it eventually gets
117 to the sound card.
118
119 The device thread posts a notification when the file streaming thread is out of data. This
120 notification must be handled in a separate thread to avoid potential deadlock in the
121 device thread. That's where the notification thread comes in. This thread is signaled
122 whenever a notification needs to be processed, so another file can be played back if need be.
123
124 The API in CDPlayer.cpp contains synchronization because otherwise both the notification thread
125 and main thread (or another other thread using the SDL CD api) can potentially call it at the same time.
126
127************************************************************************************/
128
129
130#include "SDL_cdrom.h"
131#include "../SDL_syscdrom.h"
132
133#include "CDPlayer.h"
134
135#define kErrorFakeDevice "Error: Cannot proceed since we're faking a CD-ROM device. Reinit the CD-ROM subsystem to scan for new volumes."
136