2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
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.
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.
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
22 #include "SDL_config.h"
24 #ifdef SDL_CDROM_MACOSX
26 #include "SDL_syscdrom_c.h"
28 #pragma mark -- Globals --
30 static FSRef** tracks;
31 static FSVolumeRefNum* volumes;
32 static CDstatus status;
33 static int nextTrackFrame;
34 static int nextTrackFramesRemaining;
36 static int currentTrack;
37 static int didReadTOC;
38 static int cacheTOCNumTracks;
39 static int currentDrive; /* Only allow 1 drive in use at a time */
41 #pragma mark -- Prototypes --
43 static const char *SDL_SYS_CDName (int drive);
44 static int SDL_SYS_CDOpen (int drive);
45 static int SDL_SYS_CDGetTOC (SDL_CD *cdrom);
46 static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position);
47 static int SDL_SYS_CDPlay (SDL_CD *cdrom, int start, int length);
48 static int SDL_SYS_CDPause (SDL_CD *cdrom);
49 static int SDL_SYS_CDResume (SDL_CD *cdrom);
50 static int SDL_SYS_CDStop (SDL_CD *cdrom);
51 static int SDL_SYS_CDEject (SDL_CD *cdrom);
52 static void SDL_SYS_CDClose (SDL_CD *cdrom);
54 #pragma mark -- Helper Functions --
56 /* Read a list of tracks from the volume */
57 static int LoadTracks (SDL_CD *cdrom)
59 /* Check if tracks are already loaded */
60 if ( tracks[cdrom->id] != NULL )
63 /* Allocate memory for tracks */
64 tracks[cdrom->id] = (FSRef*) SDL_calloc (1, sizeof(**tracks) * cdrom->numtracks);
65 if (tracks[cdrom->id] == NULL) {
71 if (ListTrackFiles (volumes[cdrom->id], tracks[cdrom->id], cdrom->numtracks) < 0)
77 /* Find a file for a given start frame and length */
78 static FSRef* GetFileForOffset (SDL_CD *cdrom, int start, int length, int *outStartFrame, int *outStopFrame)
82 for (i = 0; i < cdrom->numtracks; i++) {
84 if (cdrom->track[i].offset <= start &&
85 start < (cdrom->track[i].offset + cdrom->track[i].length))
89 if (i == cdrom->numtracks)
94 *outStartFrame = start - cdrom->track[i].offset;
96 if ((*outStartFrame + length) < cdrom->track[i].length) {
97 *outStopFrame = *outStartFrame + length;
100 nextTrackFramesRemaining = -1;
104 length -= cdrom->track[i].length - *outStartFrame;
105 nextTrackFrame = cdrom->track[i+1].offset;
106 nextTrackFramesRemaining = length;
109 return &tracks[cdrom->id][i];
112 /* Setup another file for playback, or stop playback (called from another thread) */
113 static void CompletionProc (SDL_CD *cdrom)
118 if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
120 /* Load the next file to play */
121 int startFrame, stopFrame;
127 file = GetFileForOffset (cdrom, nextTrackFrame,
128 nextTrackFramesRemaining, &startFrame, &stopFrame);
136 LoadFile (file, startFrame, stopFrame);
138 SetCompletionProc (CompletionProc, cdrom);
144 /* Release the current file */
154 #pragma mark -- Driver Functions --
157 int SDL_SYS_CDInit (void)
159 /* Initialize globals */
164 nextTrackFramesRemaining = -1;
167 didReadTOC = SDL_FALSE;
168 cacheTOCNumTracks = -1;
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;
184 Read the list of "drives"
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.
192 /* Find out how many cd volumes are mounted */
193 SDL_numcds = DetectAudioCDVolumes (NULL, 0);
196 If there are no volumes, fake a cd device
197 so tray empty can be reported.
199 if (SDL_numcds == 0) {
203 status = CD_TRAYEMPTY;
208 /* Allocate space for volumes */
209 volumes = (FSVolumeRefNum*) SDL_calloc (1, sizeof(*volumes) * SDL_numcds);
210 if (volumes == NULL) {
215 /* Allocate space for tracks */
216 tracks = (FSRef**) SDL_calloc (1, sizeof(*tracks) * (SDL_numcds + 1));
217 if (tracks == NULL) {
222 /* Mark the end of the tracks array */
223 tracks[ SDL_numcds ] = (FSRef*)-1;
226 Redetect, now save all volumes for later
227 Update SDL_numcds just in case it changed
230 int numVolumes = SDL_numcds;
232 SDL_numcds = DetectAudioCDVolumes (volumes, numVolumes);
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;
244 /* Shutdown and cleanup */
245 void SDL_SYS_CDQuit(void)
252 if (tracks != NULL) {
255 for (ptr = tracks; *ptr != (FSRef*)-1; ptr++)
263 /* Get the Unix disk name of the volume */
264 static const char *SDL_SYS_CDName (int drive)
267 * !!! FIXME: PBHGetVolParmsSync() is gone in 10.6,
268 * !!! FIXME: replaced with FSGetVolumeParms(), which
269 * !!! FIXME: isn't available before 10.5. :/
271 return "Mac OS X CD-ROM Device";
274 OSStatus err = noErr;
276 GetVolParmsInfoBuffer volParmsInfo;
279 return "Fake CD-ROM Device";
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);
288 SDL_SetError ("PBHGetVolParmsSync returned %d", err);
292 return volParmsInfo.vMDeviceID;
296 /* Open the "device" */
297 static int SDL_SYS_CDOpen (int drive)
299 /* Only allow 1 device to be open */
300 if (currentDrive >= 0) {
301 SDL_SetError ("Only one cdrom is supported");
305 currentDrive = drive;
310 /* Get the table of contents */
311 static int SDL_SYS_CDGetTOC (SDL_CD *cdrom)
314 SDL_SetError (kErrorFakeDevice);
319 cdrom->numtracks = cacheTOCNumTracks;
324 ReadTOCData (volumes[cdrom->id], cdrom);
325 didReadTOC = SDL_TRUE;
326 cacheTOCNumTracks = cdrom->numtracks;
331 /* Get CD-ROM status */
332 static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position)
338 trackFrame = GetCurrentFrame ();
341 *position = cdrom->track[currentTrack].offset + trackFrame;
348 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
350 int startFrame, stopFrame;
354 SDL_SetError (kErrorFakeDevice);
360 if (LoadTracks (cdrom) < 0)
363 if (PauseFile () < 0)
366 if (ReleaseFile () < 0)
369 ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame);
371 SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d", start, length);
375 if (LoadFile (ref, startFrame, stopFrame) < 0)
378 SetCompletionProc (CompletionProc, cdrom);
391 static int SDL_SYS_CDPause(SDL_CD *cdrom)
394 SDL_SetError (kErrorFakeDevice);
400 if (PauseFile () < 0) {
412 /* Resume playback */
413 static int SDL_SYS_CDResume(SDL_CD *cdrom)
416 SDL_SetError (kErrorFakeDevice);
422 if (PlayFile () < 0) {
435 static int SDL_SYS_CDStop(SDL_CD *cdrom)
438 SDL_SetError (kErrorFakeDevice);
444 if (PauseFile () < 0) {
449 if (ReleaseFile () < 0) {
461 /* Eject the CD-ROM (Unmount the volume) */
462 static int SDL_SYS_CDEject(SDL_CD *cdrom)
468 SDL_SetError (kErrorFakeDevice);
474 if (PauseFile () < 0) {
479 if (ReleaseFile () < 0) {
486 /* Eject the volume */
487 err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter);
491 SDL_SetError ("PBUnmountVol returned %d", err);
495 status = CD_TRAYEMPTY;
497 /* Invalidate volume and track info */
498 volumes[cdrom->id] = 0;
499 free (tracks[cdrom->id]);
500 tracks[cdrom->id] = NULL;
507 /* Close the CD-ROM */
508 static void SDL_SYS_CDClose(SDL_CD *cdrom)
514 #endif /* SDL_CDROM_MACOSX */