src/cdrom/win32/SDL_syscdrom.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. AddDrive
  2. SDL_SYS_CDInit
  3. SDL_SYS_CDioctl
  4. SDL_SYS_CDName
  5. SDL_SYS_CDOpen
  6. SDL_SYS_CDGetTOC
  7. SDL_SYS_CDStatus
  8. SDL_SYS_CDPlay
  9. SDL_SYS_CDPause
  10. SDL_SYS_CDResume
  11. SDL_SYS_CDStop
  12. SDL_SYS_CDEject
  13. SDL_SYS_CDClose
  14. SDL_SYS_CDQuit

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  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@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_syscdrom.c,v 1.2.2.2 2001/02/10 07:20:04 hercules Exp $";
  26 #endif
  27 
  28 /* Functions for system-level CD-ROM audio control */
  29 
  30 #include <stdlib.h>
  31 #include <stdio.h>
  32 #include <windows.h>
  33 #include <mmsystem.h>
  34 
  35 #include "SDL_error.h"
  36 #include "SDL_cdrom.h"
  37 #include "SDL_syscdrom.h"
  38 
  39 /* This really broken?? */
  40 #define BROKEN_MCI_PAUSE        /* Pausing actually stops play -- Doh! */
  41 
  42 /* The maximum number of CD-ROM drives we'll detect (Don't change!) */
  43 #define MAX_DRIVES      26      
  44 
  45 /* A list of available CD-ROM drives */
  46 static char *SDL_cdlist[MAX_DRIVES];
  47 static MCIDEVICEID SDL_mciID[MAX_DRIVES];
  48 #ifdef BROKEN_MCI_PAUSE
  49 static int SDL_paused[MAX_DRIVES];
  50 #endif
  51 
  52 /* The system-dependent CD control functions */
  53 static const char *SDL_SYS_CDName(int drive);
  54 static int SDL_SYS_CDOpen(int drive);
  55 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
  56 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
  57 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
  58 static int SDL_SYS_CDPause(SDL_CD *cdrom);
  59 static int SDL_SYS_CDResume(SDL_CD *cdrom);
  60 static int SDL_SYS_CDStop(SDL_CD *cdrom);
  61 static int SDL_SYS_CDEject(SDL_CD *cdrom);
  62 static void SDL_SYS_CDClose(SDL_CD *cdrom);
  63 
  64 
  65 /* Add a CD-ROM drive to our list of valid drives */
  66 static void AddDrive(char *drive)
     /* [<][>][^][v][top][bottom][index][help] */
  67 {
  68         int i;
  69 
  70         if ( SDL_numcds < MAX_DRIVES ) {
  71                 /* Add this drive to our list */
  72                 i = SDL_numcds;
  73                 SDL_cdlist[i] = (char *)malloc(strlen(drive)+1);
  74                 if ( SDL_cdlist[i] == NULL ) {
  75                         SDL_OutOfMemory();
  76                         return;
  77                 }
  78                 strcpy(SDL_cdlist[i], drive);
  79                 ++SDL_numcds;
  80 #ifdef CDROM_DEBUG
  81   fprintf(stderr, "Added CD-ROM drive: %s\n", drive);
  82 #endif
  83         }
  84 }
  85 
  86 int  SDL_SYS_CDInit(void)
     /* [<][>][^][v][top][bottom][index][help] */
  87 {
  88         /* checklist: Drive 'A' - 'Z' */
  89         int i;
  90         char drive[4];
  91 
  92         /* Fill in our driver capabilities */
  93         SDL_CDcaps.Name = SDL_SYS_CDName;
  94         SDL_CDcaps.Open = SDL_SYS_CDOpen;
  95         SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
  96         SDL_CDcaps.Status = SDL_SYS_CDStatus;
  97         SDL_CDcaps.Play = SDL_SYS_CDPlay;
  98         SDL_CDcaps.Pause = SDL_SYS_CDPause;
  99         SDL_CDcaps.Resume = SDL_SYS_CDResume;
 100         SDL_CDcaps.Stop = SDL_SYS_CDStop;
 101         SDL_CDcaps.Eject = SDL_SYS_CDEject;
 102         SDL_CDcaps.Close = SDL_SYS_CDClose;
 103 
 104         /* Scan the system for CD-ROM drives */
 105         for ( i='A'; i<='Z'; ++i ) {
 106                 sprintf(drive, "%c:\\", i);
 107                 if ( GetDriveType(drive) == DRIVE_CDROM ) {
 108                         AddDrive(drive);
 109                 }
 110         }
 111         memset(SDL_mciID, 0, sizeof(SDL_mciID));
 112         return(0);
 113 }
 114 
 115 /* General ioctl() CD-ROM command function */
 116 static int SDL_SYS_CDioctl(int id, UINT msg, DWORD flags, void *arg)
     /* [<][>][^][v][top][bottom][index][help] */
 117 {
 118         MCIERROR mci_error;
 119 
 120         mci_error = mciSendCommand(SDL_mciID[id], msg, flags, (DWORD)arg);
 121         if ( mci_error ) {
 122                 char error[256];
 123 
 124                 mciGetErrorString(mci_error, error, 256);
 125                 SDL_SetError("mciSendCommand() error: %s", error);
 126         }
 127         return(!mci_error ? 0 : -1);
 128 }
 129 
 130 static const char *SDL_SYS_CDName(int drive)
     /* [<][>][^][v][top][bottom][index][help] */
 131 {
 132         return(SDL_cdlist[drive]);
 133 }
 134 
 135 static int SDL_SYS_CDOpen(int drive)
     /* [<][>][^][v][top][bottom][index][help] */
 136 {
 137         MCI_OPEN_PARMS mci_open;
 138         MCI_SET_PARMS mci_set;
 139         char device[3];
 140         DWORD flags;
 141 
 142         /* Open the requested device */
 143         mci_open.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
 144         device[0] = *SDL_cdlist[drive];
 145         device[1] = ':';
 146         device[2] = '\0';
 147         mci_open.lpstrElementName = device;
 148         flags =
 149           (MCI_OPEN_TYPE|MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT);
 150         if ( SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0 ) {
 151                 flags &= ~MCI_OPEN_SHAREABLE;
 152                 if ( SDL_SYS_CDioctl(0, MCI_OPEN, flags, &mci_open) < 0 ) {
 153                         return(-1);
 154                 }
 155         }
 156         SDL_mciID[drive] = mci_open.wDeviceID;
 157 
 158         /* Set the minute-second-frame time format */
 159         mci_set.dwTimeFormat = MCI_FORMAT_MSF;
 160         SDL_SYS_CDioctl(drive, MCI_SET, MCI_SET_TIME_FORMAT, &mci_set);
 161 
 162 #ifdef BROKEN_MCI_PAUSE
 163         SDL_paused[drive] = 0;
 164 #endif
 165         return(drive);
 166 }
 167 
 168 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 169 {
 170         MCI_STATUS_PARMS mci_status;
 171         int i, okay;
 172         DWORD flags;
 173 
 174         okay = 0;
 175         mci_status.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
 176         flags = MCI_STATUS_ITEM | MCI_WAIT;
 177         if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0 ) {
 178                 cdrom->numtracks = mci_status.dwReturn;
 179                 if ( cdrom->numtracks > SDL_MAX_TRACKS ) {
 180                         cdrom->numtracks = SDL_MAX_TRACKS;
 181                 }
 182                 /* Read all the track TOC entries */
 183                 flags = MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT;
 184                 for ( i=0; i<cdrom->numtracks; ++i ) {
 185                         cdrom->track[i].id = i+1;
 186                         mci_status.dwTrack = cdrom->track[i].id;
 187 #ifdef MCI_CDA_STATUS_TYPE_TRACK
 188                         mci_status.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
 189                         if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
 190                                                         &mci_status) < 0 ) {
 191                                 break;
 192                         }
 193                         if ( mci_status.dwReturn == MCI_CDA_TRACK_AUDIO ) {
 194                                 cdrom->track[i].type = SDL_AUDIO_TRACK;
 195                         } else {
 196                                 cdrom->track[i].type = SDL_DATA_TRACK;
 197                         }
 198 #else
 199                         cdrom->track[i].type = SDL_AUDIO_TRACK;
 200 #endif
 201                         mci_status.dwItem = MCI_STATUS_POSITION;
 202                         if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
 203                                                         &mci_status) < 0 ) {
 204                                 break;
 205                         }
 206                         cdrom->track[i].offset = MSF_TO_FRAMES(
 207                                         MCI_MSF_MINUTE(mci_status.dwReturn),
 208                                         MCI_MSF_SECOND(mci_status.dwReturn),
 209                                         MCI_MSF_FRAME(mci_status.dwReturn));
 210                         cdrom->track[i].length = 0;
 211                         if ( i > 0 ) {
 212                                 cdrom->track[i-1].length =
 213                                                 cdrom->track[i].offset-
 214                                                 cdrom->track[i-1].offset;
 215                         }
 216                 }
 217                 if ( i == cdrom->numtracks ) {
 218                         flags &= ~MCI_TRACK;
 219                         mci_status.dwItem = MCI_STATUS_LENGTH;
 220                         if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
 221                                                         &mci_status) == 0 ) {
 222                                 cdrom->track[i].offset = MSF_TO_FRAMES(
 223                                         MCI_MSF_MINUTE(mci_status.dwReturn),
 224                                         MCI_MSF_SECOND(mci_status.dwReturn),
 225                                         MCI_MSF_FRAME(mci_status.dwReturn));
 226                                 cdrom->track[i].length = 0;
 227                                 cdrom->track[i-1].length =
 228                                                 cdrom->track[i].offset-
 229                                                 cdrom->track[i-1].offset;
 230                                 okay = 1;
 231                         }
 232                 }
 233         }
 234         return(okay ? 0 : -1);
 235 }
 236 
 237 /* Get CD-ROM status */
 238 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
     /* [<][>][^][v][top][bottom][index][help] */
 239 {
 240         CDstatus status;
 241         MCI_STATUS_PARMS mci_status;
 242         DWORD flags;
 243 
 244         flags = MCI_STATUS_ITEM | MCI_WAIT;
 245         mci_status.dwItem = MCI_STATUS_MODE;
 246         if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) < 0 ) {
 247                 status = CD_ERROR;
 248         } else {
 249                 switch (mci_status.dwReturn) {
 250                         case MCI_MODE_NOT_READY:
 251                         case MCI_MODE_OPEN:
 252                                 status = CD_TRAYEMPTY;
 253                                 break;
 254                         case MCI_MODE_STOP:
 255 #ifdef BROKEN_MCI_PAUSE
 256                                 if ( SDL_paused[cdrom->id] ) {
 257                                         status = CD_PAUSED;
 258                                 } else {
 259                                         status = CD_STOPPED;
 260                                 }
 261 #else
 262                                 status = CD_STOPPED;
 263 #endif /* BROKEN_MCI_PAUSE */
 264                                 break;
 265                         case MCI_MODE_PLAY:
 266                                 status = CD_PLAYING;
 267                                 break;
 268                         case MCI_MODE_PAUSE:
 269                                 status = CD_PAUSED;
 270                                 break;
 271                         default:
 272                                 status = CD_ERROR;
 273                                 break;
 274                 }
 275         }
 276         if ( position ) {
 277                 if ( status == CD_PLAYING || (status == CD_PAUSED) ) {
 278                         mci_status.dwItem = MCI_STATUS_POSITION;
 279                         if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags,
 280                                                         &mci_status) == 0 ) {
 281                                 *position = MSF_TO_FRAMES(
 282                                         MCI_MSF_MINUTE(mci_status.dwReturn),
 283                                         MCI_MSF_SECOND(mci_status.dwReturn),
 284                                         MCI_MSF_FRAME(mci_status.dwReturn));
 285                         } else {
 286                                 *position = 0;
 287                         }
 288                 } else {
 289                         *position = 0;
 290                 }
 291         }
 292         return(status);
 293 }
 294 
 295 /* Start play */
 296 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
     /* [<][>][^][v][top][bottom][index][help] */
 297 {
 298         MCI_PLAY_PARMS mci_play;
 299         int m, s, f;
 300         DWORD flags;
 301 
 302         flags = MCI_FROM | MCI_TO | MCI_NOTIFY;
 303         mci_play.dwCallback = 0;
 304         FRAMES_TO_MSF(start, &m, &s, &f);
 305         mci_play.dwFrom = MCI_MAKE_MSF(m, s, f);
 306         FRAMES_TO_MSF(start+length, &m, &s, &f);
 307         mci_play.dwTo = MCI_MAKE_MSF(m, s, f);
 308         return(SDL_SYS_CDioctl(cdrom->id, MCI_PLAY, flags, &mci_play));
 309 }
 310 
 311 /* Pause play */
 312 static int SDL_SYS_CDPause(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 313 {
 314 #ifdef BROKEN_MCI_PAUSE
 315         SDL_paused[cdrom->id] = 1;
 316 #endif
 317         return(SDL_SYS_CDioctl(cdrom->id, MCI_PAUSE, MCI_WAIT, NULL));
 318 }
 319 
 320 /* Resume play */
 321 static int SDL_SYS_CDResume(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 322 {
 323 #ifdef BROKEN_MCI_PAUSE
 324         MCI_STATUS_PARMS mci_status;
 325         int okay;
 326         int flags;
 327 
 328         okay = 0;
 329         /* Play from the current play position to end of CD */
 330         flags = MCI_STATUS_ITEM | MCI_WAIT;
 331         mci_status.dwItem = MCI_STATUS_POSITION;
 332         if ( SDL_SYS_CDioctl(cdrom->id, MCI_STATUS, flags, &mci_status) == 0 ) {
 333                 MCI_PLAY_PARMS mci_play;
 334 
 335                 flags = MCI_FROM | MCI_NOTIFY;
 336                 mci_play.dwCallback = 0;
 337                 mci_play.dwFrom = mci_status.dwReturn;
 338                 if (SDL_SYS_CDioctl(cdrom->id,MCI_PLAY,flags,&mci_play) == 0) {
 339                         okay = 1;
 340                         SDL_paused[cdrom->id] = 0;
 341                 }
 342         }
 343         return(okay ? 0 : -1);
 344 #else
 345         return(SDL_SYS_CDioctl(cdrom->id, MCI_RESUME, MCI_WAIT, NULL));
 346 #endif /* BROKEN_MCI_PAUSE */
 347 }
 348 
 349 /* Stop play */
 350 static int SDL_SYS_CDStop(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 351 {
 352         return(SDL_SYS_CDioctl(cdrom->id, MCI_STOP, MCI_WAIT, NULL));
 353 }
 354 
 355 /* Eject the CD-ROM */
 356 static int SDL_SYS_CDEject(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 357 {
 358         return(SDL_SYS_CDioctl(cdrom->id, MCI_SET, MCI_SET_DOOR_OPEN, NULL));
 359 }
 360 
 361 /* Close the CD-ROM handle */
 362 static void SDL_SYS_CDClose(SDL_CD *cdrom)
     /* [<][>][^][v][top][bottom][index][help] */
 363 {
 364         SDL_SYS_CDioctl(cdrom->id, MCI_CLOSE, MCI_WAIT, NULL);
 365 }
 366 
 367 void SDL_SYS_CDQuit(void)
     /* [<][>][^][v][top][bottom][index][help] */
 368 {
 369         int i;
 370 
 371         if ( SDL_numcds > 0 ) {
 372                 for ( i=0; i<SDL_numcds; ++i ) {
 373                         free(SDL_cdlist[i]);
 374                 }
 375                 SDL_numcds = 0;
 376         }
 377 }

/* [<][>][^][v][top][bottom][index][help] */