bool CDROM_Interface_Ioctl::mci_CDPlay(int start, int length) { DWORD flags = MCI_FROM | MCI_TO | MCI_NOTIFY; MCI_PLAY_PARMS mci_play; mci_play.dwCallback = 0; int m, s, f; 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); return mci_CDioctl(MCI_PLAY, flags, &mci_play); }
/* Start play */ static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) { MCI_PLAY_PARMS mci_play; int m, s, f; DWORD flags; flags = MCI_FROM | MCI_TO | MCI_NOTIFY; mci_play.dwCallback = 0; 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); SDL_CD_end_position = mci_play.dwTo; return(SDL_SYS_CDioctl(cdrom->id, MCI_PLAY, flags, &mci_play)); }
/************************************************************************** * MCICDA_CalcTime [internal] */ static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame, LPDWORD lpRet) { DWORD dwTime = 0; UINT wTrack; UINT wMinutes; UINT wSeconds; UINT wFrames; CDROM_TOC toc; DWORD br; TRACE("(%p, %08X, %u);\n", wmcda, tf, dwFrame); switch (tf) { case MCI_FORMAT_MILLISECONDS: dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1; TRACE("MILLISECONDS %u\n", dwTime); *lpRet = 0; break; case MCI_FORMAT_MSF: wMinutes = dwFrame / CDFRAMES_PERMIN; wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC; wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds; dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames); TRACE("MSF %02u:%02u:%02u -> dwTime=%u\n", wMinutes, wSeconds, wFrames, dwTime); *lpRet = MCI_COLONIZED3_RETURN; break; case MCI_FORMAT_TMSF: default: /* unknown format ! force TMSF ! ... */ if (!DeviceIoControl(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, NULL)) return 0; if (dwFrame < FRAME_OF_TOC(toc, toc.FirstTrack) || dwFrame > FRAME_OF_TOC(toc, toc.LastTrack + 1)) { ERR("Out of range value %u [%u,%u]\n", dwFrame, FRAME_OF_TOC(toc, toc.FirstTrack), FRAME_OF_TOC(toc, toc.LastTrack + 1)); *lpRet = 0; return 0; } for (wTrack = toc.FirstTrack; wTrack <= toc.LastTrack; wTrack++) { if (FRAME_OF_TOC(toc, wTrack) > dwFrame) break; } wTrack--; dwFrame -= FRAME_OF_TOC(toc, wTrack); wMinutes = dwFrame / CDFRAMES_PERMIN; wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC; wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds; dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames); TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames); *lpRet = MCI_COLONIZED4_RETURN; break; } return dwTime; }
static DWORD MSF_Add(DWORD d1, DWORD d2) { WORD c, m, s, f; f = MCI_MSF_FRAME(d1) + MCI_MSF_FRAME(d2); c = f / CDFRAMES_PERSEC; f = f % CDFRAMES_PERSEC; s = MCI_MSF_SECOND(d1) + MCI_MSF_SECOND(d2) + c; c = s / 60; s = s % 60; m = MCI_MSF_MINUTE(d1) + MCI_MSF_MINUTE(d2) + c; /* may be > 60 */ return MCI_MAKE_MSF(m,s,f); }
static void test_play(HWND hwnd) { MCIDEVICEID wDeviceID; MCI_PARMS_UNION parm; MCIERROR err, ok_hw; DWORD numtracks, track, duration; DWORD factor = winetest_interactive ? 3 : 1; char buf[1024]; memset(buf, 0, sizeof(buf)); parm.gen.dwCallback = (DWORD_PTR)hwnd; /* once to rule them all */ err = mciSendString("open cdaudio alias c notify shareable", buf, sizeof(buf), hwnd); ok(!err || err == MCIERR_CANNOT_LOAD_DRIVER || err == MCIERR_MUST_USE_SHAREABLE, "mci open cdaudio notify returned %s\n", dbg_mcierr(err)); test_notification(hwnd, "open alias notify", err ? 0 : MCI_NOTIFY_SUCCESSFUL); /* Native returns MUST_USE_SHAREABLE when there's trouble with the hardware * (e.g. unreadable disk) or when Media Player already has the device open, * yet adding that flag does not help get past this error. */ if(err) { skip("Cannot open any cdaudio device, %s.\n", dbg_mcierr(err)); return; } wDeviceID = atoi(buf); ok(!strcmp(buf,"1"), "mci open deviceId: %s, expected 1\n", buf); err = mciSendString("capability c has video notify", buf, sizeof(buf), hwnd); ok(!err, "capability video: %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf, "false"), "capability video is %s\n", buf); test_notification(hwnd, "capability notify", MCI_NOTIFY_SUCCESSFUL); err = mciSendString("capability c can play", buf, sizeof(buf), hwnd); ok(!err, "capability video: %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf, "true"), "capability play is %s\n", buf); err = mciSendString("capability c", buf, sizeof(buf), NULL); ok(err == MCIERR_MISSING_PARAMETER, "capability nokeyword: %s\n", dbg_mcierr(err)); parm.caps.dwItem = 0x4001; parm.caps.dwReturn = 0xFEEDABAD; err = mciSendCommand(wDeviceID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&parm); ok(err == MCIERR_UNSUPPORTED_FUNCTION, "GETDEVCAPS %x: %s\n", parm.caps.dwItem, dbg_mcierr(err)); parm.caps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE; err = mciSendCommand(wDeviceID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&parm); ok(!err, "GETDEVCAPS device type: %s\n", dbg_mcierr(err)); if(!err) ok( parm.caps.dwReturn == MCI_DEVTYPE_CD_AUDIO, "getdevcaps device type: %u\n", parm.caps.dwReturn); err = mciSendCommand(wDeviceID, MCI_RECORD, 0, (DWORD_PTR)&parm); ok(err == MCIERR_UNSUPPORTED_FUNCTION, "MCI_RECORD: %s\n", dbg_mcierr(err)); /* Wine's MCI_MapMsgAtoW crashes on MCI_SAVE without parm->lpfilename */ parm.save.lpfilename = "foo"; err = mciSendCommand(wDeviceID, MCI_SAVE, 0, (DWORD_PTR)&parm); ok(err == MCIERR_UNSUPPORTED_FUNCTION, "MCI_SAVE: %s\n", dbg_mcierr(err)); /* commands from the core set are UNSUPPORTED, others UNRECOGNIZED */ err = mciSendCommand(wDeviceID, MCI_STEP, 0, (DWORD_PTR)&parm); ok(err == MCIERR_UNRECOGNIZED_COMMAND, "MCI_STEP: %s\n", dbg_mcierr(err)); parm.status.dwItem = MCI_STATUS_TIME_FORMAT; parm.status.dwReturn = 0xFEEDABAD; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); ok(!err, "STATUS time format: %s\n", dbg_mcierr(err)); if(!err) ok(parm.status.dwReturn == MCI_FORMAT_MSF, "status time default format: %ld\n", parm.status.dwReturn); /* "CD-Audio" */ err = mciSendString("info c product wait notify", buf, sizeof(buf), hwnd); ok(!err, "info product: %s\n", dbg_mcierr(err)); test_notification(hwnd, "info notify", err ? 0 : MCI_NOTIFY_SUCCESSFUL); parm.status.dwItem = MCI_STATUS_MEDIA_PRESENT; parm.status.dwReturn = 0xFEEDABAD; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); ok(err || parm.status.dwReturn == TRUE || parm.status.dwReturn == FALSE, "STATUS media present: %s\n", dbg_mcierr(err)); if (parm.status.dwReturn != TRUE) { skip("No CD-ROM in drive.\n"); return; } parm.status.dwItem = MCI_STATUS_MODE; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); ok(!err, "STATUS mode: %s\n", dbg_mcierr(err)); switch(parm.status.dwReturn) { case MCI_MODE_NOT_READY: skip("CD-ROM mode not ready (DVD in drive?)\n"); return; case MCI_MODE_OPEN: /* should not happen with MEDIA_PRESENT */ skip("CD-ROM drive is open\n"); /* set door closed may not work. */ return; default: /* play/record/seek/pause */ ok(parm.status.dwReturn==MCI_MODE_STOP, "STATUS mode is %lx\n", parm.status.dwReturn); /* fall through */ case MCI_MODE_STOP: /* normal */ break; } /* Initial mode is "stopped" with a CD in drive */ err = mciSendString("status c mode", buf, sizeof(buf), hwnd); ok(!err, "status mode: %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf, "stopped"), "status mode is initially %s\n", buf); err = mciSendString("status c ready", buf, sizeof(buf), hwnd); ok(!err, "status ready: %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf, "true"), "status ready with media is %s\n", buf); err = mciSendString("info c product identity", buf, sizeof(buf), hwnd); ok(!err, "info 2flags: %s\n", dbg_mcierr(err)); /* not MCIERR_FLAGS_NOT_COMPATIBLE */ /* Precedence rule p>u>i verified experimentally, not tested here. */ err = mciSendString("info c identity", buf, sizeof(buf), hwnd); ok(!err || err == MCIERR_HARDWARE, "info identity: %s\n", dbg_mcierr(err)); /* a blank disk causes MCIERR_HARDWARE and other commands to fail likewise. */ ok_hw = err; err = mciSendString("info c upc", buf, sizeof(buf), hwnd); ok(err == ok_hw || err == MCIERR_NO_IDENTITY, "info upc: %s\n", dbg_mcierr(err)); parm.status.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; parm.status.dwReturn = 0; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); ok(err == ok_hw, "STATUS number of tracks: %s\n", dbg_mcierr(err)); numtracks = parm.status.dwReturn; /* cf. MAXIMUM_NUMBER_TRACKS */ ok(0 < numtracks && numtracks <= 99, "number of tracks=%ld\n", parm.status.dwReturn); err = mciSendString("status c length", buf, sizeof(buf), hwnd); ok(err == ok_hw, "status length: %s\n", dbg_mcierr(err)); if(!err) trace("CD length %s\n", buf); if(err) { /* MCIERR_HARDWARE when given a blank disk */ skip("status length %s (blank disk?)\n", dbg_mcierr(ok_hw)); return; } /* Linux leaves the drive at some random position, * native initialises to the start position below. */ err = mciSendString("status c position", buf, sizeof(buf), hwnd); ok(!err, "status position: %s\n", dbg_mcierr(err)); if(!err) todo_wine ok(!strcmp(buf, "00:02:00") || !strcmp(buf, "00:02:33") || !strcmp(buf, "00:03:00"), "status position initially %s\n", buf); /* 2 seconds is the initial position even with data tracks. */ err = mciSendString("status c position start notify", buf, sizeof(buf), hwnd); ok(err == ok_hw, "status position start: %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf, "00:02:00") || !strcmp(buf, "00:02:33") || !strcmp(buf, "00:03:00"), "status position start %s\n", buf); test_notification(hwnd, "status notify", err ? 0 : MCI_NOTIFY_SUCCESSFUL); err = mciSendString("status c position start track 1 notify", buf, sizeof(buf), hwnd); ok(err == MCIERR_FLAGS_NOT_COMPATIBLE, "status position start: %s\n", dbg_mcierr(err)); test_notification(hwnd, "status 2flags", err ? 0 : MCI_NOTIFY_SUCCESSFUL); err = mciSendString("play c from 00:02:00 to 00:01:00 notify", buf, sizeof(buf), hwnd); todo_wine ok(err == MCIERR_OUTOFRANGE, "play 2s to 1s: %s\n", dbg_mcierr(err)); test_notification(hwnd, "play 2s to 1s", err ? 0 : MCI_NOTIFY_SUCCESSFUL); err = mciSendString("resume c", buf, sizeof(buf), hwnd); ok(err == MCIERR_HARDWARE || /* Win9x */ err == MCIERR_UNSUPPORTED_FUNCTION, "resume without play: %s\n", dbg_mcierr(err)); /* not NONAPPLICABLE_FUNCTION */ /* vmware with a .iso (data-only) yields no error on NT/w2k */ err = mciSendString("seek c wait", buf, sizeof(buf), hwnd); ok(err == MCIERR_MISSING_PARAMETER, "seek noflag: %s\n", dbg_mcierr(err)); err = mciSendString("seek c to start to end", buf, sizeof(buf), hwnd); ok(err == MCIERR_FLAGS_NOT_COMPATIBLE || broken(!err), "seek to start+end: %s\n", dbg_mcierr(err)); /* Win9x only errors out with Seek to start to <position> */ /* set Wine to a defined position before play */ err = mciSendString("seek c to start notify", buf, sizeof(buf), hwnd); ok(!err, "seek to start: %s\n", dbg_mcierr(err)); test_notification(hwnd, "seek to start", err ? 0 : MCI_NOTIFY_SUCCESSFUL); /* Win9X Status position / current track then sometimes report the end position / track! */ err = mciSendString("status c mode", buf, sizeof(buf), hwnd); ok(!err, "status mode: %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf, "stopped"), "status mode after seek is %s\n", buf); /* MCICDA ignores MCI_SET_VIDEO * One xp machine ignored SET_AUDIO, one w2k and one w7 machine honoured it * and simultaneously toggled the mute button in the mixer control panel. * Or does it only depend on the HW, not the OS? */ err = mciSendString("set c video audio all on", buf, sizeof(buf), hwnd); ok(!err, "set video/audio: %s\n", dbg_mcierr(err)); err = mciSendString("set c time format ms", buf, sizeof(buf), hwnd); ok(!err, "set time format ms: %s\n", dbg_mcierr(err)); memset(buf, 0, sizeof(buf)); err = mciSendString("status c position start", buf, sizeof(buf), hwnd); ok(!err, "status position start (ms): %s\n", dbg_mcierr(err)); duration = atoi(buf); if(!err) ok(duration > 2000, "status position initially %sms\n", buf); /* 00:02:00 corresponds to 2001 ms, 02:33 -> 2441 etc. */ err = mciSendString("status c position start track 1", buf, sizeof(buf), hwnd); ok(err == MCIERR_FLAGS_NOT_COMPATIBLE, "status position start+track: %s\n", dbg_mcierr(err)); err = mciSendString("status c notify wait", buf, sizeof(buf), hwnd); ok(err == MCIERR_MISSING_PARAMETER, "status noflag: %s\n", dbg_mcierr(err)); err = mciSendString("status c length track 1", buf, sizeof(buf), hwnd); ok(!err, "status length (ms): %s\n", dbg_mcierr(err)); if(!err) { trace("track #1 length %sms\n", buf); duration = atoi(buf); } else duration = 2001; /* for the position test below */ if (0) { /* causes some native systems to return Seek and Play with MCIERR_HARDWARE */ /* depending on capability can eject only? */ err = mciSendString("set c door closed notify", buf, sizeof(buf), hwnd); ok(!err, "set door closed: %s\n", dbg_mcierr(err)); test_notification(hwnd, "door closed", err ? 0 : MCI_NOTIFY_SUCCESSFUL); } /* Changing the disk while the MCI device is open causes the Status * command to report stale data. Native obviously caches the TOC. */ /* status type track is localised, strcmp("audio|other") may fail. */ parm.status.dwItem = MCI_CDA_STATUS_TYPE_TRACK; parm.status.dwTrack = 1; parm.status.dwReturn = 0xFEEDABAD; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM|MCI_TRACK, (DWORD_PTR)&parm); ok(!err, "STATUS type track 1: %s\n", dbg_mcierr(err)); ok(parm.status.dwReturn==MCI_CDA_TRACK_OTHER || parm.status.dwReturn==MCI_CDA_TRACK_AUDIO, "unknown track type %lx\n", parm.status.dwReturn); if (parm.status.dwReturn == MCI_CDA_TRACK_OTHER) { /* Find an audio track */ parm.status.dwItem = MCI_CDA_STATUS_TYPE_TRACK; parm.status.dwTrack = numtracks; parm.status.dwReturn = 0xFEEDABAD; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM|MCI_TRACK, (DWORD_PTR)&parm); ok(!err, "STATUS type track %u: %s\n", numtracks, dbg_mcierr(err)); ok(parm.status.dwReturn == MCI_CDA_TRACK_OTHER || parm.status.dwReturn == MCI_CDA_TRACK_AUDIO, "unknown track type %lx\n", parm.status.dwReturn); track = (!err && parm.status.dwReturn == MCI_CDA_TRACK_AUDIO) ? numtracks : 0; /* Seek to start (above) skips over data tracks * In case of a data only CD, it seeks to the end of disk, however * another Status position a few seconds later yields MCIERR_HARDWARE. */ parm.status.dwItem = MCI_STATUS_POSITION; parm.status.dwReturn = 2000; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&parm); ok(!err || broken(err == MCIERR_HARDWARE), "STATUS position: %s\n", dbg_mcierr(err)); if(!err && track) ok(parm.status.dwReturn > duration, "Seek did not skip data tracks, position %lums\n", parm.status.dwReturn); /* dwReturn > start + length(#1) may fail because of small position report fluctuation. * On some native systems, status position fluctuates around the target position; * Successive calls return varying positions! */ err = mciSendString("set c time format msf", buf, sizeof(buf), hwnd); ok(!err, "set time format msf: %s\n", dbg_mcierr(err)); parm.status.dwItem = MCI_STATUS_LENGTH; parm.status.dwTrack = 1; parm.status.dwReturn = 0xFEEDABAD; err = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM|MCI_TRACK, (DWORD_PTR)&parm); ok(!err, "STATUS length track %u: %s\n", parm.status.dwTrack, dbg_mcierr(err)); duration = parm.status.dwReturn; trace("track #1 length: %02um:%02us:%02uframes\n", MCI_MSF_MINUTE(duration), MCI_MSF_SECOND(duration), MCI_MSF_FRAME(duration)); ok(duration>>24==0, "CD length high bits %08X\n", duration); /* TODO only with mixed CDs? */ /* play track 1 to length silently works with data tracks */ parm.play.dwFrom = MCI_MAKE_MSF(0,2,0); parm.play.dwTo = duration; /* omitting 2 seconds from end */ err = mciSendCommand(wDeviceID, MCI_PLAY, MCI_FROM|MCI_TO, (DWORD_PTR)&parm); ok(!err, "PLAY data to %08X: %s\n", duration, dbg_mcierr(err)); Sleep(1500*factor); /* Time to spin up, hopefully less than track length */ err = mciSendString("status c mode", buf, sizeof(buf), hwnd); ok(!err, "status mode: %s\n", dbg_mcierr(err)); if(!err) ok(!strcmp(buf, "stopped"), "status mode on data is %s\n", buf); } else if (parm.status.dwReturn == MCI_CDA_TRACK_AUDIO) {
MCIERROR WINAPI fake_mciSendCommandA(MCIDEVICEID IDDevice, UINT uMsg, DWORD_PTR fdwCommand, DWORD_PTR dwParam) { char cmdbuf[1024]; dprintf("mciSendCommandA(IDDevice=%p, uMsg=%p, fdwCommand=%p, dwParam=%p)\r\n", IDDevice, uMsg, fdwCommand, dwParam); if (fdwCommand & MCI_NOTIFY) { dprintf(" MCI_NOTIFY\r\n"); } if (fdwCommand & MCI_WAIT) { dprintf(" MCI_WAIT\r\n"); } if (uMsg == MCI_OPEN) { LPMCI_OPEN_PARMS parms = (LPVOID)dwParam; dprintf(" MCI_OPEN\r\n"); if (fdwCommand & MCI_OPEN_ALIAS) { dprintf(" MCI_OPEN_ALIAS\r\n"); } if (fdwCommand & MCI_OPEN_SHAREABLE) { dprintf(" MCI_OPEN_SHAREABLE\r\n"); } if (fdwCommand & MCI_OPEN_TYPE_ID) { dprintf(" MCI_OPEN_TYPE_ID\r\n"); if (LOWORD(parms->lpstrDeviceType) == MCI_DEVTYPE_CD_AUDIO) { dprintf(" Returning magic device id for MCI_DEVTYPE_CD_AUDIO\r\n"); parms->wDeviceID = MAGIC_DEVICEID; return 0; } } if (fdwCommand & MCI_OPEN_TYPE && !(fdwCommand & MCI_OPEN_TYPE_ID)) { dprintf(" MCI_OPEN_TYPE\r\n"); dprintf(" -> %s\r\n", parms->lpstrDeviceType); if (strcmp(parms->lpstrDeviceType, "cdaudio") == 0) { dprintf(" Returning magic device id for MCI_DEVTYPE_CD_AUDIO\r\n"); parms->wDeviceID = MAGIC_DEVICEID; return 0; } } } if (IDDevice == MAGIC_DEVICEID || IDDevice == 0 || IDDevice == 0xFFFFFFFF) { if (uMsg == MCI_SET) { LPMCI_SET_PARMS parms = (LPVOID)dwParam; dprintf(" MCI_SET\r\n"); if (fdwCommand & MCI_SET_TIME_FORMAT) { dprintf(" MCI_SET_TIME_FORMAT\r\n"); time_format = parms->dwTimeFormat; if (parms->dwTimeFormat == MCI_FORMAT_BYTES) { dprintf(" MCI_FORMAT_BYTES\r\n"); } if (parms->dwTimeFormat == MCI_FORMAT_FRAMES) { dprintf(" MCI_FORMAT_FRAMES\r\n"); } if (parms->dwTimeFormat == MCI_FORMAT_HMS) { dprintf(" MCI_FORMAT_HMS\r\n"); } if (parms->dwTimeFormat == MCI_FORMAT_MILLISECONDS) { dprintf(" MCI_FORMAT_MILLISECONDS\r\n"); } if (parms->dwTimeFormat == MCI_FORMAT_MSF) { dprintf(" MCI_FORMAT_MSF\r\n"); } if (parms->dwTimeFormat == MCI_FORMAT_SAMPLES) { dprintf(" MCI_FORMAT_SAMPLES\r\n"); } if (parms->dwTimeFormat == MCI_FORMAT_TMSF) { dprintf(" MCI_FORMAT_TMSF\r\n"); } } } if (uMsg == MCI_CLOSE) { dprintf(" MCI_CLOSE\r\n"); if (player) { TerminateThread(player, 0); } playing = 0; player = NULL; } if (uMsg == MCI_PLAY) { LPMCI_PLAY_PARMS parms = (LPVOID)dwParam; static struct play_info info = { -1, -1 }; dprintf(" MCI_PLAY\r\n"); if (fdwCommand & MCI_FROM) { dprintf(" dwFrom: %d\r\n", parms->dwFrom); // FIXME: rounding to nearest track if (time_format == MCI_FORMAT_TMSF) { info.first = MCI_TMSF_TRACK(parms->dwFrom); dprintf(" TRACK %d\n", MCI_TMSF_TRACK(parms->dwFrom)); dprintf(" MINUTE %d\n", MCI_TMSF_MINUTE(parms->dwFrom)); dprintf(" SECOND %d\n", MCI_TMSF_SECOND(parms->dwFrom)); dprintf(" FRAME %d\n", MCI_TMSF_FRAME(parms->dwFrom)); } else if (time_format == MCI_FORMAT_MILLISECONDS) { info.first = 0; for (int i = 0; i < MAX_TRACKS; i++) { // FIXME: take closest instead of absolute if (tracks[i].position == parms->dwFrom / 1000) { info.first = i; } } dprintf(" mapped milliseconds to %d\n", info.first); } else { // FIXME: not really info.first = parms->dwFrom; } if (info.first < firstTrack) info.first = firstTrack; if (info.first > lastTrack) info.first = lastTrack; info.last = info.first; } if (fdwCommand & MCI_TO) { dprintf(" dwTo: %d\r\n", parms->dwTo); if (time_format == MCI_FORMAT_TMSF) { info.last = MCI_TMSF_TRACK(parms->dwTo); dprintf(" TRACK %d\n", MCI_TMSF_TRACK(parms->dwTo)); dprintf(" MINUTE %d\n", MCI_TMSF_MINUTE(parms->dwTo)); dprintf(" SECOND %d\n", MCI_TMSF_SECOND(parms->dwTo)); dprintf(" FRAME %d\n", MCI_TMSF_FRAME(parms->dwTo)); } else if (time_format == MCI_FORMAT_MILLISECONDS) { info.last = info.first; for (int i = info.first; i < MAX_TRACKS; i ++) { // FIXME: use better matching if (tracks[i].position + tracks[i].length > parms->dwFrom / 1000) { info.last = i; break; } } dprintf(" mapped milliseconds to %d\n", info.last); } else info.last = parms->dwTo; if (info.last < info.first) info.last = info.first; if (info.last > lastTrack) info.last = lastTrack; } if (info.first && (fdwCommand & MCI_FROM)) { if (player) { TerminateThread(player, 0); } playing = 0; player = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)player_main, (void *)&info, 0, NULL); } } if (uMsg == MCI_STOP) { dprintf(" MCI_STOP\r\n"); playing = 0; } if (uMsg == MCI_STATUS) { LPMCI_STATUS_PARMS parms = (LPVOID)dwParam; dprintf(" MCI_STATUS\r\n"); parms->dwReturn = 0; if (fdwCommand & MCI_TRACK) { dprintf(" MCI_TRACK\r\n"); dprintf(" dwTrack = %d\r\n", parms->dwTrack); } if (fdwCommand & MCI_STATUS_ITEM) { dprintf(" MCI_STATUS_ITEM\r\n"); if (parms->dwItem == MCI_STATUS_CURRENT_TRACK) { dprintf(" MCI_STATUS_CURRENT_TRACK\r\n"); } if (parms->dwItem == MCI_STATUS_LENGTH) { dprintf(" MCI_STATUS_LENGTH\r\n"); int seconds = tracks[parms->dwTrack].length; if (seconds) { if (time_format == MCI_FORMAT_MILLISECONDS) { parms->dwReturn = seconds * 1000; } else { parms->dwReturn = MCI_MAKE_MSF(seconds / 60, seconds % 60, 0); } } } if (parms->dwItem == MCI_CDA_STATUS_TYPE_TRACK) { dprintf(" MCI_CDA_STATUS_TYPE_TRACK\r\n"); } if (parms->dwItem == MCI_STATUS_MEDIA_PRESENT) { dprintf(" MCI_STATUS_MEDIA_PRESENT\r\n"); parms->dwReturn = lastTrack > 0; } if (parms->dwItem == MCI_STATUS_NUMBER_OF_TRACKS) { dprintf(" MCI_STATUS_NUMBER_OF_TRACKS\r\n"); parms->dwReturn = numTracks; } if (parms->dwItem == MCI_STATUS_POSITION) { dprintf(" MCI_STATUS_POSITION\r\n"); if (fdwCommand & MCI_TRACK) { // FIXME: implying milliseconds parms->dwReturn = tracks[parms->dwTrack].position * 1000; } } if (parms->dwItem == MCI_STATUS_MODE) { dprintf(" MCI_STATUS_MODE\r\n"); dprintf(" we are %s\r\n", playing ? "playing" : "NOT playing"); parms->dwReturn = playing ? MCI_MODE_PLAY : MCI_MODE_STOP; } if (parms->dwItem == MCI_STATUS_READY) { dprintf(" MCI_STATUS_READY\r\n"); } if (parms->dwItem == MCI_STATUS_TIME_FORMAT) { dprintf(" MCI_STATUS_TIME_FORMAT\r\n"); } if (parms->dwItem == MCI_STATUS_START) { dprintf(" MCI_STATUS_START\r\n"); } } dprintf(" dwReturn %d\n", parms->dwReturn); } return 0; } /* fallback */ return MCIERR_UNRECOGNIZED_COMMAND; }