From: Andrew Eikum Subject: [PATCH 1/2] winmm/tests: Demonstrate that WOM_DONE is not invoked reentrantly Message-Id: <20220127162259.GC5773@foghorn.codeweavers.com> Date: Thu, 27 Jan 2022 10:22:59 -0600 From: Liam Murphy Signed-off-by: Andrew Eikum --- dlls/winmm/tests/wave.c | 103 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/dlls/winmm/tests/wave.c b/dlls/winmm/tests/wave.c index 2f0c8443363..56501367190 100644 --- a/dlls/winmm/tests/wave.c +++ b/dlls/winmm/tests/wave.c @@ -1626,6 +1626,108 @@ static void test_fragmentsize(void) CloseHandle(hevent); } +static void CALLBACK test_reentrant_callback_func(HWAVEOUT hwo, UINT uMsg, + DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + static int wom_done_count = 0; + + switch(uMsg){ + case WOM_OPEN: + case WOM_CLOSE: + ok(GetCurrentThreadId() == g_tid, "Got different thread ID\n"); + break; + + case WOM_DONE: + /* verify that WOM_DONE is not sent during the following waveOutWrite */ + todo_wine_if(wom_done_count == 1) + ok(g_tid == 0, "callback called reentrantly\n"); + + g_tid = GetCurrentThreadId(); + + if(wom_done_count++ == 0){ + Sleep(125); /* ensure 2nd header is done playing before waveOutWrite */ + waveOutWrite(hwo, (WAVEHDR *)dwParam1, sizeof(WAVEHDR)); + } + + break; + } + + g_tid = 0; + SetEvent((HANDLE)dwInstance); +} + +static void test_reentrant_callback(void) +{ + MMRESULT rc; + WAVEHDR hdr[2]; + HWAVEOUT wout; + WAVEFORMATEX fmt; + DWORD wait; + HANDLE hevent; + + if(waveOutGetNumDevs() == 0) + return; + + fmt.wFormatTag = WAVE_FORMAT_PCM; + fmt.nChannels = 2; + fmt.nSamplesPerSec = 44100; + fmt.wBitsPerSample = 16; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nBlockAlign * fmt.nSamplesPerSec; + fmt.cbSize = sizeof(WAVEFORMATEX); + + hevent = CreateEventW(NULL, FALSE, FALSE, NULL); + g_tid = GetCurrentThreadId(); + + rc = waveOutOpen(&wout, WAVE_MAPPER, &fmt, (DWORD_PTR)test_reentrant_callback_func, + (DWORD_PTR)hevent, CALLBACK_FUNCTION); + ok(rc == MMSYSERR_NOERROR || rc == WAVERR_BADFORMAT || + rc == MMSYSERR_INVALFLAG || rc == MMSYSERR_INVALPARAM, + "waveOutOpen(%s) failed: %s\n", dev_name(WAVE_MAPPER), wave_out_error(rc)); + if(rc != MMSYSERR_NOERROR){ + CloseHandle(hevent); + return; + } + + wait = WaitForSingleObject(hevent, 1000); + ok(wait == WAIT_OBJECT_0, "wave open callback missed\n"); + + memset(hdr, 0, sizeof(hdr)); + hdr[0].dwBufferLength = (fmt.nSamplesPerSec * fmt.nBlockAlign / 10); + hdr[1].dwBufferLength = hdr[0].dwBufferLength; + hdr[1].lpData = hdr[0].lpData = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, hdr[0].dwBufferLength); + + rc = waveOutPrepareHeader(wout, &hdr[0], sizeof(hdr[0])); + ok(rc == MMSYSERR_NOERROR, "waveOutPrepareHeader failed: %s\n", wave_out_error(rc)); + + rc = waveOutPrepareHeader(wout, &hdr[1], sizeof(hdr[1])); + ok(rc == MMSYSERR_NOERROR, "waveOutPrepareHeader failed: %s\n", wave_out_error(rc)); + + rc = waveOutWrite(wout, &hdr[0], sizeof(hdr[0])); + ok(rc == MMSYSERR_NOERROR, "waveOutWrite failed: %s\n", wave_out_error(rc)); + + rc = waveOutWrite(wout, &hdr[1], sizeof(hdr[1])); + ok(rc == MMSYSERR_NOERROR, "waveOutWrite failed: %s\n", wave_out_error(rc)); + + wait = WaitForSingleObject(hevent, 1000); + ok(wait == WAIT_OBJECT_0, "header 1 callback missed\n"); + + wait = WaitForSingleObject(hevent, 1000); + ok(wait == WAIT_OBJECT_0, "header 2 callback missed\n"); + + wait = WaitForSingleObject(hevent, 1000); + ok(wait == WAIT_OBJECT_0, "header 3 callback missed\n"); + + g_tid = GetCurrentThreadId(); + rc = waveOutClose(wout); + ok(rc == MMSYSERR_NOERROR, "waveOutClose failed: %s\n", wave_out_error(rc)); + + HeapFree(GetProcessHeap(), 0, hdr[0].lpData); + CloseHandle(hevent); +} + static void create_wav_file(char *temp_file) { WAVEFORMATEX format; @@ -1727,5 +1829,6 @@ START_TEST(wave) wave_out_tests(); test_sndPlaySound(); test_fragmentsize(); + test_reentrant_callback(); test_PlaySound(); } -- 2.35.0