Improved GetRandomRegion().
[wine/wine-kai.git] / multimedia / mcicda.c
blob40f1fe521f79fcddea15a0a5c24185ad8c9404ef
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Sample MCI CDAUDIO Wine Driver for Linux
5 * Copyright 1994 Martin Ayotte
6 * Copyright 1998-99 Eric Pouech
7 */
9 #include "winuser.h"
10 #include "driver.h"
11 #include "multimedia.h"
12 #include "cdrom.h"
13 #include "debugtools.h"
15 DEFAULT_DEBUG_CHANNEL(cdaudio)
17 typedef struct {
18 UINT16 wDevID;
19 int nUseCount; /* Incremented for each shared open */
20 BOOL16 fShareable; /* TRUE if first open was shareable */
21 WORD wNotifyDeviceID; /* MCI device ID with a pending notification */
22 HANDLE16 hCallback; /* Callback handle for pending notification */
23 MCI_OPEN_PARMS16 openParms;
24 DWORD dwTimeFormat;
25 WINE_CDAUDIO wcda;
26 int mciMode;
27 } WINE_MCICDAUDIO;
29 /*-----------------------------------------------------------------------*/
31 /**************************************************************************
32 * CDAUDIO_drvOpen [internal]
34 static DWORD CDAUDIO_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
36 WINE_MCICDAUDIO* wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCICDAUDIO));
38 if (!wmcda)
39 return 0;
41 wmcda->wDevID = modp->wDeviceID;
42 mciSetDriverData(wmcda->wDevID, (DWORD)wmcda);
43 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
44 modp->wType = MCI_DEVTYPE_SEQUENCER;
45 return modp->wDeviceID;
48 /**************************************************************************
49 * CDAUDIO_drvClose [internal]
51 static DWORD CDAUDIO_drvClose(DWORD dwDevID)
53 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);
55 if (wmcda) {
56 HeapFree(GetProcessHeap(), 0, wmcda);
57 mciSetDriverData(dwDevID, 0);
59 return 0;
62 /**************************************************************************
63 * CDAUDIO_mciGetOpenDrv [internal]
65 static WINE_MCICDAUDIO* CDAUDIO_mciGetOpenDrv(UINT16 wDevID)
67 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
69 if (wmcda == NULL || wmcda->nUseCount == 0 || wmcda->wcda.unixdev <= 0) {
70 WARN("Invalid wDevID=%u\n", wDevID);
71 return 0;
73 return wmcda;
76 /**************************************************************************
77 * CDAUDIO_mciMode [internal]
79 static int CDAUDIO_mciMode(int wcdaMode)
81 switch (wcdaMode) {
82 case WINE_CDA_DONTKNOW: return MCI_MODE_STOP;
83 case WINE_CDA_NOTREADY: return MCI_MODE_STOP;
84 case WINE_CDA_OPEN: return MCI_MODE_OPEN;
85 case WINE_CDA_PLAY: return MCI_MODE_PLAY;
86 case WINE_CDA_STOP: return MCI_MODE_STOP;
87 case WINE_CDA_PAUSE: return MCI_MODE_PAUSE;
88 default:
89 FIXME("Unknown mode %04x\n", wcdaMode);
91 return MCI_MODE_STOP;
94 /**************************************************************************
95 * CDAUDIO_mciGetError [internal]
97 static int CDAUDIO_mciGetError(WINE_MCICDAUDIO* wmcda)
99 switch (wmcda->wcda.cdaMode) {
100 case WINE_CDA_DONTKNOW:
101 case WINE_CDA_NOTREADY: return MCIERR_DEVICE_NOT_READY;
102 case WINE_CDA_OPEN: return MCIERR_DEVICE_OPEN;
103 case WINE_CDA_PLAY:
104 case WINE_CDA_STOP:
105 case WINE_CDA_PAUSE: break;
106 default:
107 FIXME("Unknown mode %04x\n", wmcda->wcda.cdaMode);
109 return MCIERR_DRIVER_INTERNAL;
112 /**************************************************************************
113 * CDAUDIO_CalcFrame [internal]
115 static DWORD CDAUDIO_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime)
117 DWORD dwFrame = 0;
118 UINT16 wTrack;
120 TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwTime);
122 switch (wmcda->dwTimeFormat) {
123 case MCI_FORMAT_MILLISECONDS:
124 dwFrame = (dwTime * CDFRAMES_PERSEC) / 1000;
125 TRACE("MILLISECONDS %lu\n", dwFrame);
126 break;
127 case MCI_FORMAT_MSF:
128 TRACE("MSF %02u:%02u:%02u\n",
129 MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
130 dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
131 dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
132 dwFrame += MCI_MSF_FRAME(dwTime);
133 break;
134 case MCI_FORMAT_TMSF:
135 default:
136 /* unknown format ! force TMSF ! ... */
137 wTrack = MCI_TMSF_TRACK(dwTime);
138 TRACE("MSF %02u-%02u:%02u:%02u\n",
139 MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime),
140 MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
141 TRACE("TMSF trackpos[%u]=%lu\n",
142 wTrack, wmcda->wcda.lpdwTrackPos[wTrack - 1]);
143 dwFrame = wmcda->wcda.lpdwTrackPos[wTrack - 1];
144 dwFrame += CDFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
145 dwFrame += CDFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
146 dwFrame += MCI_TMSF_FRAME(dwTime);
147 break;
149 return dwFrame;
152 /**************************************************************************
153 * CDAUDIO_CalcTime [internal]
155 static DWORD CDAUDIO_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD dwFrame, LPDWORD lpRet)
157 DWORD dwTime = 0;
158 UINT16 wTrack;
159 UINT16 wMinutes;
160 UINT16 wSeconds;
161 UINT16 wFrames;
163 TRACE("(%p, %08lX, %lu);\n", wmcda, wmcda->dwTimeFormat, dwFrame);
165 switch (wmcda->dwTimeFormat) {
166 case MCI_FORMAT_MILLISECONDS:
167 dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC;
168 TRACE("MILLISECONDS %lu\n", dwTime);
169 *lpRet = 0;
170 break;
171 case MCI_FORMAT_MSF:
172 wMinutes = dwFrame / CDFRAMES_PERMIN;
173 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
174 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
175 dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
176 TRACE("MSF %02u:%02u:%02u -> dwTime=%lu\n",
177 wMinutes, wSeconds, wFrames, dwTime);
178 *lpRet = MCI_COLONIZED3_RETURN;
179 break;
180 case MCI_FORMAT_TMSF:
181 default:
182 /* unknown format ! force TMSF ! ... */
183 for (wTrack = 0; wTrack < wmcda->wcda.nTracks; wTrack++) {
184 /*dwTime += wmcda->lpdwTrackLen[wTrack - 1];
185 TRACE("Adding trk#%u curpos=%u \n", dwTime);
186 if (dwTime >= dwFrame) break; */
187 if (wmcda->wcda.lpdwTrackPos[wTrack - 1] >= dwFrame) break;
189 wMinutes = dwFrame / CDFRAMES_PERMIN;
190 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
191 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
192 dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
193 TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
194 *lpRet = MCI_COLONIZED4_RETURN;
195 break;
197 return dwTime;
200 static DWORD CDAUDIO_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms);
201 static DWORD CDAUDIO_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
203 /**************************************************************************
204 * CDAUDIO_mciOpen [internal]
206 static DWORD CDAUDIO_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSA lpOpenParms)
208 DWORD dwDeviceID;
209 WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
210 MCI_SEEK_PARMS seekParms;
212 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpOpenParms);
214 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
215 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
217 dwDeviceID = lpOpenParms->wDeviceID;
219 if (wmcda->nUseCount > 0) {
220 /* The driver is already open on this channel */
221 /* If the driver was opened shareable before and this open specifies */
222 /* shareable then increment the use count */
223 if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
224 ++wmcda->nUseCount;
225 else
226 return MCIERR_MUST_USE_SHAREABLE;
227 } else {
228 wmcda->nUseCount = 1;
229 wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
231 if (dwFlags & MCI_OPEN_ELEMENT) {
232 TRACE("MCI_OPEN_ELEMENT !\n");
233 /* return MCIERR_NO_ELEMENT_ALLOWED; */
236 wmcda->openParms.dwCallback = lpOpenParms->dwCallback;
237 wmcda->openParms.wDeviceID = (WORD)lpOpenParms->wDeviceID;
238 wmcda->openParms.wReserved0 = 0; /*????*/
239 wmcda->openParms.lpstrDeviceType = lpOpenParms->lpstrDeviceType;
240 wmcda->openParms.lpstrElementName = lpOpenParms->lpstrElementName;
241 wmcda->openParms.lpstrAlias = lpOpenParms->lpstrAlias;
243 wmcda->wNotifyDeviceID = dwDeviceID;
244 if (CDAUDIO_Open(&wmcda->wcda) == -1) {
245 --wmcda->nUseCount;
246 return MCIERR_HARDWARE;
248 wmcda->mciMode = MCI_MODE_STOP;
249 wmcda->dwTimeFormat = MCI_FORMAT_TMSF;
250 if (!CDAUDIO_GetTracksInfo(&wmcda->wcda)) {
251 WARN("error reading TracksInfo !\n");
252 /* return MCIERR_INTERNAL; */
255 CDAUDIO_mciSeek(wDevID, MCI_SEEK_TO_START, &seekParms);
257 return 0;
260 /**************************************************************************
261 * CDAUDIO_mciClose [internal]
263 static DWORD CDAUDIO_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
265 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
267 TRACE("(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
269 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
271 if (wmcda->nUseCount == 1) {
272 /* FIXME: I don't think we have to stop CD on exit
273 * CDAUDIO_mciStop(wDevID, 0, NULL);
275 CDAUDIO_Close(&wmcda->wcda);
277 wmcda->nUseCount--;
278 return 0;
281 /**************************************************************************
282 * CDAUDIO_mciGetDevCaps [internal]
284 static DWORD CDAUDIO_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags,
285 LPMCI_GETDEVCAPS_PARMS lpParms)
287 DWORD ret = 0;
289 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
291 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
293 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
294 TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n", lpParms->dwItem);
296 switch (lpParms->dwItem) {
297 case MCI_GETDEVCAPS_CAN_RECORD:
298 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
299 ret = MCI_RESOURCE_RETURNED;
300 break;
301 case MCI_GETDEVCAPS_HAS_AUDIO:
302 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
303 ret = MCI_RESOURCE_RETURNED;
304 break;
305 case MCI_GETDEVCAPS_HAS_VIDEO:
306 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
307 ret = MCI_RESOURCE_RETURNED;
308 break;
309 case MCI_GETDEVCAPS_DEVICE_TYPE:
310 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
311 ret = MCI_RESOURCE_RETURNED;
312 break;
313 case MCI_GETDEVCAPS_USES_FILES:
314 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
315 ret = MCI_RESOURCE_RETURNED;
316 break;
317 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
318 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
319 ret = MCI_RESOURCE_RETURNED;
320 break;
321 case MCI_GETDEVCAPS_CAN_EJECT:
322 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
323 ret = MCI_RESOURCE_RETURNED;
324 break;
325 case MCI_GETDEVCAPS_CAN_PLAY:
326 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
327 ret = MCI_RESOURCE_RETURNED;
328 break;
329 case MCI_GETDEVCAPS_CAN_SAVE:
330 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
331 ret = MCI_RESOURCE_RETURNED;
332 break;
333 default:
334 ERR("Unsupported %lx devCaps item\n", lpParms->dwItem);
335 return MCIERR_UNRECOGNIZED_COMMAND;
337 } else {
338 TRACE("No GetDevCaps-Item !\n");
339 return MCIERR_UNRECOGNIZED_COMMAND;
341 TRACE("lpParms->dwReturn=%08lX;\n", lpParms->dwReturn);
342 return ret;
345 /**************************************************************************
346 * CDAUDIO_mciInfo [internal]
348 static DWORD CDAUDIO_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
350 LPSTR str = 0;
351 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
353 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
355 if (lpParms == NULL || lpParms->lpstrReturn == NULL)
356 return MCIERR_NULL_PARAMETER_BLOCK;
357 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
359 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
361 switch(dwFlags) {
362 case MCI_INFO_PRODUCT:
363 str = "Wine's audio CD";
364 break;
365 default:
366 WARN("Don't know this info command (%lu)\n", dwFlags);
367 return MCIERR_UNRECOGNIZED_COMMAND;
369 return MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, str);
372 /**************************************************************************
373 * CDAUDIO_mciStatus [internal]
375 static DWORD CDAUDIO_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
377 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
378 DWORD ret = 0;
380 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
382 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
383 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
385 if (dwFlags & MCI_NOTIFY) {
386 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
387 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
388 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
390 if (dwFlags & MCI_STATUS_ITEM) {
391 switch (lpParms->dwItem) {
392 case MCI_STATUS_CURRENT_TRACK:
393 if (!CDAUDIO_GetCDStatus(&wmcda->wcda)) {
394 return CDAUDIO_mciGetError(wmcda);
396 lpParms->dwReturn = wmcda->wcda.nCurTrack;
397 TRACE("CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
398 break;
399 case MCI_STATUS_LENGTH:
400 if (wmcda->wcda.nTracks == 0) {
401 if (!CDAUDIO_GetTracksInfo(&wmcda->wcda)) {
402 WARN("error reading TracksInfo !\n");
403 return CDAUDIO_mciGetError(wmcda);
406 if (dwFlags & MCI_TRACK) {
407 TRACE("MCI_TRACK #%lu LENGTH=??? !\n", lpParms->dwTrack);
408 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
409 return MCIERR_OUTOFRANGE;
410 lpParms->dwReturn = wmcda->wcda.lpdwTrackLen[lpParms->dwTrack - 1];
411 } else {
412 lpParms->dwReturn = wmcda->wcda.dwTotalLen;
414 lpParms->dwReturn = CDAUDIO_CalcTime(wmcda, lpParms->dwReturn, &ret);
415 TRACE("LENGTH=%lu !\n", lpParms->dwReturn);
416 break;
417 case MCI_STATUS_MODE:
418 if (!CDAUDIO_GetCDStatus(&wmcda->wcda))
419 return CDAUDIO_mciGetError(wmcda);
420 lpParms->dwReturn = CDAUDIO_mciMode(wmcda->wcda.cdaMode);
421 if (!lpParms->dwReturn) lpParms->dwReturn = wmcda->mciMode;
422 TRACE("MCI_STATUS_MODE=%08lX !\n", lpParms->dwReturn);
423 lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
424 ret = MCI_RESOURCE_RETURNED;
425 break;
426 case MCI_STATUS_MEDIA_PRESENT:
427 if (!CDAUDIO_GetCDStatus(&wmcda->wcda))
428 return CDAUDIO_mciGetError(wmcda);
429 lpParms->dwReturn = (wmcda->wcda.nTracks == 0) ?
430 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
431 TRACE("MCI_STATUS_MEDIA_PRESENT =%s!\n", LOWORD(lpParms->dwReturn) ? "Y" : "N");
432 ret = MCI_RESOURCE_RETURNED;
433 break;
434 case MCI_STATUS_NUMBER_OF_TRACKS:
435 lpParms->dwReturn = CDAUDIO_GetNumberOfTracks(&wmcda->wcda);
436 TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n", lpParms->dwReturn);
437 if (lpParms->dwReturn == (WORD)-1)
438 return CDAUDIO_mciGetError(wmcda);
439 break;
440 case MCI_STATUS_POSITION:
441 if (!CDAUDIO_GetCDStatus(&wmcda->wcda))
442 return CDAUDIO_mciGetError(wmcda);
443 lpParms->dwReturn = wmcda->wcda.dwCurFrame;
444 if (dwFlags & MCI_STATUS_START) {
445 lpParms->dwReturn = wmcda->wcda.dwFirstOffset;
446 TRACE("get MCI_STATUS_START !\n");
448 if (dwFlags & MCI_TRACK) {
449 if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
450 return MCIERR_OUTOFRANGE;
451 lpParms->dwReturn = wmcda->wcda.lpdwTrackPos[lpParms->dwTrack - 1];
452 TRACE("get MCI_TRACK #%lu !\n", lpParms->dwTrack);
454 lpParms->dwReturn = CDAUDIO_CalcTime(wmcda, lpParms->dwReturn, &ret);
455 TRACE("MCI_STATUS_POSITION=%08lX !\n", lpParms->dwReturn);
456 break;
457 case MCI_STATUS_READY:
458 TRACE("MCI_STATUS_READY !\n");
459 lpParms->dwReturn = (wmcda->wcda.cdaMode == WINE_CDA_DONTKNOW ||
460 wmcda->wcda.cdaMode == WINE_CDA_NOTREADY) ?
461 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
462 TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
463 ret = MCI_RESOURCE_RETURNED;
464 break;
465 case MCI_STATUS_TIME_FORMAT:
466 lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, wmcda->dwTimeFormat);
467 TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
468 ret = MCI_RESOURCE_RETURNED;
469 break;
470 case MCI_CDA_STATUS_TYPE_TRACK:
471 if (!(dwFlags & MCI_TRACK))
472 ret = MCIERR_MISSING_PARAMETER;
473 else if (lpParms->dwTrack > wmcda->wcda.nTracks || lpParms->dwTrack == 0)
474 ret = MCIERR_OUTOFRANGE;
475 else
476 lpParms->dwReturn = (wmcda->wcda.lpbTrackFlags[lpParms->dwTrack - 1] &
477 CDROM_DATA_TRACK) ? MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
478 TRACE("MCI_CDA_STATUS_TYPE_TRACK[%ld]=%08lx\n", lpParms->dwTrack, lpParms->dwReturn);
479 break;
480 default:
481 FIXME("unknown command %08lX !\n", lpParms->dwItem);
482 return MCIERR_UNRECOGNIZED_COMMAND;
484 } else {
485 WARN("not MCI_STATUS_ITEM !\n");
487 return ret;
490 /**************************************************************************
491 * CDAUDIO_mciPlay [internal]
493 static DWORD CDAUDIO_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
495 int start, end;
496 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
497 DWORD ret = 0;
499 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
501 if (lpParms == NULL) {
502 ret = MCIERR_NULL_PARAMETER_BLOCK;
503 } else if (wmcda == NULL) {
504 ret = MCIERR_INVALID_DEVICE_ID;
505 } else {
506 if (wmcda->wcda.nTracks == 0) {
507 if (!CDAUDIO_GetTracksInfo(&wmcda->wcda)) {
508 WARN("error reading TracksInfo !\n");
509 return MCIERR_DRIVER_INTERNAL;
512 wmcda->wcda.nCurTrack = 1;
513 if (dwFlags & MCI_FROM) {
514 start = CDAUDIO_CalcFrame(wmcda, lpParms->dwFrom);
515 TRACE("MCI_FROM=%08lX -> %u \n", lpParms->dwFrom, start);
516 } else {
517 if (!CDAUDIO_GetCDStatus(&wmcda->wcda)) return MCIERR_DRIVER_INTERNAL;
518 start = wmcda->wcda.dwCurFrame;
520 if (dwFlags & MCI_TO) {
521 end = CDAUDIO_CalcFrame(wmcda, lpParms->dwTo);
522 TRACE("MCI_TO=%08lX -> %u \n", lpParms->dwTo, end);
523 } else {
524 end = wmcda->wcda.dwFirstOffset + wmcda->wcda.dwTotalLen;
527 if (CDAUDIO_Play(&wmcda->wcda, start, end) == -1)
528 return MCIERR_HARDWARE;
529 wmcda->mciMode = MCI_MODE_PLAY;
530 if (dwFlags & MCI_NOTIFY) {
531 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
533 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
534 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
538 return ret;
541 /**************************************************************************
542 * CDAUDIO_mciStop [internal]
544 static DWORD CDAUDIO_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
546 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
548 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
550 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
552 if (CDAUDIO_Stop(&wmcda->wcda) == -1)
553 return MCIERR_HARDWARE;
555 wmcda->mciMode = MCI_MODE_STOP;
556 if (lpParms && (dwFlags & MCI_NOTIFY)) {
557 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
558 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
559 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
561 return 0;
564 /**************************************************************************
565 * CDAUDIO_mciPause [internal]
567 static DWORD CDAUDIO_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
569 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
571 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
573 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
575 if (CDAUDIO_Pause(&wmcda->wcda, 1) == -1)
576 return MCIERR_HARDWARE;
577 wmcda->mciMode = MCI_MODE_PAUSE;
578 if (lpParms && (dwFlags & MCI_NOTIFY)) {
579 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
580 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
581 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
583 return 0;
586 /**************************************************************************
587 * CDAUDIO_mciResume [internal]
589 static DWORD CDAUDIO_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
591 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
593 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
595 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
597 if (CDAUDIO_Pause(&wmcda->wcda, 0) == -1)
598 return MCIERR_HARDWARE;
599 wmcda->mciMode = MCI_MODE_STOP;
600 if (lpParms && (dwFlags & MCI_NOTIFY)) {
601 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
602 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
603 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
605 return 0;
608 /**************************************************************************
609 * CDAUDIO_mciSeek [internal]
611 static DWORD CDAUDIO_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
613 DWORD at;
614 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
616 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
618 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
619 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
621 wmcda->mciMode = MCI_MODE_SEEK;
622 switch (dwFlags & ~(MCI_NOTIFY|MCI_WAIT)) {
623 case MCI_SEEK_TO_START:
624 TRACE("Seeking to start\n");
625 at = 0;
626 break;
627 case MCI_SEEK_TO_END:
628 TRACE("Seeking to end\n");
629 at = wmcda->wcda.dwTotalLen;
630 break;
631 case MCI_TO:
632 TRACE("Seeking to %lu\n", lpParms->dwTo);
633 at = lpParms->dwTo;
634 break;
635 default:
636 TRACE("Seeking to ??=%lu\n", dwFlags);
637 return MCIERR_UNSUPPORTED_FUNCTION;
639 if (CDAUDIO_Seek(&wmcda->wcda, at) == -1) {
640 return MCIERR_HARDWARE;
642 if (dwFlags & MCI_NOTIFY) {
643 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
644 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
645 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
647 return 0;
650 /**************************************************************************
651 * CDAUDIO_mciSetDoor [internal]
653 static DWORD CDAUDIO_mciSetDoor(UINT16 wDevID, int open)
655 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
657 TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
659 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
661 if (CDAUDIO_SetDoor(&wmcda->wcda, open) == -1)
662 return MCIERR_HARDWARE;
663 wmcda->mciMode = (open) ? MCI_MODE_OPEN : MCI_MODE_STOP;
664 return 0;
667 /**************************************************************************
668 * CDAUDIO_mciSet [internal]
670 static DWORD CDAUDIO_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
672 WINE_MCICDAUDIO* wmcda = CDAUDIO_mciGetOpenDrv(wDevID);
674 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
676 if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
677 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;;
679 TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
680 TRACE("dwAudio=%08lX\n", lpParms->dwAudio);
682 if (dwFlags & MCI_SET_TIME_FORMAT) {
683 switch (lpParms->dwTimeFormat) {
684 case MCI_FORMAT_MILLISECONDS:
685 TRACE("MCI_FORMAT_MILLISECONDS !\n");
686 break;
687 case MCI_FORMAT_MSF:
688 TRACE("MCI_FORMAT_MSF !\n");
689 break;
690 case MCI_FORMAT_TMSF:
691 TRACE("MCI_FORMAT_TMSF !\n");
692 break;
693 default:
694 WARN("bad time format !\n");
695 return MCIERR_BAD_TIME_FORMAT;
697 wmcda->dwTimeFormat = lpParms->dwTimeFormat;
699 if (dwFlags & MCI_SET_DOOR_OPEN) {
700 CDAUDIO_mciSetDoor(wDevID, TRUE);
702 if (dwFlags & MCI_SET_DOOR_CLOSED) {
703 CDAUDIO_mciSetDoor(wDevID, FALSE);
705 if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
706 if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
707 if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
708 if (dwFlags & MCI_NOTIFY) {
709 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n",
710 lpParms->dwCallback);
711 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
712 wmcda->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
714 return 0;
717 /**************************************************************************
718 * MCICDAUDIO_DriverProc [sample driver]
720 LONG CALLBACK MCICDAUDIO_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
721 DWORD dwParam1, DWORD dwParam2)
723 switch(wMsg) {
724 case DRV_LOAD: return 1;
725 case DRV_FREE: return 1;
726 case DRV_OPEN: return CDAUDIO_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
727 case DRV_CLOSE: return CDAUDIO_drvClose(dwDevID);
728 case DRV_ENABLE: return 1;
729 case DRV_DISABLE: return 1;
730 case DRV_QUERYCONFIGURE: return 1;
731 case DRV_CONFIGURE: MessageBoxA(0, "Sample Multimedia Driver !", "Wine Driver", MB_OK); return 1;
732 case DRV_INSTALL: return DRVCNF_RESTART;
733 case DRV_REMOVE: return DRVCNF_RESTART;
735 case MCI_OPEN_DRIVER: return CDAUDIO_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMSA)dwParam2);
736 case MCI_CLOSE_DRIVER: return CDAUDIO_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
737 case MCI_GETDEVCAPS: return CDAUDIO_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
738 case MCI_INFO: return CDAUDIO_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)dwParam2);
739 case MCI_STATUS: return CDAUDIO_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
740 case MCI_SET: return CDAUDIO_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
741 case MCI_PLAY: return CDAUDIO_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
742 case MCI_STOP: return CDAUDIO_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
743 case MCI_PAUSE: return CDAUDIO_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
744 case MCI_RESUME: return CDAUDIO_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
745 case MCI_SEEK: return CDAUDIO_mciSeek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
746 /* FIXME: I wonder if those two next items are really called ? */
747 case MCI_SET_DOOR_OPEN: return CDAUDIO_mciSetDoor(dwDevID, TRUE);
748 case MCI_SET_DOOR_CLOSED: return CDAUDIO_mciSetDoor(dwDevID, FALSE);
749 /* commands that should be supported */
750 case MCI_LOAD:
751 case MCI_SAVE:
752 case MCI_FREEZE:
753 case MCI_PUT:
754 case MCI_REALIZE:
755 case MCI_UNFREEZE:
756 case MCI_UPDATE:
757 case MCI_WHERE:
758 case MCI_STEP:
759 case MCI_SPIN:
760 case MCI_ESCAPE:
761 case MCI_COPY:
762 case MCI_CUT:
763 case MCI_DELETE:
764 case MCI_PASTE:
765 FIXME("Unsupported yet command=%s\n", MCI_MessageToString(wMsg));
766 break;
767 /* commands that should report an error */
768 case MCI_WINDOW:
769 FIXME("Unsupported command=%s\n", MCI_MessageToString(wMsg));
770 break;
771 case MCI_OPEN:
772 case MCI_CLOSE:
773 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
774 break;
775 default:
776 TRACE("Sending msg=%s to default driver proc\n", MCI_MessageToString(wMsg));
777 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
779 return MCIERR_UNRECOGNIZED_COMMAND;
782 /*-----------------------------------------------------------------------*/