comparison src/cdrom/macosx/SDL_syscdrom.c @ 616:12c746afbc27

Oops...
author Sam Lantinga <slouken@libsdl.org>
date Sat, 26 Apr 2003 06:40:01 +0000
parents
children de1b2c3063b9
comparison
equal deleted inserted replaced
615:7ec821f3cbd0 616:12c746afbc27
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 #include "SDL_syscdrom_c.h"
29
30 #pragma mark -- Globals --
31
32 static FSRef** tracks;
33 static FSVolumeRefNum* volumes;
34 static CDstatus status;
35 static int nextTrackFrame;
36 static int nextTrackFramesRemaining;
37 static int fakeCD;
38 static int currentTrack;
39 static int didReadTOC;
40 static int cacheTOCNumTracks;
41 static int currentDrive; /* Only allow 1 drive in use at a time */
42
43 #pragma mark -- Prototypes --
44
45 static const char *SDL_SYS_CDName (int drive);
46 static int SDL_SYS_CDOpen (int drive);
47 static int SDL_SYS_CDGetTOC (SDL_CD *cdrom);
48 static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position);
49 static int SDL_SYS_CDPlay (SDL_CD *cdrom, int start, int length);
50 static int SDL_SYS_CDPause (SDL_CD *cdrom);
51 static int SDL_SYS_CDResume (SDL_CD *cdrom);
52 static int SDL_SYS_CDStop (SDL_CD *cdrom);
53 static int SDL_SYS_CDEject (SDL_CD *cdrom);
54 static void SDL_SYS_CDClose (SDL_CD *cdrom);
55
56 #pragma mark -- Helper Functions --
57
58 /* Read a list of tracks from the volume */
59 static int LoadTracks (SDL_CD *cdrom)
60 {
61 /* Check if tracks are already loaded */
62 if ( tracks[cdrom->id] != NULL )
63 return 0;
64
65 /* Allocate memory for tracks */
66 tracks[cdrom->id] = (FSRef*) calloc (1, sizeof(**tracks) * cdrom->numtracks);
67 if (tracks[cdrom->id] == NULL) {
68 SDL_OutOfMemory ();
69 return -1;
70 }
71
72 /* Load tracks */
73 if (ListTrackFiles (volumes[cdrom->id], tracks[cdrom->id], cdrom->numtracks) < 0)
74 return -1;
75
76 return 0;
77 }
78
79 /* Find a file for a given start frame and length */
80 static FSRef* GetFileForOffset (SDL_CD *cdrom, int start, int length, int *outStartFrame, int *outStopFrame)
81 {
82 int i;
83
84 for (i = 0; i < cdrom->numtracks; i++) {
85
86 if (cdrom->track[i].offset <= start &&
87 start < (cdrom->track[i].offset + cdrom->track[i].length))
88 break;
89 }
90
91 if (i == cdrom->numtracks)
92 return NULL;
93
94 currentTrack = i;
95
96 *outStartFrame = start - cdrom->track[i].offset;
97
98 if ((*outStartFrame + length) < cdrom->track[i].length) {
99 *outStopFrame = *outStartFrame + length;
100 length = 0;
101 nextTrackFrame = -1;
102 nextTrackFramesRemaining = -1;
103 }
104 else {
105 *outStopFrame = -1;
106 length -= cdrom->track[i].length - *outStartFrame;
107 nextTrackFrame = cdrom->track[i+1].offset;
108 nextTrackFramesRemaining = length;
109 }
110
111 return &tracks[cdrom->id][i];
112 }
113
114 /* Setup another file for playback, or stop playback (called from another thread) */
115 static void CompletionProc (SDL_CD *cdrom)
116 {
117
118 Lock ();
119
120 if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
121
122 /* Load the next file to play */
123 int startFrame, stopFrame;
124 FSRef *file;
125
126 PauseFile ();
127 ReleaseFile ();
128
129 file = GetFileForOffset (cdrom, nextTrackFrame,
130 nextTrackFramesRemaining, &startFrame, &stopFrame);
131
132 if (file == NULL) {
133 status = CD_STOPPED;
134 Unlock ();
135 return;
136 }
137
138 LoadFile (file, startFrame, stopFrame);
139
140 SetCompletionProc (CompletionProc, cdrom);
141
142 PlayFile ();
143 }
144 else {
145
146 /* Release the current file */
147 PauseFile ();
148 ReleaseFile ();
149 status = CD_STOPPED;
150 }
151
152 Unlock ();
153 }
154
155
156 #pragma mark -- Driver Functions --
157
158 /* Initialize */
159 int SDL_SYS_CDInit (void)
160 {
161 /* Initialize globals */
162 volumes = NULL;
163 tracks = NULL;
164 status = CD_STOPPED;
165 nextTrackFrame = -1;
166 nextTrackFramesRemaining = -1;
167 fakeCD = SDL_FALSE;
168 currentTrack = -1;
169 didReadTOC = SDL_FALSE;
170 cacheTOCNumTracks = -1;
171 currentDrive = -1;
172
173 /* Fill in function pointers */
174 SDL_CDcaps.Name = SDL_SYS_CDName;
175 SDL_CDcaps.Open = SDL_SYS_CDOpen;
176 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
177 SDL_CDcaps.Status = SDL_SYS_CDStatus;
178 SDL_CDcaps.Play = SDL_SYS_CDPlay;
179 SDL_CDcaps.Pause = SDL_SYS_CDPause;
180 SDL_CDcaps.Resume = SDL_SYS_CDResume;
181 SDL_CDcaps.Stop = SDL_SYS_CDStop;
182 SDL_CDcaps.Eject = SDL_SYS_CDEject;
183 SDL_CDcaps.Close = SDL_SYS_CDClose;
184
185 /*
186 Read the list of "drives"
187
188 This is currently a hack that infers drives from
189 mounted audio CD volumes, rather than
190 actual CD-ROM devices - which means it may not
191 act as expected sometimes.
192 */
193
194 /* Find out how many cd volumes are mounted */
195 SDL_numcds = DetectAudioCDVolumes (NULL, 0);
196
197 /*
198 If there are no volumes, fake a cd device
199 so tray empty can be reported.
200 */
201 if (SDL_numcds == 0) {
202
203 fakeCD = SDL_TRUE;
204 SDL_numcds = 1;
205 status = CD_TRAYEMPTY;
206
207 return 0;
208 }
209
210 /* Allocate space for volumes */
211 volumes = (FSVolumeRefNum*) calloc (1, sizeof(*volumes) * SDL_numcds);
212 if (volumes == NULL) {
213 SDL_OutOfMemory ();
214 return -1;
215 }
216
217 /* Allocate space for tracks */
218 tracks = (FSRef**) calloc (1, sizeof(*tracks) * (SDL_numcds + 1));
219 if (tracks == NULL) {
220 SDL_OutOfMemory ();
221 return -1;
222 }
223
224 /* Mark the end of the tracks array */
225 tracks[ SDL_numcds ] = (FSRef*)-1;
226
227 /*
228 Redetect, now save all volumes for later
229 Update SDL_numcds just in case it changed
230 */
231 {
232 int numVolumes = SDL_numcds;
233
234 SDL_numcds = DetectAudioCDVolumes (volumes, numVolumes);
235
236 /* If more cds suddenly show up, ignore them */
237 if (SDL_numcds > numVolumes) {
238 SDL_SetError ("Some CD's were added but they will be ignored");
239 SDL_numcds = numVolumes;
240 }
241 }
242
243 return 0;
244 }
245
246 /* Shutdown and cleanup */
247 void SDL_SYS_CDQuit(void)
248 {
249 ReleaseFile();
250
251 if (volumes != NULL)
252 free (volumes);
253
254 if (tracks != NULL) {
255
256 FSRef **ptr;
257 for (ptr = tracks; *ptr != (FSRef*)-1; ptr++)
258 if (*ptr != NULL)
259 free (*ptr);
260
261 free (tracks);
262 }
263 }
264
265 /* Get the Unix disk name of the volume */
266 static const char *SDL_SYS_CDName (int drive)
267 {
268 CFStringRef diskID;
269 OSStatus err = noErr;
270
271 if (fakeCD)
272 return "Fake CD-ROM Device";
273
274 err = FSCopyDiskIDForVolume (volumes[drive], &diskID);
275 if (err != noErr) {
276 SDL_SetError ("FSCopyDiskIDForVolume returned %d", err);
277 return NULL;
278 }
279
280 return CFStringGetCStringPtr (diskID, 0);
281 }
282
283 /* Open the "device" */
284 static int SDL_SYS_CDOpen (int drive)
285 {
286 /* Only allow 1 device to be open */
287 if (currentDrive >= 0) {
288 SDL_SetError ("Only one cdrom is supported");
289 return -1;
290 }
291 else
292 currentDrive = drive;
293
294 return drive;
295 }
296
297 /* Get the table of contents */
298 static int SDL_SYS_CDGetTOC (SDL_CD *cdrom)
299 {
300 if (fakeCD) {
301 SDL_SetError (kErrorFakeDevice);
302 return -1;
303 }
304
305 if (didReadTOC) {
306 cdrom->numtracks = cacheTOCNumTracks;
307 return 0;
308 }
309
310
311 ReadTOCData (volumes[cdrom->id], cdrom);
312 didReadTOC = SDL_TRUE;
313 cacheTOCNumTracks = cdrom->numtracks;
314
315 return 0;
316 }
317
318 /* Get CD-ROM status */
319 static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position)
320 {
321 int trackFrame;
322
323 Lock ();
324 trackFrame = GetCurrentFrame ();
325 Unlock ();
326
327 if (position)
328 *position = cdrom->track[currentTrack].offset + trackFrame;
329
330 return status;
331 }
332
333 /* Start playback */
334 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
335 {
336 int startFrame, stopFrame;
337 FSRef *ref;
338
339 if (fakeCD) {
340 SDL_SetError (kErrorFakeDevice);
341 return -1;
342 }
343
344 Lock();
345
346 if (LoadTracks (cdrom) < 0)
347 return -2;
348
349 if (PauseFile () < 0)
350 return -3;
351
352 if (ReleaseFile () < 0)
353 return -4;
354
355 ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame);
356 if (ref == NULL) {
357 SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d", start, length);
358 return -5;
359 }
360
361 if (LoadFile (ref, startFrame, stopFrame) < 0)
362 return -6;
363
364 SetCompletionProc (CompletionProc, cdrom);
365
366 if (PlayFile () < 0)
367 return -7;
368
369 status = CD_PLAYING;
370
371 Unlock();
372
373 return 0;
374 }
375
376 /* Pause playback */
377 static int SDL_SYS_CDPause(SDL_CD *cdrom)
378 {
379 if (fakeCD) {
380 SDL_SetError (kErrorFakeDevice);
381 return -1;
382 }
383
384 Lock ();
385
386 if (PauseFile () < 0)
387 return -2;
388
389 status = CD_PAUSED;
390
391 Unlock ();
392
393 return 0;
394 }
395
396 /* Resume playback */
397 static int SDL_SYS_CDResume(SDL_CD *cdrom)
398 {
399 if (fakeCD) {
400 SDL_SetError (kErrorFakeDevice);
401 return -1;
402 }
403
404 Lock ();
405
406 if (PlayFile () < 0)
407 return -2;
408
409 status = CD_PLAYING;
410
411 Unlock ();
412
413 return 0;
414 }
415
416 /* Stop playback */
417 static int SDL_SYS_CDStop(SDL_CD *cdrom)
418 {
419 if (fakeCD) {
420 SDL_SetError (kErrorFakeDevice);
421 return -1;
422 }
423
424 Lock ();
425
426 if (PauseFile () < 0)
427 return -2;
428
429 if (ReleaseFile () < 0)
430 return -3;
431
432 status = CD_STOPPED;
433
434 Unlock ();
435
436 return 0;
437 }
438
439 /* Eject the CD-ROM (Unmount the volume) */
440 static int SDL_SYS_CDEject(SDL_CD *cdrom)
441 {
442 OSStatus err;
443
444 if (fakeCD) {
445 SDL_SetError (kErrorFakeDevice);
446 return -1;
447 }
448
449 Lock ();
450
451 if (PauseFile () < 0)
452 return -2;
453
454 if (ReleaseFile () < 0)
455 return -3;
456
457 status = CD_STOPPED;
458
459 err = FSEjectVolumeSync (volumes[cdrom->id], 0, NULL);
460
461 if (err != noErr) {
462 SDL_SetError ("FSEjectVolumeSync returned %d", err);
463 return -4;
464 }
465
466 status = CD_TRAYEMPTY;
467
468 /* Invalidate volume and track info */
469 volumes[cdrom->id] = 0;
470 free (tracks[cdrom->id]);
471 tracks[cdrom->id] = NULL;
472
473 Unlock ();
474
475 return 0;
476 }
477
478 /* Close the CD-ROM */
479 static void SDL_SYS_CDClose(SDL_CD *cdrom)
480 {
481 currentDrive = -1;
482 return;
483 }
484