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