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