src/cdrom/macosx/SDL_syscdrom.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 09 May 2006 07:52:04 +0000
changeset 1793 4d66375c2012
parent 1635 92947e3a18db
child 1662 782fd950bd46
child 1895 c121d94672cb
child 4159 a1b03ba2fcd0
permissions -rw-r--r--
Date: Mon, 8 May 2006 14:19:30 -0700
From: Bob Ippolito
Subject: SDL trunk (r2346) and Mac OS X

As for all the Carbon warnings.. the two File Manager ones should be
easy to get rid of, the QuickDraw ones won't be so easy since that
requires actual refactoring.

PBUnmountVol -> FSEjectVolumeSync
FSClose -> FSCloseFork
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 
    30 static FSRef**         tracks;
    31 static FSVolumeRefNum* volumes;
    32 static CDstatus        status;
    33 static int             nextTrackFrame;
    34 static int             nextTrackFramesRemaining;
    35 static int             fakeCD;
    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 */
    40 
    41 #pragma mark -- Prototypes --
    42 
    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);
    53 
    54 #pragma mark -- Helper Functions --
    55 
    56 /* Read a list of tracks from the volume */
    57 static 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 */
    78 static 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) */
   113 static 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 */
   157 int 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 */
   245 void 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 */
   264 static const char *SDL_SYS_CDName (int drive)
   265 {
   266     OSStatus     err = noErr;
   267     HParamBlockRec  pb;
   268     GetVolParmsInfoBuffer   volParmsInfo;
   269    
   270     if (fakeCD)
   271         return "Fake CD-ROM Device";
   272 
   273     pb.ioParam.ioNamePtr = NULL;
   274     pb.ioParam.ioVRefNum = volumes[drive];
   275     pb.ioParam.ioBuffer = (Ptr)&volParmsInfo;
   276     pb.ioParam.ioReqCount = (SInt32)sizeof(volParmsInfo);
   277     err = PBHGetVolParmsSync(&pb);
   278 
   279     if (err != noErr) {
   280         SDL_SetError ("PBHGetVolParmsSync returned %d", err);
   281         return NULL;
   282     }
   283 
   284     return volParmsInfo.vMDeviceID;
   285 }
   286 
   287 /* Open the "device" */
   288 static int SDL_SYS_CDOpen (int drive)
   289 {
   290     /* Only allow 1 device to be open */
   291     if (currentDrive >= 0) {
   292         SDL_SetError ("Only one cdrom is supported");
   293         return -1;
   294     }
   295     else
   296         currentDrive = drive;
   297 
   298     return drive;
   299 }
   300 
   301 /* Get the table of contents */
   302 static int SDL_SYS_CDGetTOC (SDL_CD *cdrom)
   303 {
   304     if (fakeCD) {
   305         SDL_SetError (kErrorFakeDevice);
   306         return -1;
   307     }
   308     
   309     if (didReadTOC) {
   310         cdrom->numtracks = cacheTOCNumTracks;
   311         return 0;
   312     }
   313     
   314     
   315     ReadTOCData (volumes[cdrom->id], cdrom);
   316     didReadTOC = SDL_TRUE;
   317     cacheTOCNumTracks = cdrom->numtracks;
   318     
   319     return 0;
   320 }
   321 
   322 /* Get CD-ROM status */
   323 static CDstatus SDL_SYS_CDStatus (SDL_CD *cdrom, int *position)
   324 {
   325     if (position) {
   326         int trackFrame;
   327         
   328         Lock ();
   329         trackFrame = GetCurrentFrame ();
   330         Unlock ();
   331     
   332         *position = cdrom->track[currentTrack].offset + trackFrame;
   333     }
   334     
   335     return status;
   336 }
   337 
   338 /* Start playback */
   339 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
   340 {
   341     int startFrame, stopFrame;
   342     FSRef *ref;
   343     
   344     if (fakeCD) {
   345         SDL_SetError (kErrorFakeDevice);
   346         return -1;
   347     }
   348     
   349     Lock();
   350     
   351     if (LoadTracks (cdrom) < 0)
   352         return -2;
   353     
   354     if (PauseFile () < 0)
   355         return -3;
   356         
   357     if (ReleaseFile () < 0)
   358         return -4;
   359     
   360     ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame);
   361     if (ref == NULL) {
   362         SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d", start, length);
   363         return -5;
   364     }
   365     
   366     if (LoadFile (ref, startFrame, stopFrame) < 0)
   367         return -6;
   368     
   369     SetCompletionProc (CompletionProc, cdrom);
   370     
   371     if (PlayFile () < 0)
   372         return -7;
   373     
   374     status = CD_PLAYING;
   375     
   376     Unlock();
   377     
   378     return 0;
   379 }
   380 
   381 /* Pause playback */
   382 static int SDL_SYS_CDPause(SDL_CD *cdrom)
   383 {
   384     if (fakeCD) {
   385         SDL_SetError (kErrorFakeDevice);
   386         return -1;
   387     }
   388     
   389     Lock ();
   390     
   391     if (PauseFile () < 0) {
   392         Unlock ();
   393         return -2;
   394     }
   395     
   396     status = CD_PAUSED;
   397     
   398     Unlock ();
   399     
   400     return 0;
   401 }
   402 
   403 /* Resume playback */
   404 static int SDL_SYS_CDResume(SDL_CD *cdrom)
   405 {
   406     if (fakeCD) {
   407         SDL_SetError (kErrorFakeDevice);
   408         return -1;
   409     }
   410     
   411     Lock ();
   412     
   413     if (PlayFile () < 0) {
   414         Unlock ();
   415         return -2;
   416     }
   417         
   418     status = CD_PLAYING;
   419     
   420     Unlock ();
   421     
   422     return 0;
   423 }
   424 
   425 /* Stop playback */
   426 static int SDL_SYS_CDStop(SDL_CD *cdrom)
   427 {
   428     if (fakeCD) {
   429         SDL_SetError (kErrorFakeDevice);
   430         return -1;
   431     }
   432     
   433     Lock ();
   434     
   435     if (PauseFile () < 0) {
   436         Unlock ();
   437         return -2;
   438     }
   439         
   440     if (ReleaseFile () < 0) {
   441         Unlock ();
   442         return -3;
   443     }
   444         
   445     status = CD_STOPPED;
   446     
   447     Unlock ();
   448     
   449     return 0;
   450 }
   451 
   452 /* Eject the CD-ROM (Unmount the volume) */
   453 static int SDL_SYS_CDEject(SDL_CD *cdrom)
   454 {
   455     OSStatus err;
   456     pid_t dissenter;
   457 
   458     if (fakeCD) {
   459         SDL_SetError (kErrorFakeDevice);
   460         return -1;
   461     }
   462     
   463     Lock ();
   464     
   465     if (PauseFile () < 0) {
   466         Unlock ();
   467         return -2;
   468     }
   469         
   470     if (ReleaseFile () < 0) {
   471         Unlock ();
   472         return -3;
   473     }
   474     
   475     status = CD_STOPPED;
   476     
   477 	/* Eject the volume */
   478 	err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter);
   479 
   480 	if (err != noErr) {
   481         Unlock ();
   482 		SDL_SetError ("PBUnmountVol returned %d", err);
   483 		return -4;
   484 	}
   485     
   486     status = CD_TRAYEMPTY;
   487 
   488     /* Invalidate volume and track info */
   489     volumes[cdrom->id] = 0;
   490     free (tracks[cdrom->id]);
   491     tracks[cdrom->id] = NULL;
   492     
   493     Unlock ();
   494     
   495     return 0;
   496 }
   497 
   498 /* Close the CD-ROM */
   499 static void SDL_SYS_CDClose(SDL_CD *cdrom)
   500 {
   501     currentDrive = -1;
   502     return;
   503 }
   504 
   505 #endif /* SDL_CDROM_MACOSX */