From 483269918b610431a01539b87658381cdc123486 Mon Sep 17 00:00:00 2001 From: =?utf-8?q?J=C3=B6rg=20H=C3=B6hle?= Date: Wed, 21 Oct 2009 17:44:58 +0200 Subject: [PATCH] mciwave: Play/Record return MCIERR_OUTOFRANGE as required. --- dlls/mciwave/mciwave.c | 75 +++++++++++++++++++++--------------------------- dlls/winmm/tests/mci.c | 44 +++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 43 deletions(-) diff --git a/dlls/mciwave/mciwave.c b/dlls/mciwave/mciwave.c index 0157436..220bb8d 100644 --- a/dlls/mciwave/mciwave.c +++ b/dlls/mciwave/mciwave.c @@ -751,8 +751,6 @@ static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms); } - wmw->fInput = FALSE; - /** This function will be called again by a thread when async is used. * We have to set MCI_MODE_PLAY before we do this so that the app can spin * on MCI_STATUS, so we have to allow it here if we're not going to start this thread. @@ -761,13 +759,6 @@ static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, return MCIERR_INTERNAL; } - wmw->dwStatus = MCI_MODE_PLAY; - - if (!(dwFlags & MCI_WAIT)) { - return MCI_SendCommandAsync(wmw->openParms.wDeviceID, WAVE_mciPlay, dwFlags, - (DWORD_PTR)lpParms, sizeof(MCI_PLAY_PARMS)); - } - if (wmw->lpWaveFormat->wFormatTag == WAVE_FORMAT_PCM) { if (wmw->lpWaveFormat->nBlockAlign != wmw->lpWaveFormat->nChannels * wmw->lpWaveFormat->wBitsPerSample/8) { @@ -791,12 +782,30 @@ static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, } } - end = 0xFFFFFFFF; + end = wmw->ckWaveData.cksize; + if (lpParms && (dwFlags & MCI_TO)) { + DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo); + if (position > end) return MCIERR_OUTOFRANGE; + end = position; + } if (lpParms && (dwFlags & MCI_FROM)) { - wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom); + DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom); + if (position > end) return MCIERR_OUTOFRANGE; + /* Seek rounds down, so do we. */ + position /= wmw->lpWaveFormat->nBlockAlign; + position *= wmw->lpWaveFormat->nBlockAlign; + wmw->dwPosition = position; } - if (lpParms && (dwFlags & MCI_TO)) { - end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo); + if (end < wmw->dwPosition) return MCIERR_OUTOFRANGE; + left = end - wmw->dwPosition; + if (0==left) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */ + + wmw->fInput = FALSE; /* FIXME: waveInOpen may have been called. */ + wmw->dwStatus = MCI_MODE_PLAY; + + if (!(dwFlags & MCI_WAIT)) { + return MCI_SendCommandAsync(wmw->openParms.wDeviceID, WAVE_mciPlay, dwFlags, + (DWORD_PTR)lpParms, sizeof(MCI_PLAY_PARMS)); } TRACE("Playing from byte=%u to byte=%u\n", wmw->dwPosition, end); @@ -806,17 +815,9 @@ static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED); oldcb = NULL; - if (end <= wmw->dwPosition) - return MMSYSERR_NOERROR; - - #define WAVE_ALIGN_ON_BLOCK(wmw,v) \ ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign) - wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition); - wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize); - - /* go back to beginning of chunk plus the requested position */ /* FIXME: I'm not sure this is correct, notably because some data linked to * the decompression state machine will not be correctly initialized. @@ -825,9 +826,6 @@ static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, */ mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */ - /* By default the device will be opened for output, the MCI_CUE function is there to - * change from output to input and back - */ /* FIXME: how to choose between several output channels ? here mapper is forced */ dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat, (DWORD_PTR)WAVE_mciPlayCallback, (DWORD_PTR)wmw, CALLBACK_FUNCTION); @@ -856,7 +854,6 @@ static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, } whidx = 0; - left = min(wmw->ckWaveData.cksize, end - wmw->dwPosition); wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); wmw->dwEventCount = 1L; /* for first buffer */ @@ -999,11 +996,6 @@ static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms); } - /* FIXME : since there is no way to determine in which mode the device is - * open (recording/playback) automatically switch from a mode to another - */ - wmw->fInput = TRUE; - /** This function will be called again by a thread when async is used. * We have to set MCI_MODE_RECORD before we do this so that the app can spin * on MCI_STATUS, so we have to allow it here if we're not going to start this thread. @@ -1012,6 +1004,7 @@ static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt return MCIERR_INTERNAL; } + wmw->fInput = TRUE; /* FIXME: waveOutOpen may have been called. */ wmw->dwStatus = MCI_MODE_RECORD; if (!(dwFlags & MCI_WAIT)) { @@ -1027,18 +1020,22 @@ static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt dwRet = create_tmp_file(&wmw->hFile, (WCHAR**)&wmw->openParms.lpstrElementName); if (dwRet != 0) return dwRet; - /* new RIFF file */ + /* new RIFF file, lpWaveFormat now valid */ dwRet = WAVE_mciCreateRIFFSkeleton(wmw); if (dwRet != 0) return dwRet; - end = 0xFFFFFFFF; - if (lpParms && (dwFlags & MCI_FROM)) { - wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom); - } - if (lpParms && (dwFlags & MCI_TO)) { end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo); + } else end = 0xFFFFFFFF; + if (lpParms && (dwFlags & MCI_FROM)) { + DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom); + if (wmw->ckWaveData.cksize < position) return MCIERR_OUTOFRANGE; + /* Seek rounds down, so do we. */ + position /= wmw->lpWaveFormat->nBlockAlign; + position *= wmw->lpWaveFormat->nBlockAlign; + wmw->dwPosition = position; } + if (end==wmw->dwPosition) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */ TRACE("Recording from byte=%u to byte=%u\n", wmw->dwPosition, end); @@ -1047,15 +1044,9 @@ static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED); oldcb = NULL; - if (end <= wmw->dwPosition) - { - return MMSYSERR_NOERROR; - } - #define WAVE_ALIGN_ON_BLOCK(wmw,v) \ ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign) - wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition); wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize); /* Go back to the beginning of the chunk plus the requested position */ diff --git a/dlls/winmm/tests/mci.c b/dlls/winmm/tests/mci.c index e450a22..90f6e3a 100644 --- a/dlls/winmm/tests/mci.c +++ b/dlls/winmm/tests/mci.c @@ -332,7 +332,22 @@ static void test_playWAVE(HWND hwnd) err = mciSendString("cue output", NULL, 0, NULL); todo_wine ok(err==MCIERR_UNRECOGNIZED_COMMAND,"mci incorrect cue output returned: %s\n", dbg_mcierr(err)); - /* A second play would cause Wine to hang */ + err = mciSendString("play mysound from 0 to 0 notify", NULL, 0, hwnd); + ok(!err,"mci play from 0 to 0 returned error: %d\n", err); + todo_wine test_notification1(hwnd,"play from 0 to 0",MCI_NOTIFY_SUCCESSFUL); + + err = mciSendString("status mysound mode", buf, sizeof(buf), hwnd); + ok(!err,"mci status mode returned error: %d\n", err); + ok(!strcmp(buf,"stopped"), "mci status mode: %s\n", buf); + + err = mciSendString("play mysound from 250 to 0", NULL, 0, NULL); + ok(err==MCIERR_OUTOFRANGE,"mci play from 250 to 0 returned error: %d\n", err); + + err = mciSendString("play mysound from 250 to 0 notify", NULL, 0, hwnd); + ok(err==MCIERR_OUTOFRANGE,"mci play from 250 to 0 notify returned error: %d\n", err); + /* No notification (checked below) sent if error */ + + /* A second play caused Wine to hang */ err = mciSendString("play mysound from 500 to 1500 wait", NULL, 0, NULL); ok(!err,"mci play from 500 to 1500 returned error: %d\n", err); @@ -341,6 +356,29 @@ static void test_playWAVE(HWND hwnd) ok(!err,"mci status position returned error: %d\n", err); if(!err) ok(!strcmp(buf,"1500"), "mci status position: %s\n", buf); + /* mci will not play position < current */ + err = mciSendString("play mysound to 1000", NULL, 0, NULL); + ok(err==MCIERR_OUTOFRANGE,"mci play to 1000 returned error: %d\n", err); + + /* mci will not play to > end */ + err = mciSendString("play mysound to 3000 notify", NULL, 0, hwnd); + ok(err==MCIERR_OUTOFRANGE,"mci play to 3000 notify returned error: %d\n", err); + /* Again, no notification upon error */ + + err = mciSendString("play mysound to 2000", NULL, 0, NULL); + ok(!err,"mci play to 2000 returned error: %d\n", err); + + /* Rejected while playing */ + err = mciSendString("cue mysound output", NULL, 0, NULL); + ok(err==MCIERR_NONAPPLICABLE_FUNCTION,"mci cue output while playing returned error: %d\n", err); + + err = mciSendString("play mysound to 3000", NULL, 0, NULL); + ok(err==MCIERR_OUTOFRANGE,"mci play to 3000 returned error: %d\n", err); + + err = mciSendString("stop mysound wait", NULL, 0, NULL); + ok(!err,"mci stop wait returned error: %d\n", err); + test_notification(hwnd,"play outofrange notify #2",0); + err = mciSendString("seek mysound to 250 wait notify", NULL, 0, hwnd); ok(!err,"mci seek to 250 wait notify returned error: %d\n", err); test_notification(hwnd,"seek wait notify",MCI_NOTIFY_SUCCESSFUL); @@ -357,6 +395,10 @@ static void test_playWAVE(HWND hwnd) ok(!err,"mci status mode returned error: %d\n", err); ok(!strcmp(buf,"stopped"), "mci status mode: %s\n", buf); + err = mciSendString("play mysound to 250 wait notify", NULL, 0, hwnd); + ok(!err,"mci play to 250 returned error: %d\n", err); + todo_wine test_notification1(hwnd,"play to 250 wait notify",MCI_NOTIFY_SUCCESSFUL); + err = mciSendString("close mysound", NULL, 0, NULL); ok(!err,"mci close returned error: %d\n", err); test_notification(hwnd,"after close",0); -- 1.5.6.3