winmm/tests: Demonstrate that WOM_DONE is not invoked reentrantly.
[wine.git] / dlls / winmm / tests / wave.c
blob56501367190b2906e64398dfcf10c0247dea650f
1 /*
2 * Test winmm sound playback in each sound format
4 * Copyright (c) 2002 Francois Gouget
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <math.h>
26 #include "wine/test.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "mmsystem.h"
32 #define NOBITMAP
33 #include "mmddk.h"
34 #include "mmreg.h"
35 #include "ks.h"
36 #include "ksguid.h"
37 #include "ksmedia.h"
39 #include "winmm_test.h"
41 static DWORD g_tid;
43 static void test_multiple_waveopens(void)
45 HWAVEOUT handle1, handle2;
46 MMRESULT ret;
47 WAVEFORMATEX wfx;
49 wfx.wFormatTag = WAVE_FORMAT_PCM;
50 wfx.nChannels = 1;
51 wfx.nSamplesPerSec = 11025;
52 wfx.nBlockAlign = 1;
53 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
54 wfx.wBitsPerSample = 8;
55 wfx.cbSize = 0;
57 ret = waveOutOpen(&handle1, 0, &wfx, 0, 0, 0);
58 if (ret != MMSYSERR_NOERROR)
60 skip("Could not do the duplicate waveopen test\n");
61 return;
64 ret = waveOutOpen(&handle2, 0, &wfx, 0, 0, 0);
65 /* Modern Windows allows for wave-out devices to be opened multiple times.
66 * Some Wine audio drivers allow that and some don't. To avoid false alarms
67 * for those that do, don't "todo_wine ok(...)" on success.
69 if (ret != MMSYSERR_NOERROR)
71 todo_wine ok(ret == MMSYSERR_NOERROR || broken(ret == MMSYSERR_ALLOCATED), /* winME */
72 "second waveOutOpen returns: %x\n", ret);
74 else
75 waveOutClose(handle2);
77 waveOutClose(handle1);
81 * Note that in most of this test we may get MMSYSERR_BADDEVICEID errors
82 * at about any time if the user starts another application that uses the
83 * sound device. So we should not report these as test failures.
85 * This test can play a test tone. But this only makes sense if someone
86 * is going to carefully listen to it, and would only bother everyone else.
87 * So this is only done if the test is being run in interactive mode.
90 #define PI 3.14159265358979323846
91 static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
93 int i,j;
94 int nb_samples;
95 char* buf;
96 char* b;
97 WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE*)wfx;
99 nb_samples=(int)(duration*wfx->nSamplesPerSec);
100 *size=nb_samples*wfx->nBlockAlign;
101 b=buf=HeapAlloc(GetProcessHeap(), 0, *size);
102 for (i=0;i<nb_samples;i++) {
103 double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
104 if (wfx->wBitsPerSample==8) {
105 unsigned char sample=(unsigned char)(127.5*(y+1.0));
106 for (j = 0; j < wfx->nChannels; j++)
107 *b++=sample;
108 } else if (wfx->wBitsPerSample==16) {
109 signed short sample=(signed short)(32767.5*y-0.5);
110 for (j = 0; j < wfx->nChannels; j++) {
111 b[0]=sample & 0xff;
112 b[1]=sample >> 8;
113 b+=2;
115 } else if (wfx->wBitsPerSample==24) {
116 signed int sample=(signed int)(((double)0x7fffff+0.5)*y-0.5);
117 for (j = 0; j < wfx->nChannels; j++) {
118 b[0]=sample & 0xff;
119 b[1]=(sample >> 8) & 0xff;
120 b[2]=(sample >> 16) & 0xff;
121 b+=3;
123 } else if ((wfx->wBitsPerSample==32) && ((wfx->wFormatTag == WAVE_FORMAT_PCM) ||
124 ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
125 IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)))) {
126 signed int sample=(signed int)(((double)0x7fffffff+0.5)*y-0.5);
127 for (j = 0; j < wfx->nChannels; j++) {
128 b[0]=sample & 0xff;
129 b[1]=(sample >> 8) & 0xff;
130 b[2]=(sample >> 16) & 0xff;
131 b[3]=(sample >> 24) & 0xff;
132 b+=4;
134 } else if ((wfx->wBitsPerSample==32) && (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
135 IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
136 union { float f; char c[4]; } sample;
137 sample.f=(float)y;
138 for (j = 0; j < wfx->nChannels; j++) {
139 b[0]=sample.c[0];
140 b[1]=sample.c[1];
141 b[2]=sample.c[2];
142 b[3]=sample.c[3];
143 b+=4;
147 return buf;
150 static char* wave_generate_silence(WAVEFORMATEX* wfx, double duration, DWORD* size)
152 int i,j;
153 int nb_samples;
154 char* buf;
155 char* b;
156 WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE*)wfx;
158 nb_samples=(int)(duration*wfx->nSamplesPerSec);
159 *size=nb_samples*wfx->nBlockAlign;
160 b=buf=HeapAlloc(GetProcessHeap(), 0, *size);
161 for (i=0;i<nb_samples;i++) {
162 if (wfx->wBitsPerSample==8) {
163 for (j = 0; j < wfx->nChannels; j++)
164 *b++=(char)128;
165 } else if (wfx->wBitsPerSample==16) {
166 for (j = 0; j < wfx->nChannels; j++) {
167 b[0]=0;
168 b[1]=0;
169 b+=2;
171 } else if (wfx->wBitsPerSample==24) {
172 for (j = 0; j < wfx->nChannels; j++) {
173 b[0]=0;
174 b[1]=0;
175 b[2]=0;
176 b+=3;
178 } else if ((wfx->wBitsPerSample==32) && ((wfx->wFormatTag == WAVE_FORMAT_PCM) ||
179 ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
180 IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)))) {
181 for (j = 0; j < wfx->nChannels; j++) {
182 b[0]=0;
183 b[1]=0;
184 b[2]=0;
185 b[3]=0;
186 b+=4;
188 } else if ((wfx->wBitsPerSample==32) && (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
189 IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
190 union { float f; char c[4]; } sample;
191 sample.f=0;
192 for (j = 0; j < wfx->nChannels; j++) {
193 b[0]=sample.c[0];
194 b[1]=sample.c[1];
195 b[2]=sample.c[2];
196 b[3]=sample.c[3];
197 b+=4;
201 return buf;
204 const char * dev_name(int device)
206 static char name[16];
207 if (device == WAVE_MAPPER)
208 return "WAVE_MAPPER";
209 sprintf(name, "%d", device);
210 return name;
213 const char* mmsys_error(MMRESULT error)
215 #define ERR_TO_STR(dev) case dev: return #dev
216 static char unknown[32];
217 switch (error) {
218 ERR_TO_STR(MMSYSERR_NOERROR);
219 ERR_TO_STR(MMSYSERR_ERROR);
220 ERR_TO_STR(MMSYSERR_BADDEVICEID);
221 ERR_TO_STR(MMSYSERR_NOTENABLED);
222 ERR_TO_STR(MMSYSERR_ALLOCATED);
223 ERR_TO_STR(MMSYSERR_INVALHANDLE);
224 ERR_TO_STR(MMSYSERR_NODRIVER);
225 ERR_TO_STR(MMSYSERR_NOMEM);
226 ERR_TO_STR(MMSYSERR_NOTSUPPORTED);
227 ERR_TO_STR(MMSYSERR_BADERRNUM);
228 ERR_TO_STR(MMSYSERR_INVALFLAG);
229 ERR_TO_STR(MMSYSERR_INVALPARAM);
230 ERR_TO_STR(WAVERR_BADFORMAT);
231 ERR_TO_STR(WAVERR_STILLPLAYING);
232 ERR_TO_STR(WAVERR_UNPREPARED);
233 ERR_TO_STR(WAVERR_SYNC);
234 ERR_TO_STR(MIDIERR_UNPREPARED);
235 ERR_TO_STR(MIDIERR_STILLPLAYING);
236 ERR_TO_STR(MIDIERR_NOTREADY);
237 ERR_TO_STR(MIDIERR_NODEVICE);
238 ERR_TO_STR(MIDIERR_INVALIDSETUP);
239 ERR_TO_STR(TIMERR_NOCANDO);
240 ERR_TO_STR(TIMERR_STRUCT);
241 ERR_TO_STR(JOYERR_PARMS);
242 ERR_TO_STR(JOYERR_NOCANDO);
243 ERR_TO_STR(JOYERR_UNPLUGGED);
244 ERR_TO_STR(MIXERR_INVALLINE);
245 ERR_TO_STR(MIXERR_INVALCONTROL);
246 ERR_TO_STR(MIXERR_INVALVALUE);
247 ERR_TO_STR(MMIOERR_FILENOTFOUND);
248 ERR_TO_STR(MMIOERR_OUTOFMEMORY);
249 ERR_TO_STR(MMIOERR_CANNOTOPEN);
250 ERR_TO_STR(MMIOERR_CANNOTCLOSE);
251 ERR_TO_STR(MMIOERR_CANNOTREAD);
252 ERR_TO_STR(MMIOERR_CANNOTWRITE);
253 ERR_TO_STR(MMIOERR_CANNOTSEEK);
254 ERR_TO_STR(MMIOERR_CANNOTEXPAND);
255 ERR_TO_STR(MMIOERR_CHUNKNOTFOUND);
256 ERR_TO_STR(MMIOERR_UNBUFFERED);
258 sprintf(unknown, "Unknown(0x%08x)", error);
259 return unknown;
260 #undef ERR_TO_STR
263 const char* wave_out_error(MMRESULT error)
265 static char msg[1024];
266 static char long_msg[1100];
267 MMRESULT rc;
269 rc = waveOutGetErrorTextA(error, msg, sizeof(msg));
270 if (rc != MMSYSERR_NOERROR)
271 sprintf(long_msg, "waveOutGetErrorTextA(%x) failed with error %x", error, rc);
272 else
273 sprintf(long_msg, "%s(%s)", mmsys_error(error), msg);
274 return long_msg;
277 const char * wave_open_flags(DWORD flags)
279 static char msg[1024];
280 BOOL first = TRUE;
281 msg[0] = 0;
282 if ((flags & CALLBACK_TYPEMASK) == CALLBACK_EVENT) {
283 strcat(msg, "CALLBACK_EVENT");
284 first = FALSE;
286 if ((flags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION) {
287 if (!first) strcat(msg, "|");
288 strcat(msg, "CALLBACK_FUNCTION");
289 first = FALSE;
291 if ((flags & CALLBACK_TYPEMASK) == CALLBACK_NULL) {
292 if (!first) strcat(msg, "|");
293 strcat(msg, "CALLBACK_NULL");
294 first = FALSE;
296 if ((flags & CALLBACK_TYPEMASK) == CALLBACK_THREAD) {
297 if (!first) strcat(msg, "|");
298 strcat(msg, "CALLBACK_THREAD");
299 first = FALSE;
301 if ((flags & CALLBACK_TYPEMASK) == CALLBACK_WINDOW) {
302 if (!first) strcat(msg, "|");
303 strcat(msg, "CALLBACK_WINDOW");
304 first = FALSE;
306 if ((flags & WAVE_ALLOWSYNC) == WAVE_ALLOWSYNC) {
307 if (!first) strcat(msg, "|");
308 strcat(msg, "WAVE_ALLOWSYNC");
309 first = FALSE;
311 if ((flags & WAVE_FORMAT_DIRECT) == WAVE_FORMAT_DIRECT) {
312 if (!first) strcat(msg, "|");
313 strcat(msg, "WAVE_FORMAT_DIRECT");
314 first = FALSE;
316 if ((flags & WAVE_FORMAT_QUERY) == WAVE_FORMAT_QUERY) {
317 if (!first) strcat(msg, "|");
318 strcat(msg, "WAVE_FORMAT_QUERY");
319 first = FALSE;
321 if ((flags & WAVE_MAPPED) == WAVE_MAPPED) {
322 if (!first) strcat(msg, "|");
323 strcat(msg, "WAVE_MAPPED");
325 return msg;
328 static const char * wave_header_flags(DWORD flags)
330 #define WHDR_MASK (WHDR_BEGINLOOP|WHDR_DONE|WHDR_ENDLOOP|WHDR_INQUEUE|WHDR_PREPARED)
331 static char msg[1024];
332 BOOL first = TRUE;
333 msg[0] = 0;
334 if (flags & WHDR_BEGINLOOP) {
335 strcat(msg, "WHDR_BEGINLOOP");
336 first = FALSE;
338 if (flags & WHDR_DONE) {
339 if (!first) strcat(msg, " ");
340 strcat(msg, "WHDR_DONE");
341 first = FALSE;
343 if (flags & WHDR_ENDLOOP) {
344 if (!first) strcat(msg, " ");
345 strcat(msg, "WHDR_ENDLOOP");
346 first = FALSE;
348 if (flags & WHDR_INQUEUE) {
349 if (!first) strcat(msg, " ");
350 strcat(msg, "WHDR_INQUEUE");
351 first = FALSE;
353 if (flags & WHDR_PREPARED) {
354 if (!first) strcat(msg, " ");
355 strcat(msg, "WHDR_PREPARED");
356 first = FALSE;
358 if (flags & ~WHDR_MASK) {
359 char temp[32];
360 sprintf(temp, "UNKNOWN(0x%08x)", flags & ~WHDR_MASK);
361 if (!first) strcat(msg, " ");
362 strcat(msg, temp);
364 return msg;
367 static const char * wave_out_caps(DWORD dwSupport)
369 #define ADD_FLAG(f) if (dwSupport & f) strcat(msg, " " #f)
370 static char msg[256];
371 msg[0] = 0;
373 ADD_FLAG(WAVECAPS_PITCH);
374 ADD_FLAG(WAVECAPS_PLAYBACKRATE);
375 ADD_FLAG(WAVECAPS_VOLUME);
376 ADD_FLAG(WAVECAPS_LRVOLUME);
377 ADD_FLAG(WAVECAPS_SYNC);
378 ADD_FLAG(WAVECAPS_SAMPLEACCURATE);
380 return msg[0] ? msg + 1 : "";
381 #undef ADD_FLAG
384 const char * wave_time_format(UINT type)
386 static char msg[32];
387 #define TIME_FORMAT(f) case f: return #f
388 switch (type) {
389 TIME_FORMAT(TIME_MS);
390 TIME_FORMAT(TIME_SAMPLES);
391 TIME_FORMAT(TIME_BYTES);
392 TIME_FORMAT(TIME_SMPTE);
393 TIME_FORMAT(TIME_MIDI);
394 TIME_FORMAT(TIME_TICKS);
396 #undef TIME_FORMAT
397 sprintf(msg, "Unknown(0x%04x)", type);
398 return msg;
401 const char * get_format_str(WORD format)
403 static char msg[32];
404 #define WAVE_FORMAT(f) case f: return #f
405 switch (format) {
406 WAVE_FORMAT(WAVE_FORMAT_PCM);
407 WAVE_FORMAT(WAVE_FORMAT_ADPCM);
408 WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD);
409 WAVE_FORMAT(WAVE_FORMAT_ALAW);
410 WAVE_FORMAT(WAVE_FORMAT_MULAW);
411 WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM);
412 WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM);
413 WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM);
414 WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM);
415 WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM);
416 WAVE_FORMAT(WAVE_FORMAT_DIGISTD);
417 WAVE_FORMAT(WAVE_FORMAT_DIGIFIX);
418 WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM);
419 WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM);
420 WAVE_FORMAT(WAVE_FORMAT_SONARC);
421 WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH);
422 WAVE_FORMAT(WAVE_FORMAT_ECHOSC1);
423 WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36);
424 WAVE_FORMAT(WAVE_FORMAT_APTX);
425 WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10);
426 WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2);
427 WAVE_FORMAT(WAVE_FORMAT_GSM610);
428 WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME);
429 WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC);
430 WAVE_FORMAT(WAVE_FORMAT_DIGIREAL);
431 WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM);
432 WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10);
433 WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM);
434 WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM);
435 WAVE_FORMAT(WAVE_FORMAT_MPEG);
436 WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3);
437 WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM);
438 WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8);
439 WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10);
440 WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND);
441 WAVE_FORMAT(WAVE_FORMAT_OLIGSM);
442 WAVE_FORMAT(WAVE_FORMAT_OLIADPCM);
443 WAVE_FORMAT(WAVE_FORMAT_OLICELP);
444 WAVE_FORMAT(WAVE_FORMAT_OLISBC);
445 WAVE_FORMAT(WAVE_FORMAT_OLIOPR);
446 WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT);
447 WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE);
449 #undef WAVE_FORMAT
450 sprintf(msg, "Unknown(0x%04x)", format);
451 return msg;
454 DWORD bytes_to_samples(DWORD bytes, LPWAVEFORMATEX pwfx)
456 return bytes / pwfx->nBlockAlign;
459 DWORD time_to_bytes(LPMMTIME mmtime, LPWAVEFORMATEX pwfx)
461 if (mmtime->wType == TIME_BYTES)
462 return mmtime->u.cb;
463 else if (mmtime->wType == TIME_SAMPLES)
464 return mmtime->u.sample * pwfx->nBlockAlign;
466 trace("FIXME: time_to_bytes() type not supported\n");
467 return -1;
470 static void check_position(int device, HWAVEOUT wout, DWORD bytes,
471 LPWAVEFORMATEX pwfx )
473 MMTIME mmtime;
474 MMRESULT rc;
475 DWORD returned;
477 mmtime.wType = TIME_BYTES;
478 rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime) - 1);
479 ok(rc==MMSYSERR_ERROR,
480 "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
482 mmtime.wType = TIME_BYTES;
483 rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime) + 1);
484 ok(rc==MMSYSERR_NOERROR,
485 "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
486 ok(mmtime.wType == TIME_BYTES, "(waveOutGetPosition(%s): returned %s\n",
487 dev_name(device), wave_time_format(mmtime.wType));
488 returned = time_to_bytes(&mmtime, pwfx);
489 ok(returned == bytes, "waveOutGetPosition(%s): returned %d bytes, "
490 "should be %d\n", dev_name(device), returned, bytes);
492 mmtime.wType = TIME_SAMPLES;
493 rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime));
494 ok(rc==MMSYSERR_NOERROR,
495 "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
496 ok(mmtime.wType == TIME_SAMPLES, "(waveOutGetPosition(%s): returned %s\n",
497 dev_name(device), wave_time_format(mmtime.wType));
498 returned = time_to_bytes(&mmtime, pwfx);
499 ok(returned == bytes, "waveOutGetPosition(%s): returned %d samples "
500 "(%d bytes), should be %d (%d bytes)\n", dev_name(device),
501 bytes_to_samples(returned, pwfx), returned,
502 bytes_to_samples(bytes, pwfx), bytes);
504 mmtime.wType = TIME_MS;
505 rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime));
506 ok(rc==MMSYSERR_NOERROR,
507 "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
508 ok(mmtime.wType == TIME_BYTES, "(waveOutGetPosition(%s): returned %s\n",
509 dev_name(device), wave_time_format(mmtime.wType));
510 returned = time_to_bytes(&mmtime, pwfx);
511 ok(returned == bytes, "waveOutGetPosition(%s): TIME_MS test failed\n",
512 dev_name(device));
514 mmtime.wType = TIME_SMPTE;
515 rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime));
516 ok(rc==MMSYSERR_NOERROR,
517 "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
518 ok(mmtime.wType == TIME_BYTES, "(waveOutGetPosition(%s): returned %s\n",
519 dev_name(device), wave_time_format(mmtime.wType));
520 returned = time_to_bytes(&mmtime, pwfx);
521 ok(returned == bytes, "waveOutGetPosition(%s): SMPTE test failed\n",
522 dev_name(device));
524 mmtime.wType = TIME_MIDI;
525 rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime));
526 ok(rc==MMSYSERR_NOERROR,
527 "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
528 ok(mmtime.wType == TIME_BYTES, "(waveOutGetPosition(%s): returned %s\n",
529 dev_name(device), wave_time_format(mmtime.wType));
530 returned = time_to_bytes(&mmtime, pwfx);
531 ok(returned == bytes, "waveOutGetPosition(%s): MIDI test failed\n",
532 dev_name(device));
534 mmtime.wType = TIME_TICKS;
535 rc=waveOutGetPosition(wout, &mmtime, sizeof(mmtime));
536 ok(rc==MMSYSERR_NOERROR,
537 "waveOutGetPosition(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
538 ok(mmtime.wType == TIME_BYTES, "(waveOutGetPosition(%s): returned %s\n",
539 dev_name(device), wave_time_format(mmtime.wType));
540 returned = time_to_bytes(&mmtime, pwfx);
541 ok(returned == bytes, "waveOutGetPosition(%s): TICKS test failed\n",
542 dev_name(device));
545 static void CALLBACK callback_func(HWAVEOUT hwo, UINT uMsg,
546 DWORD_PTR dwInstance,
547 DWORD dwParam1, DWORD dwParam2)
549 if(uMsg == WOM_OPEN || uMsg == WOM_CLOSE)
550 ok(GetCurrentThreadId() == g_tid, "Got different thread ID\n");
551 SetEvent((HANDLE)dwInstance);
554 static DWORD WINAPI callback_thread(LPVOID lpParameter)
556 MSG msg;
558 PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); /* make sure the thread has a message queue */
559 SetEvent(lpParameter);
561 while (GetMessageA(&msg, 0, 0, 0)) {
562 UINT message = msg.message;
563 /* for some reason XP sends a WM_USER message before WOM_OPEN */
564 ok (message == WOM_OPEN || message == WOM_DONE ||
565 message == WOM_CLOSE || message == WM_USER || message == WM_APP,
566 "GetMessageA returned unexpected message: %u\n", message);
567 if (message == WOM_OPEN || message == WOM_DONE || message == WOM_CLOSE)
568 SetEvent(lpParameter);
569 else if (message == WM_APP) {
570 SetEvent(lpParameter);
571 return 0;
575 return 0;
578 static void wave_out_test_deviceOut(int device, double duration, int headers, int loops,
579 WAVEFORMATEX *pwfx, DWORD format, DWORD flags, WAVEOUTCAPSA *pcaps, BOOL interactive,
580 BOOL sine, BOOL pause)
582 HWAVEOUT wout, wout2;
583 HANDLE hevent = CreateEventW(NULL, FALSE, FALSE, NULL);
584 WAVEHDR *frags = 0;
585 WAVEOUTCAPSW capsW;
586 MMRESULT rc;
587 DWORD volume;
588 WORD nChannels = pwfx->nChannels;
589 WORD wBitsPerSample = pwfx->wBitsPerSample;
590 DWORD nSamplesPerSec = pwfx->nSamplesPerSec;
591 BOOL has_volume = (pcaps->dwSupport & WAVECAPS_VOLUME) != 0;
592 double paused = 0.0;
593 DWORD_PTR callback = 0;
594 DWORD_PTR callback_instance = 0;
595 HANDLE thread = 0;
596 DWORD thread_id;
597 char * buffer;
598 DWORD length;
599 DWORD frag_length;
600 int i, j;
602 if ((flags & CALLBACK_TYPEMASK) == CALLBACK_EVENT) {
603 callback = (DWORD_PTR)hevent;
604 callback_instance = 0;
605 } else if ((flags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION) {
606 callback = (DWORD_PTR)callback_func;
607 callback_instance = (DWORD_PTR)hevent;
608 } else if ((flags & CALLBACK_TYPEMASK) == CALLBACK_THREAD) {
609 thread = CreateThread(NULL, 0, callback_thread, hevent, 0, &thread_id);
610 if (thread) {
611 /* make sure thread is running */
612 WaitForSingleObject(hevent,10000);
613 callback = thread_id;
614 callback_instance = 0;
615 } else {
616 trace("CreateThread() failed\n");
617 CloseHandle(hevent);
618 return;
620 } else if ((flags & CALLBACK_TYPEMASK) == CALLBACK_WINDOW) {
621 trace("CALLBACK_THREAD not implemented\n");
622 CloseHandle(hevent);
623 return;
624 } else if (flags & CALLBACK_TYPEMASK) {
625 trace("Undefined callback type!\n");
626 CloseHandle(hevent);
627 return;
628 } else {
629 trace("CALLBACK_NULL not implemented\n");
630 CloseHandle(hevent);
631 return;
633 wout=NULL;
634 g_tid = GetCurrentThreadId();
635 rc=waveOutOpen(&wout,device,pwfx,callback,callback_instance,flags);
636 /* Note: Win9x doesn't know WAVE_FORMAT_DIRECT */
637 /* It is acceptable to fail on formats that are not specified to work */
638 ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_BADDEVICEID ||
639 rc==MMSYSERR_NOTENABLED || rc==MMSYSERR_NODRIVER ||
640 rc==MMSYSERR_ALLOCATED ||
641 ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) &&
642 (flags & WAVE_FORMAT_DIRECT) && !(pcaps->dwFormats & format)) ||
643 ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) &&
644 (!(flags & WAVE_FORMAT_DIRECT) || (flags & WAVE_MAPPED)) &&
645 !(pcaps->dwFormats & format)) ||
646 (rc==MMSYSERR_INVALFLAG && (flags & WAVE_FORMAT_DIRECT)),
647 "waveOutOpen(%s): format=%dx%2dx%d flags=%x(%s) rc=%s\n",
648 dev_name(device),pwfx->nSamplesPerSec,pwfx->wBitsPerSample,
649 pwfx->nChannels,flags,wave_open_flags(flags),wave_out_error(rc));
650 if ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) &&
651 (flags & WAVE_FORMAT_DIRECT) && (pcaps->dwFormats & format))
652 trace(" Reason: The device lists this format as supported in its "
653 "capabilities but opening it failed.\n");
654 if ((rc==WAVERR_BADFORMAT || rc==MMSYSERR_NOTSUPPORTED) &&
655 !(pcaps->dwFormats & format))
656 trace("waveOutOpen(%s): format=%dx%2dx%d %s rc=%s failed but format "
657 "not supported so OK.\n", dev_name(device), pwfx->nSamplesPerSec,
658 pwfx->wBitsPerSample,pwfx->nChannels,
659 flags & WAVE_FORMAT_DIRECT ? "flags=WAVE_FORMAT_DIRECT" :
660 flags & WAVE_MAPPED ? "flags=WAVE_MAPPED" : "", mmsys_error(rc));
661 if (rc!=MMSYSERR_NOERROR)
662 goto EXIT;
664 rc=WaitForSingleObject(hevent,9000);
665 ok(rc==WAIT_OBJECT_0, "missing WOM_OPEN notification\n");
667 ok(pwfx->nChannels==nChannels &&
668 pwfx->wBitsPerSample==wBitsPerSample &&
669 pwfx->nSamplesPerSec==nSamplesPerSec,
670 "got the wrong format: %dx%2dx%d instead of %dx%2dx%d\n",
671 pwfx->nSamplesPerSec, pwfx->wBitsPerSample,
672 pwfx->nChannels, nSamplesPerSec, wBitsPerSample, nChannels);
674 frags = HeapAlloc(GetProcessHeap(), 0, headers * sizeof(WAVEHDR));
676 if (sine)
677 buffer=wave_generate_la(pwfx,duration / (loops + 1),&length);
678 else
679 buffer=wave_generate_silence(pwfx,duration / (loops + 1),&length);
681 rc=waveOutGetVolume(wout,0);
682 ok(rc==MMSYSERR_INVALPARAM,"waveOutGetVolume(%s,0) expected "
683 "MMSYSERR_INVALPARAM, got %s\n", dev_name(device),wave_out_error(rc));
684 rc=waveOutGetVolume(wout,&volume);
685 if (rc == MMSYSERR_NOTSUPPORTED) has_volume = FALSE;
686 ok(has_volume ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED,
687 "waveOutGetVolume(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
689 /* waveOutGetDevCaps allows an open handle instead of a device id */
690 rc=waveOutGetDevCapsW(HandleToUlong(wout),&capsW,sizeof(capsW));
691 ok(rc==MMSYSERR_NOERROR,
692 "waveOutGetDevCapsW(%s): MMSYSERR_NOERROR "
693 "expected, got %s\n",dev_name(device),wave_out_error(rc));
695 /* waveOutOpen does not allow an open handle instead of a device id */
696 rc=waveOutOpen(&wout2,HandleToUlong(wout),pwfx,0,0,CALLBACK_NULL);
697 ok(rc==MMSYSERR_BADDEVICEID,
698 "waveOutOpen(%s): MMSYSERR_BADDEVICEID "
699 "expected, got %s\n",dev_name(device),wave_out_error(rc));
700 if(rc==MMSYSERR_NOERROR)
701 waveOutClose(wout2);
703 /* make sure fragment length is a multiple of block size */
704 frag_length = ((length / headers) / pwfx->nBlockAlign) * pwfx->nBlockAlign;
706 for (i = 0; i < headers; i++) {
707 frags[i].lpData=buffer + (i * frag_length);
708 if (i != (headers-1))
709 frags[i].dwBufferLength=frag_length;
710 else {
711 /* use remainder of buffer for last fragment */
712 frags[i].dwBufferLength=length - (i * frag_length);
714 frags[i].dwFlags=0;
715 frags[i].dwLoops=0;
716 rc=waveOutPrepareHeader(wout, &frags[i], sizeof(frags[0]));
717 ok(rc==MMSYSERR_NOERROR,
718 "waveOutPrepareHeader(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
721 if (interactive && rc==MMSYSERR_NOERROR) {
722 trace("Playing %g second %s at %5dx%2dx%d %2d header%s %d loop%s %d bytes %s %s\n",duration,
723 sine ? "440 Hz tone" : "silence", pwfx->nSamplesPerSec,
724 pwfx->wBitsPerSample,pwfx->nChannels, headers, headers > 1 ? "s": " ",
725 loops, loops == 1 ? " " : "s", length * (loops + 1),
726 get_format_str(pwfx->wFormatTag),
727 wave_open_flags(flags));
728 if (sine && has_volume && volume == 0)
729 trace("*** Warning the sound is muted, you will not hear the test\n");
731 /* Check that the position is 0 at start */
732 check_position(device, wout, 0, pwfx);
734 rc=waveOutSetVolume(wout,0x20002000);
735 ok(has_volume ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED,
736 "waveOutSetVolume(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
738 rc=waveOutSetVolume(wout,volume);
739 ok(has_volume ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED,
740 "waveOutSetVolume(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
742 rc=waveOutWrite(wout, &frags[0], sizeof(frags[0]));
743 ok(rc==MMSYSERR_NOERROR,"waveOutWrite(%s): rc=%s\n",
744 dev_name(device),wave_out_error(rc));
746 ok(frags[0].dwFlags==(WHDR_PREPARED|WHDR_INQUEUE),
747 "WHDR_INQUEUE WHDR_PREPARED expected, got= %s\n",
748 wave_header_flags(frags[0].dwFlags));
750 rc=waveOutWrite(wout, &frags[0], sizeof(frags[0]));
751 ok(rc==WAVERR_STILLPLAYING,
752 "waveOutWrite(%s): WAVE_STILLPLAYING expected, got %s\n",
753 dev_name(device),wave_out_error(rc));
755 ok(frags[0].dwFlags==(WHDR_PREPARED|WHDR_INQUEUE),
756 "WHDR_INQUEUE WHDR_PREPARED expected, got %s\n",
757 wave_header_flags(frags[0].dwFlags));
759 if (headers == 1 && loops == 0 && pause) {
760 paused = duration / 2;
761 Sleep(paused * 1000);
762 rc=waveOutPause(wout);
763 ok(rc==MMSYSERR_NOERROR,"waveOutPause(%s): rc=%s\n",
764 dev_name(device),wave_out_error(rc));
765 trace("pausing for %g seconds\n", paused);
766 Sleep(paused * 1000);
767 rc=waveOutRestart(wout);
768 ok(rc==MMSYSERR_NOERROR,"waveOutRestart(%s): rc=%s\n",
769 dev_name(device),wave_out_error(rc));
772 for (j = 0; j <= loops; j++) {
773 for (i = 0; i < headers; i++) {
774 /* don't do last one */
775 if (!((j == loops) && (i == (headers - 1)))) {
776 if (j > 0)
777 frags[(i+1) % headers].dwFlags = WHDR_PREPARED;
778 rc=waveOutWrite(wout, &frags[(i+1) % headers], sizeof(frags[0]));
779 ok(rc==MMSYSERR_NOERROR,"waveOutWrite(%s, header[%d]): rc=%s\n",
780 dev_name(device),(i+1)%headers,wave_out_error(rc));
782 rc=WaitForSingleObject(hevent,8000);
783 ok(rc==WAIT_OBJECT_0, "missing WOM_DONE notification\n");
787 for (i = 0; i < headers; i++) {
788 ok(frags[i].dwFlags==(WHDR_DONE|WHDR_PREPARED) ||
789 broken((flags & CALLBACK_TYPEMASK)==CALLBACK_EVENT &&
790 frags[i].dwFlags==(WHDR_DONE|WHDR_PREPARED|0x1000)), /* < NT4 */
791 "(%02d) WHDR_DONE WHDR_PREPARED expected, got %s\n",
792 i, wave_header_flags(frags[i].dwFlags));
794 check_position(device, wout, length * (loops + 1), pwfx);
797 for (i = 0; i < headers; i++) {
798 rc=waveOutUnprepareHeader(wout, &frags[i], sizeof(frags[0]));
799 ok(rc==MMSYSERR_NOERROR,
800 "waveOutUnprepareHeader(%s): rc=%s\n",dev_name(device),
801 wave_out_error(rc));
804 ok(frags[0].dwFlags==(interactive ? WHDR_DONE : 0), "dwFlags(%d)=%x\n",device,frags[0].dwFlags);
806 frags[0].dwFlags |= WHDR_DONE;
807 rc=waveOutUnprepareHeader(wout, &frags[0], sizeof(frags[0]));
808 ok(rc==MMSYSERR_NOERROR, "waveOutUnprepareHeader(%d): rc=%s\n",device,wave_out_error(rc));
809 ok(frags[0].dwFlags==WHDR_DONE, "dwFlags(%d)=%x\n",device,frags[0].dwFlags);
811 frags[0].dwFlags |= WHDR_INQUEUE;
812 rc=waveOutPrepareHeader(wout, &frags[0], sizeof(frags[0]));
813 ok(rc==MMSYSERR_NOERROR, "waveOutPrepareHeader(%d): rc=%s\n",device,wave_out_error(rc));
814 ok(frags[0].dwFlags==WHDR_PREPARED, "dwFlags(%d)=%x\n",device,frags[0].dwFlags);
816 frags[0].dwFlags |= WHDR_INQUEUE;
817 rc=waveOutPrepareHeader(wout, &frags[0], sizeof(frags[0]));
818 ok(rc==MMSYSERR_NOERROR, "waveOutPrepareHeader(%d): rc=%s\n",device,wave_out_error(rc));
819 ok(frags[0].dwFlags==(WHDR_PREPARED|WHDR_INQUEUE), "dwFlags(%d)=%x\n",device,frags[0].dwFlags);
821 frags[0].dwFlags &= ~(WHDR_INQUEUE|WHDR_DONE);
822 rc=waveOutUnprepareHeader(wout, &frags[0], sizeof(frags[0]));
823 ok(rc==MMSYSERR_NOERROR, "waveOutUnprepareHeader(%d): rc=%s\n",device,wave_out_error(rc));
824 ok(frags[0].dwFlags==0, "dwFlags(%d)=%x\n",device,frags[0].dwFlags);
826 rc=waveOutClose(wout);
827 ok(rc==MMSYSERR_NOERROR,"waveOutClose(%s): rc=%s\n",dev_name(device),
828 wave_out_error(rc));
829 if (rc==WAVERR_STILLPLAYING) {
830 /* waveOutReset ought to return all buffers s.t. waveOutClose succeeds */
831 rc=waveOutReset(wout);
832 ok(rc==MMSYSERR_NOERROR,"waveOutReset(%s): rc=%s\n",dev_name(device),
833 wave_out_error(rc));
835 for (i = 0; i < headers; i++) {
836 rc=waveOutUnprepareHeader(wout, &frags[i], sizeof(frags[0]));
837 ok(rc==MMSYSERR_NOERROR,
838 "waveOutUnprepareHeader(%s): rc=%s\n",dev_name(device),
839 wave_out_error(rc));
841 rc=waveOutClose(wout);
842 ok(rc==MMSYSERR_NOERROR,"waveOutClose(%s): rc=%s\n",dev_name(device),
843 wave_out_error(rc));
845 rc=WaitForSingleObject(hevent,1500);
846 ok(rc==WAIT_OBJECT_0, "missing WOM_CLOSE notification\n");
848 wout = (HWAVEOUT)0xdeadf00d;
849 rc=waveOutOpen(&wout,device,pwfx,callback,callback_instance,flags|WAVE_FORMAT_QUERY);
850 ok(rc==MMSYSERR_NOERROR, "WAVE_FORMAT_QUERY(%s): rc=%s\n",dev_name(device),
851 wave_out_error(rc));
852 ok(wout==(HWAVEOUT)0xdeadf00d, "WAVE_FORMAT_QUERY handle %p\n", wout);
854 rc=WaitForSingleObject(hevent,20);
855 ok(rc==WAIT_TIMEOUT, "Notification from %s rc=%x\n",
856 wave_open_flags(flags|WAVE_FORMAT_QUERY),rc);
858 HeapFree(GetProcessHeap(), 0, buffer);
859 EXIT:
860 if ((flags & CALLBACK_TYPEMASK) == CALLBACK_THREAD) {
861 PostThreadMessageW(thread_id, WM_APP, 0, 0);
862 WaitForSingleObject(hevent,10000);
864 CloseHandle(hevent);
865 HeapFree(GetProcessHeap(), 0, frags);
868 static void wave_out_test_device(UINT_PTR device)
870 WAVEOUTCAPSA capsA;
871 WAVEOUTCAPSW capsW;
872 WAVEFORMATEX format;
873 WAVEFORMATEXTENSIBLE wfex;
874 IMAADPCMWAVEFORMAT wfa;
875 HWAVEOUT wout;
876 MMRESULT rc;
877 UINT f;
878 WCHAR * nameW;
879 CHAR * nameA;
880 DWORD size;
881 DWORD dwPageSize;
882 BYTE * twoPages;
883 SYSTEM_INFO sSysInfo;
884 DWORD flOldProtect;
885 BOOL res;
887 GetSystemInfo(&sSysInfo);
888 dwPageSize = sSysInfo.dwPageSize;
890 rc=waveOutGetDevCapsA(device,&capsA,sizeof(capsA));
891 ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_BADDEVICEID ||
892 rc==MMSYSERR_NODRIVER,
893 "waveOutGetDevCapsA(%s): failed to get capabilities: rc=%s\n",
894 dev_name(device),wave_out_error(rc));
895 if (rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER)
896 return;
898 rc=waveOutGetDevCapsW(device,&capsW,sizeof(capsW));
899 ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED,
900 "waveOutGetDevCapsW(%s): MMSYSERR_NOERROR or MMSYSERR_NOTSUPPORTED "
901 "expected, got %s\n",dev_name(device),wave_out_error(rc));
903 rc=waveOutGetDevCapsA(device,0,sizeof(capsA));
904 ok(rc==MMSYSERR_INVALPARAM,
905 "waveOutGetDevCapsA(%s): MMSYSERR_INVALPARAM expected, "
906 "got %s\n",dev_name(device),wave_out_error(rc));
908 rc=waveOutGetDevCapsW(device,0,sizeof(capsW));
909 ok(rc==MMSYSERR_INVALPARAM || rc==MMSYSERR_NOTSUPPORTED,
910 "waveOutGetDevCapsW(%s): MMSYSERR_INVALPARAM or MMSYSERR_NOTSUPPORTED "
911 "expected, got %s\n",dev_name(device),wave_out_error(rc));
913 if (0)
915 /* FIXME: this works on windows but crashes wine */
916 rc=waveOutGetDevCapsA(device,(LPWAVEOUTCAPSA)1,sizeof(capsA));
917 ok(rc==MMSYSERR_INVALPARAM,
918 "waveOutGetDevCapsA(%s): MMSYSERR_INVALPARAM expected, got %s\n",
919 dev_name(device),wave_out_error(rc));
921 rc=waveOutGetDevCapsW(device,(LPWAVEOUTCAPSW)1,sizeof(capsW));
922 ok(rc==MMSYSERR_INVALPARAM || rc==MMSYSERR_NOTSUPPORTED,
923 "waveOutGetDevCapsW(%s): MMSYSERR_INVALPARAM or MMSYSERR_NOTSUPPORTED "
924 "expected, got %s\n",dev_name(device),wave_out_error(rc));
927 rc=waveOutGetDevCapsA(device,&capsA,4);
928 ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_INVALPARAM,
929 "waveOutGetDevCapsA(%s): MMSYSERR_NOERROR or MMSYSERR_INVALPARAM "
930 "expected, got %s\n", dev_name(device),wave_out_error(rc));
932 rc=waveOutGetDevCapsW(device,&capsW,4);
933 ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED ||
934 rc==MMSYSERR_INVALPARAM, /* Vista, W2K8 */
935 "waveOutGetDevCapsW(%s): unexpected return value %s\n",
936 dev_name(device),wave_out_error(rc));
938 rc=waveOutMessage((HWAVEOUT)device, DRV_QUERYMAPPABLE, 0, 0);
939 ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED,
940 "DRV_QUERYMAPPABLE(%s): unexpected return value %s\n",
941 dev_name(device),wave_out_error(rc));
943 nameA=NULL;
944 rc=waveOutMessage((HWAVEOUT)device, DRV_QUERYDEVICEINTERFACESIZE,
945 (DWORD_PTR)&size, 0);
946 ok(rc==MMSYSERR_NOERROR || broken(rc==MMSYSERR_INVALPARAM ||
947 rc==MMSYSERR_NOTSUPPORTED),
948 "waveOutMessage(%s): failed to get interface size, rc=%s\n",
949 dev_name(device),wave_out_error(rc));
950 if (rc==MMSYSERR_NOERROR) {
951 nameW = HeapAlloc(GetProcessHeap(), 0, size);
952 rc=waveOutMessage((HWAVEOUT)device, DRV_QUERYDEVICEINTERFACE,
953 (DWORD_PTR)nameW, size);
954 ok(rc==MMSYSERR_NOERROR,"waveOutMessage(%s): failed to get interface "
955 "name, rc=%s\n",dev_name(device),wave_out_error(rc));
956 ok(lstrlenW(nameW)+1==size/sizeof(WCHAR),"got an incorrect size %d\n",size);
957 if (rc==MMSYSERR_NOERROR) {
958 nameA = HeapAlloc(GetProcessHeap(), 0, size/sizeof(WCHAR));
959 WideCharToMultiByte(CP_ACP, 0, nameW, size/sizeof(WCHAR), nameA,
960 size/sizeof(WCHAR), NULL, NULL);
962 HeapFree(GetProcessHeap(), 0, nameW);
964 else if (rc==MMSYSERR_NOTSUPPORTED) {
965 nameA=HeapAlloc(GetProcessHeap(), 0, sizeof("not supported"));
966 strcpy(nameA, "not supported");
969 rc=waveOutGetDevCapsA(device,&capsA,sizeof(capsA));
970 ok(rc==MMSYSERR_NOERROR,
971 "waveOutGetDevCapsA(%s): MMSYSERR_NOERROR expected, got %s\n",
972 dev_name(device),wave_out_error(rc));
973 if (rc!=MMSYSERR_NOERROR)
975 HeapFree(GetProcessHeap(), 0, nameA);
976 return;
979 trace(" %s: \"%s\" (%s) %d.%d (%d:%d)\n",dev_name(device),capsA.szPname,
980 (nameA?nameA:"failed"),capsA.vDriverVersion >> 8,
981 capsA.vDriverVersion & 0xff, capsA.wMid,capsA.wPid);
982 trace(" channels=%d formats=%05x support=%04x\n",
983 capsA.wChannels,capsA.dwFormats,capsA.dwSupport);
984 trace(" %s\n",wave_out_caps(capsA.dwSupport));
985 HeapFree(GetProcessHeap(), 0, nameA);
987 if (winetest_interactive && (device != WAVE_MAPPER))
989 trace("Playing a 5 seconds reference tone.\n");
990 trace("All subsequent tones should be identical to this one.\n");
991 trace("Listen for stutter, changes in pitch, volume, etc.\n");
992 format.wFormatTag=WAVE_FORMAT_PCM;
993 format.nChannels=1;
994 format.wBitsPerSample=8;
995 format.nSamplesPerSec=22050;
996 format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
997 format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
998 format.cbSize=0;
1000 wave_out_test_deviceOut(device,5.0,1,0,&format,WAVE_FORMAT_2M08,
1001 CALLBACK_EVENT,&capsA,TRUE,TRUE,FALSE);
1002 wave_out_test_deviceOut(device,5.0,1,0,&format,WAVE_FORMAT_2M08,
1003 CALLBACK_FUNCTION,&capsA,TRUE,TRUE,FALSE);
1004 wave_out_test_deviceOut(device,5.0,1,0,&format,WAVE_FORMAT_2M08,
1005 CALLBACK_THREAD,&capsA,TRUE,TRUE,FALSE);
1007 wave_out_test_deviceOut(device,5.0,10,0,&format,WAVE_FORMAT_2M08,
1008 CALLBACK_EVENT,&capsA,TRUE,TRUE,FALSE);
1009 wave_out_test_deviceOut(device,5.0,5,1,&format,WAVE_FORMAT_2M08,
1010 CALLBACK_EVENT,&capsA,TRUE,TRUE,FALSE);
1011 } else {
1012 format.wFormatTag=WAVE_FORMAT_PCM;
1013 format.nChannels=1;
1014 format.wBitsPerSample=8;
1015 format.nSamplesPerSec=22050;
1016 format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
1017 format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
1018 format.cbSize=0;
1019 wave_out_test_deviceOut(device,0.6,1,0,&format,WAVE_FORMAT_2M08,
1020 CALLBACK_EVENT,&capsA,TRUE,FALSE,FALSE);
1021 wave_out_test_deviceOut(device,0.6,1,0,&format,WAVE_FORMAT_2M08,
1022 CALLBACK_EVENT,&capsA,TRUE,FALSE,TRUE);
1023 wave_out_test_deviceOut(device,0.6,1,0,&format,WAVE_FORMAT_2M08,
1024 CALLBACK_FUNCTION,&capsA,TRUE,FALSE,FALSE);
1025 wave_out_test_deviceOut(device,0.6,1,0,&format,WAVE_FORMAT_2M08,
1026 CALLBACK_FUNCTION,&capsA,TRUE,FALSE,TRUE);
1027 wave_out_test_deviceOut(device,0.6,1,0,&format,WAVE_FORMAT_2M08,
1028 CALLBACK_THREAD,&capsA,TRUE,FALSE,FALSE);
1029 wave_out_test_deviceOut(device,0.6,1,0,&format,WAVE_FORMAT_2M08,
1030 CALLBACK_THREAD,&capsA,TRUE,FALSE,TRUE);
1032 wave_out_test_deviceOut(device,0.8,10,0,&format,WAVE_FORMAT_2M08,
1033 CALLBACK_EVENT,&capsA,TRUE,FALSE,FALSE);
1034 wave_out_test_deviceOut(device,1.0,5,1,&format,WAVE_FORMAT_2M08,
1035 CALLBACK_EVENT,&capsA,TRUE,FALSE,FALSE);
1038 for (f = 0; f < ARRAY_SIZE(win_formats); f++) {
1039 format.wFormatTag=WAVE_FORMAT_PCM;
1040 format.nChannels=win_formats[f][3];
1041 format.wBitsPerSample=win_formats[f][2];
1042 format.nSamplesPerSec=win_formats[f][1];
1043 format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
1044 format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
1045 format.cbSize=0;
1046 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1047 CALLBACK_EVENT,&capsA,winetest_interactive,
1048 TRUE,FALSE);
1049 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1050 CALLBACK_FUNCTION,&capsA,winetest_interactive,
1051 TRUE,FALSE);
1052 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1053 CALLBACK_THREAD,&capsA,winetest_interactive,
1054 TRUE,FALSE);
1056 wave_out_test_deviceOut(device,1.0,10,0,&format,win_formats[f][0],
1057 CALLBACK_EVENT,&capsA,winetest_interactive,
1058 TRUE,FALSE);
1059 wave_out_test_deviceOut(device,1.0,5,1,&format,win_formats[f][0],
1060 CALLBACK_EVENT,&capsA,winetest_interactive,
1061 TRUE,FALSE);
1063 if (winetest_interactive) {
1064 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1065 CALLBACK_EVENT,&capsA,winetest_interactive,
1066 TRUE,TRUE);
1067 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1068 CALLBACK_FUNCTION,&capsA,winetest_interactive,
1069 TRUE,TRUE);
1070 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1071 CALLBACK_THREAD,&capsA,winetest_interactive,
1072 TRUE,TRUE);
1074 wave_out_test_deviceOut(device,1.0,10,0,&format,win_formats[f][0],
1075 CALLBACK_EVENT,&capsA,winetest_interactive,
1076 TRUE,TRUE);
1077 wave_out_test_deviceOut(device,1.0,5,1,&format,win_formats[f][0],
1078 CALLBACK_EVENT,&capsA,winetest_interactive,
1079 TRUE,TRUE);
1081 if (device != WAVE_MAPPER)
1083 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1084 CALLBACK_EVENT|WAVE_FORMAT_DIRECT,&capsA,
1085 winetest_interactive,TRUE,FALSE);
1086 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1087 CALLBACK_EVENT|WAVE_MAPPED,&capsA,
1088 winetest_interactive,TRUE,FALSE);
1089 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1090 CALLBACK_FUNCTION|WAVE_FORMAT_DIRECT,&capsA,
1091 winetest_interactive,TRUE,FALSE);
1092 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1093 CALLBACK_FUNCTION|WAVE_MAPPED,&capsA,
1094 winetest_interactive,TRUE,FALSE);
1095 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1096 CALLBACK_THREAD|WAVE_FORMAT_DIRECT,&capsA,
1097 winetest_interactive,TRUE,FALSE);
1098 wave_out_test_deviceOut(device,1.0,1,0,&format,win_formats[f][0],
1099 CALLBACK_THREAD|WAVE_MAPPED,&capsA,
1100 winetest_interactive,TRUE,FALSE);
1102 wave_out_test_deviceOut(device,1.0,10,0,&format,win_formats[f][0],
1103 CALLBACK_EVENT|WAVE_FORMAT_DIRECT,&capsA,
1104 winetest_interactive,TRUE,FALSE);
1105 wave_out_test_deviceOut(device,1.0,5,1,&format,win_formats[f][0],
1106 CALLBACK_EVENT|WAVE_FORMAT_DIRECT,&capsA,
1107 winetest_interactive,TRUE,FALSE);
1111 /* Try a PCMWAVEFORMAT aligned next to an unaccessible page for bounds
1112 * checking */
1113 twoPages = VirtualAlloc(NULL, 2 * dwPageSize, MEM_RESERVE | MEM_COMMIT,
1114 PAGE_READWRITE);
1115 ok(twoPages!=NULL,"Failed to allocate 2 pages of memory\n");
1116 if (twoPages) {
1117 res = VirtualProtect(twoPages + dwPageSize, dwPageSize, PAGE_NOACCESS,
1118 &flOldProtect);
1119 ok(res, "Failed to set memory access on second page\n");
1120 if (res) {
1121 LPWAVEFORMATEX pwfx = (LPWAVEFORMATEX)(twoPages + dwPageSize -
1122 sizeof(PCMWAVEFORMAT));
1123 pwfx->wFormatTag=WAVE_FORMAT_PCM;
1124 pwfx->nChannels=1;
1125 pwfx->wBitsPerSample=8;
1126 pwfx->nSamplesPerSec=22050;
1127 pwfx->nBlockAlign=pwfx->nChannels*pwfx->wBitsPerSample/8;
1128 pwfx->nAvgBytesPerSec=pwfx->nSamplesPerSec*pwfx->nBlockAlign;
1129 wave_out_test_deviceOut(device,1.0,1,0,pwfx,WAVE_FORMAT_2M08,
1130 CALLBACK_EVENT,&capsA,winetest_interactive,
1131 TRUE,FALSE);
1132 wave_out_test_deviceOut(device,1.0,10,0,pwfx,WAVE_FORMAT_2M08,
1133 CALLBACK_EVENT,&capsA,winetest_interactive,
1134 TRUE,FALSE);
1135 wave_out_test_deviceOut(device,1.0,5,1,pwfx,WAVE_FORMAT_2M08,
1136 CALLBACK_EVENT,&capsA,winetest_interactive,
1137 TRUE,FALSE);
1138 if (device != WAVE_MAPPER)
1140 wave_out_test_deviceOut(device,1.0,1,0,pwfx,WAVE_FORMAT_2M08,
1141 CALLBACK_EVENT|WAVE_FORMAT_DIRECT,
1142 &capsA,winetest_interactive,TRUE,FALSE);
1143 wave_out_test_deviceOut(device,1.0,1,0,pwfx,WAVE_FORMAT_2M08,
1144 CALLBACK_EVENT|WAVE_MAPPED,&capsA,
1145 winetest_interactive,TRUE,FALSE);
1146 wave_out_test_deviceOut(device,1.0,10,0,pwfx,WAVE_FORMAT_2M08,
1147 CALLBACK_EVENT|WAVE_FORMAT_DIRECT,
1148 &capsA,winetest_interactive,TRUE,FALSE);
1149 wave_out_test_deviceOut(device,1.0,10,0,pwfx,WAVE_FORMAT_2M08,
1150 CALLBACK_EVENT|WAVE_MAPPED,&capsA,
1151 winetest_interactive,TRUE,FALSE);
1152 wave_out_test_deviceOut(device,1.0,5,1,pwfx,WAVE_FORMAT_2M08,
1153 CALLBACK_EVENT|WAVE_FORMAT_DIRECT,
1154 &capsA,winetest_interactive,TRUE,FALSE);
1155 wave_out_test_deviceOut(device,1.0,5,1,pwfx,WAVE_FORMAT_2M08,
1156 CALLBACK_EVENT|WAVE_MAPPED,&capsA,
1157 winetest_interactive,TRUE,FALSE);
1160 VirtualFree(twoPages, 0, MEM_RELEASE);
1163 /* try some non PCM formats */
1164 format.wFormatTag=WAVE_FORMAT_MULAW;
1165 format.nChannels=1;
1166 format.wBitsPerSample=8;
1167 format.nSamplesPerSec=8000;
1168 format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
1169 format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
1170 format.cbSize=0;
1171 rc=waveOutOpen(&wout,device,&format,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1172 ok(rc==MMSYSERR_NOERROR ||rc==WAVERR_BADFORMAT ||
1173 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1174 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1175 if (rc==MMSYSERR_NOERROR) {
1176 waveOutClose(wout);
1177 wave_out_test_deviceOut(device,1.0,1,0,&format,0,CALLBACK_EVENT,
1178 &capsA,winetest_interactive,TRUE,FALSE);
1179 wave_out_test_deviceOut(device,1.0,10,0,&format,0,CALLBACK_EVENT,
1180 &capsA,winetest_interactive,TRUE,FALSE);
1181 wave_out_test_deviceOut(device,1.0,5,1,&format,0,CALLBACK_EVENT,
1182 &capsA,winetest_interactive,TRUE,FALSE);
1183 } else {
1184 MMRESULT query_rc;
1186 trace("waveOutOpen(%s): WAVE_FORMAT_MULAW not supported\n",
1187 dev_name(device));
1189 query_rc = waveOutOpen(NULL, device, &format, 0, 0, CALLBACK_NULL | WAVE_FORMAT_QUERY);
1190 ok(query_rc==MMSYSERR_NOERROR || query_rc==WAVERR_BADFORMAT || query_rc==MMSYSERR_INVALPARAM,
1191 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1193 rc = waveOutOpen(&wout, device, &format, 0, 0, CALLBACK_NULL);
1194 ok(rc == query_rc,
1195 "waveOutOpen(%s): returned different from query: %s\n",dev_name(device),wave_out_error(rc));
1196 if(rc == MMSYSERR_NOERROR)
1197 waveOutClose(wout);
1200 wfa.wfx.wFormatTag=WAVE_FORMAT_IMA_ADPCM;
1201 wfa.wfx.nChannels=1;
1202 wfa.wfx.nSamplesPerSec=11025;
1203 wfa.wfx.nAvgBytesPerSec=5588;
1204 wfa.wfx.nBlockAlign=256;
1205 wfa.wfx.wBitsPerSample=4; /* see imaadp32.c */
1206 wfa.wfx.cbSize=2;
1207 wfa.wSamplesPerBlock=505;
1208 rc=waveOutOpen(&wout,device,&wfa.wfx,0,0,CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1209 ok(rc==MMSYSERR_NOERROR ||rc==WAVERR_BADFORMAT ||
1210 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1211 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1212 if (rc==MMSYSERR_NOERROR) {
1213 waveOutClose(wout);
1214 /* TODO: teach wave_generate_* ADPCM
1215 wave_out_test_deviceOut(device,1.0,1,0,&wfa.wfx,0,CALLBACK_EVENT,
1216 &capsA,winetest_interactive,TRUE,FALSE);
1217 wave_out_test_deviceOut(device,1.0,10,0,&wfa.wfx,0,CALLBACK_EVENT,
1218 &capsA,winetest_interactive,TRUE,FALSE);
1219 wave_out_test_deviceOut(device,1.0,5,1,&wfa.wfx,0,CALLBACK_EVENT,
1220 &capsA,winetest_interactive,TRUE,FALSE);
1222 } else
1223 trace("waveOutOpen(%s): WAVE_FORMAT_IMA_ADPCM not supported\n",
1224 dev_name(device));
1226 /* test if WAVEFORMATEXTENSIBLE supported */
1227 wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
1228 wfex.Format.nChannels=2;
1229 wfex.Format.wBitsPerSample=16;
1230 wfex.Format.nSamplesPerSec=22050;
1231 wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8;
1232 wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*
1233 wfex.Format.nBlockAlign;
1234 wfex.Format.cbSize=22;
1235 wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample;
1236 wfex.dwChannelMask=SPEAKER_ALL;
1237 wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM;
1238 rc=waveOutOpen(&wout,device,&wfex.Format,0,0,
1239 CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1240 ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT ||
1241 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1242 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1243 if (rc==MMSYSERR_NOERROR) {
1244 waveOutClose(wout);
1245 wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16,
1246 CALLBACK_EVENT,&capsA,winetest_interactive,
1247 TRUE,FALSE);
1248 wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16,
1249 CALLBACK_EVENT,&capsA,winetest_interactive,
1250 TRUE,FALSE);
1251 wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16,
1252 CALLBACK_EVENT,&capsA,winetest_interactive,
1253 TRUE,FALSE);
1254 } else
1255 trace("waveOutOpen(%s): WAVE_FORMAT_EXTENSIBLE not supported\n",
1256 dev_name(device));
1258 /* test if 4 channels supported */
1259 wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
1260 wfex.Format.nChannels=4;
1261 wfex.Format.wBitsPerSample=16;
1262 wfex.Format.nSamplesPerSec=22050;
1263 wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8;
1264 wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*
1265 wfex.Format.nBlockAlign;
1266 wfex.Format.cbSize=22;
1267 wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample;
1268 wfex.dwChannelMask=SPEAKER_ALL;
1269 wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM;
1270 rc=waveOutOpen(&wout,device,&wfex.Format,0,0,
1271 CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1272 ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT ||
1273 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1274 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1275 if (rc==MMSYSERR_NOERROR) {
1276 waveOutClose(wout);
1277 wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,0,CALLBACK_EVENT,
1278 &capsA,winetest_interactive,TRUE,FALSE);
1279 wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,0,CALLBACK_EVENT,
1280 &capsA,winetest_interactive,TRUE,FALSE);
1281 wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,0,CALLBACK_EVENT,
1282 &capsA,winetest_interactive,TRUE,FALSE);
1283 } else
1284 trace("waveOutOpen(%s): 4 channels not supported\n",
1285 dev_name(device));
1287 /* test if 6 channels supported */
1288 wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
1289 wfex.Format.nChannels=6;
1290 wfex.Format.wBitsPerSample=16;
1291 wfex.Format.nSamplesPerSec=22050;
1292 wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8;
1293 wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*
1294 wfex.Format.nBlockAlign;
1295 wfex.Format.cbSize=22;
1296 wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample;
1297 wfex.dwChannelMask=SPEAKER_ALL;
1298 wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM;
1299 rc=waveOutOpen(&wout,device,&wfex.Format,0,0,
1300 CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1301 ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT ||
1302 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1303 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1304 if (rc==MMSYSERR_NOERROR) {
1305 waveOutClose(wout);
1306 wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16,
1307 CALLBACK_EVENT,&capsA,winetest_interactive,
1308 TRUE,FALSE);
1309 wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16,
1310 CALLBACK_EVENT,&capsA,winetest_interactive,
1311 TRUE,FALSE);
1312 wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16,
1313 CALLBACK_EVENT,&capsA,winetest_interactive,
1314 TRUE,FALSE);
1315 } else
1316 trace("waveOutOpen(%s): 6 channels not supported\n",
1317 dev_name(device));
1319 if (0)
1321 /* FIXME: ALSA doesn't like this format */
1322 /* test if 24 bit samples supported */
1323 wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
1324 wfex.Format.nChannels=2;
1325 wfex.Format.wBitsPerSample=24;
1326 wfex.Format.nSamplesPerSec=22050;
1327 wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8;
1328 wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*
1329 wfex.Format.nBlockAlign;
1330 wfex.Format.cbSize=22;
1331 wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample;
1332 wfex.dwChannelMask=SPEAKER_ALL;
1333 wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM;
1334 rc=waveOutOpen(&wout,device,&wfex.Format,0,0,
1335 CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1336 ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT ||
1337 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1338 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1339 if (rc==MMSYSERR_NOERROR) {
1340 waveOutClose(wout);
1341 wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16,
1342 CALLBACK_EVENT,&capsA,winetest_interactive,
1343 TRUE,FALSE);
1344 } else
1345 trace("waveOutOpen(%s): 24 bit samples not supported\n",
1346 dev_name(device));
1349 /* test if 32 bit samples supported */
1350 wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
1351 wfex.Format.nChannels=2;
1352 wfex.Format.wBitsPerSample=32;
1353 wfex.Format.nSamplesPerSec=22050;
1354 wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8;
1355 wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*
1356 wfex.Format.nBlockAlign;
1357 wfex.Format.cbSize=22;
1358 wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample;
1359 wfex.dwChannelMask=SPEAKER_ALL;
1360 wfex.SubFormat=KSDATAFORMAT_SUBTYPE_PCM;
1361 rc=waveOutOpen(&wout,device,&wfex.Format,0,0,
1362 CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1363 ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT ||
1364 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1365 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1366 if (rc==MMSYSERR_NOERROR) {
1367 waveOutClose(wout);
1368 wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16,
1369 CALLBACK_EVENT,&capsA,winetest_interactive,
1370 TRUE,FALSE);
1371 wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16,
1372 CALLBACK_EVENT,&capsA,winetest_interactive,
1373 TRUE,FALSE);
1374 wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16,
1375 CALLBACK_EVENT,&capsA,winetest_interactive,
1376 TRUE,FALSE);
1377 } else
1378 trace("waveOutOpen(%s): 32 bit samples not supported\n",
1379 dev_name(device));
1381 /* test if 32 bit float samples supported */
1382 wfex.Format.wFormatTag=WAVE_FORMAT_EXTENSIBLE;
1383 wfex.Format.nChannels=2;
1384 wfex.Format.wBitsPerSample=32;
1385 wfex.Format.nSamplesPerSec=22050;
1386 wfex.Format.nBlockAlign=wfex.Format.nChannels*wfex.Format.wBitsPerSample/8;
1387 wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*
1388 wfex.Format.nBlockAlign;
1389 wfex.Format.cbSize=22;
1390 wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample;
1391 wfex.dwChannelMask=SPEAKER_ALL;
1392 wfex.SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1393 rc=waveOutOpen(&wout,device,&wfex.Format,0,0,
1394 CALLBACK_NULL|WAVE_FORMAT_DIRECT);
1395 ok(rc==MMSYSERR_NOERROR || rc==WAVERR_BADFORMAT ||
1396 rc==MMSYSERR_INVALFLAG || rc==MMSYSERR_INVALPARAM,
1397 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1398 if (rc==MMSYSERR_NOERROR) {
1399 waveOutClose(wout);
1400 wave_out_test_deviceOut(device,1.0,1,0,&wfex.Format,WAVE_FORMAT_2M16,
1401 CALLBACK_EVENT,&capsA,winetest_interactive,
1402 TRUE,FALSE);
1403 wave_out_test_deviceOut(device,1.0,10,0,&wfex.Format,WAVE_FORMAT_2M16,
1404 CALLBACK_EVENT,&capsA,winetest_interactive,
1405 TRUE,FALSE);
1406 wave_out_test_deviceOut(device,1.0,5,1,&wfex.Format,WAVE_FORMAT_2M16,
1407 CALLBACK_EVENT,&capsA,winetest_interactive,
1408 TRUE,FALSE);
1409 } else
1410 trace("waveOutOpen(%s): 32 bit float samples not supported\n",
1411 dev_name(device));
1413 /* Test invalid parameters */
1415 format.wFormatTag = WAVE_FORMAT_PCM;
1416 format.nChannels = 1;
1417 format.nSamplesPerSec = 11025;
1418 format.nBlockAlign = 1;
1419 format.nAvgBytesPerSec = 11025 * 1;
1420 format.wBitsPerSample = 8;
1421 format.cbSize = 0;
1423 format.nAvgBytesPerSec = 0;
1424 rc = waveOutOpen(&wout, device, &format, 0, 0, 0);
1425 ok(rc == MMSYSERR_NOERROR,
1426 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1427 waveOutClose(wout);
1428 format.nAvgBytesPerSec = 11025 * 1;
1430 format.nSamplesPerSec = 0;
1431 rc = waveOutOpen(&wout, device, &format, 0, 0, 0);
1432 ok(rc == MMSYSERR_INVALPARAM || rc == WAVERR_BADFORMAT, /* XP and lower return WAVERR_BADFORMAT */
1433 "waveOutOpen(%s): returned %s\n",dev_name(device),wave_out_error(rc));
1436 static void wave_out_tests(void)
1438 WAVEOUTCAPSA capsA;
1439 WAVEOUTCAPSW capsW;
1440 WAVEFORMATEX format;
1441 HWAVEOUT wout;
1442 MMRESULT rc;
1443 DWORD preferred, status;
1444 UINT ndev,d;
1446 ndev=waveOutGetNumDevs();
1447 trace("found %d WaveOut devices\n",ndev);
1449 rc = waveOutMessage((HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
1450 (DWORD_PTR)&preferred, (DWORD_PTR)&status);
1451 ok((ndev == 0 && (rc == MMSYSERR_NODRIVER || rc == MMSYSERR_BADDEVICEID)) ||
1452 rc == MMSYSERR_NOTSUPPORTED ||
1453 rc == MMSYSERR_NOERROR, "waveOutMessage(DRVM_MAPPER_PREFERRED_GET) failed: %u\n", rc);
1455 if(rc != MMSYSERR_NOTSUPPORTED)
1456 ok((ndev == 0 && (preferred == -1 || broken(preferred != -1))) ||
1457 preferred < ndev, "Got invalid preferred device: 0x%x\n", preferred);
1459 rc = waveOutMessage((HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
1460 (DWORD_PTR)-1 , 0);
1461 ok(rc == MMSYSERR_INVALPARAM || rc == MMSYSERR_BADDEVICEID, /* w2008+wvista */
1462 "waveOutMessage(DRVM_MAPPER_PREFERRED_GET) failed: %u\n", rc);
1464 rc = waveOutMessage((HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
1465 0, (DWORD_PTR)&status);
1466 ok(rc == MMSYSERR_INVALPARAM || rc == MMSYSERR_BADDEVICEID, /* w2008+wvista */
1467 "waveOutMessage(DRVM_MAPPER_PREFERRED_GET) failed: %u\n", rc);
1469 rc=waveOutGetDevCapsA(ndev+1,&capsA,sizeof(capsA));
1470 ok(rc==MMSYSERR_BADDEVICEID,
1471 "waveOutGetDevCapsA(%s): MMSYSERR_BADDEVICEID expected, got %s\n",
1472 dev_name(ndev+1),mmsys_error(rc));
1474 rc=waveOutGetDevCapsW(ndev+1,&capsW,sizeof(capsW));
1475 ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NOTSUPPORTED,
1476 "waveOutGetDevCapsW(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED "
1477 "expected, got %s\n",dev_name(ndev+1),mmsys_error(rc));
1479 rc=waveOutGetDevCapsA(WAVE_MAPPER,&capsA,sizeof(capsA));
1480 if (ndev>0)
1481 ok(rc==MMSYSERR_NOERROR,
1482 "waveOutGetDevCapsA(%s): MMSYSERR_NOERROR expected, got %s\n",
1483 dev_name(WAVE_MAPPER),mmsys_error(rc));
1484 else
1485 ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER,
1486 "waveOutGetDevCapsA(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NODRIVER "
1487 "expected, got %s\n",dev_name(WAVE_MAPPER),mmsys_error(rc));
1489 rc=waveOutGetDevCapsW(WAVE_MAPPER,&capsW,sizeof(capsW));
1490 if (ndev>0)
1491 ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_NOTSUPPORTED,
1492 "waveOutGetDevCapsW(%s): MMSYSERR_NOERROR or MMSYSERR_NOTSUPPORTED "
1493 "expected, got %s\n",dev_name(WAVE_MAPPER),mmsys_error(rc));
1494 else
1495 ok(rc==MMSYSERR_BADDEVICEID || rc==MMSYSERR_NODRIVER ||
1496 rc==MMSYSERR_NOTSUPPORTED,
1497 "waveOutGetDevCapsW(%s): MMSYSERR_BADDEVICEID or MMSYSERR_NODRIVER "
1498 " or MMSYSERR_NOTSUPPORTED expected, got %s\n",
1499 dev_name(WAVE_MAPPER),mmsys_error(rc));
1501 format.wFormatTag=WAVE_FORMAT_PCM;
1502 format.nChannels=2;
1503 format.wBitsPerSample=16;
1504 format.nSamplesPerSec=44100;
1505 format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
1506 format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
1507 format.cbSize=0;
1508 rc=waveOutOpen(&wout,ndev+1,&format,0,0,CALLBACK_NULL);
1509 ok(rc==MMSYSERR_BADDEVICEID,
1510 "waveOutOpen(%s): MMSYSERR_BADDEVICEID expected, got %s\n",
1511 dev_name(ndev+1),mmsys_error(rc));
1513 if(winetest_interactive)
1514 for (d=0;d<ndev;d++)
1515 wave_out_test_device(d);
1517 if (ndev>0)
1518 wave_out_test_device(WAVE_MAPPER);
1521 static void test_sndPlaySound(void)
1523 BOOL br;
1525 br = sndPlaySoundA((LPCSTR)SND_ALIAS_SYSTEMASTERISK, SND_ALIAS_ID|SND_SYNC);
1526 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1528 br = sndPlaySoundW((LPCWSTR)SND_ALIAS_SYSTEMASTERISK, SND_ALIAS_ID|SND_SYNC);
1529 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1531 br = sndPlaySoundA((LPCSTR)sndAlias('X','Y'), SND_ALIAS_ID|SND_SYNC);
1532 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1534 br = sndPlaySoundW((LPCWSTR)sndAlias('X','Y'), SND_ALIAS_ID|SND_SYNC);
1535 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1537 br = sndPlaySoundA("SystemAsterisk", SND_ALIAS|SND_SYNC);
1538 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1540 br = sndPlaySoundW(L"SystemAsterisk", SND_ALIAS|SND_SYNC);
1541 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1543 br = sndPlaySoundA("C:\not_exist.wav", SND_FILENAME|SND_SYNC);
1544 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1546 br = sndPlaySoundW(L"C:\\not_exist.wav", SND_FILENAME|SND_SYNC);
1547 ok(br == TRUE || br == FALSE, "sndPlaySound gave strange return: %u\n", br);
1550 static void test_fragmentsize(void)
1552 MMRESULT rc;
1553 WAVEHDR hdr[2];
1554 HWAVEOUT wout;
1555 WAVEFORMATEX fmt;
1556 MMTIME mmtime;
1557 DWORD wait;
1558 HANDLE hevent;
1560 if(waveOutGetNumDevs() == 0)
1561 return;
1563 fmt.wFormatTag = WAVE_FORMAT_PCM;
1564 fmt.nChannels = 2;
1565 fmt.nSamplesPerSec = 44100;
1566 fmt.wBitsPerSample = 16;
1567 fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
1568 fmt.nAvgBytesPerSec = fmt.nBlockAlign * fmt.nSamplesPerSec;
1569 fmt.cbSize = sizeof(WAVEFORMATEX);
1571 hevent = CreateEventW(NULL, FALSE, FALSE, NULL);
1572 g_tid = GetCurrentThreadId();
1574 rc = waveOutOpen(&wout, WAVE_MAPPER, &fmt, (DWORD_PTR)callback_func,
1575 (DWORD_PTR)hevent, CALLBACK_FUNCTION);
1576 ok(rc == MMSYSERR_NOERROR || rc == WAVERR_BADFORMAT ||
1577 rc == MMSYSERR_INVALFLAG || rc == MMSYSERR_INVALPARAM,
1578 "waveOutOpen(%s) failed: %s\n", dev_name(WAVE_MAPPER), wave_out_error(rc));
1579 if(rc != MMSYSERR_NOERROR){
1580 CloseHandle(hevent);
1581 return;
1584 wait = WaitForSingleObject(hevent, 1000);
1585 ok(wait == WAIT_OBJECT_0, "wave open callback missed\n");
1587 memset(hdr, 0, sizeof(hdr));
1588 hdr[0].dwBufferLength = (fmt.nSamplesPerSec * fmt.nBlockAlign / 4) + 1;
1589 hdr[1].dwBufferLength = hdr[0].dwBufferLength - 2;
1590 hdr[1].lpData = hdr[0].lpData =
1591 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, hdr[0].dwBufferLength);
1593 rc = waveOutPrepareHeader(wout, &hdr[0], sizeof(hdr[0]));
1594 ok(rc == MMSYSERR_NOERROR, "waveOutPrepareHeader failed: %s\n", wave_out_error(rc));
1596 rc = waveOutPrepareHeader(wout, &hdr[1], sizeof(hdr[1]));
1597 ok(rc == MMSYSERR_NOERROR, "waveOutPrepareHeader failed: %s\n", wave_out_error(rc));
1599 trace("writing %u bytes then %u bytes\n", hdr[0].dwBufferLength, hdr[1].dwBufferLength);
1600 rc = waveOutWrite(wout, &hdr[0], sizeof(hdr[0]));
1601 ok(rc == MMSYSERR_NOERROR, "waveOutWrite failed: %s\n", wave_out_error(rc));
1603 rc = waveOutWrite(wout, &hdr[1], sizeof(hdr[1]));
1604 ok(rc == MMSYSERR_NOERROR, "waveOutWrite failed: %s\n", wave_out_error(rc));
1606 wait = WaitForSingleObject(hevent, 1000);
1607 ok(wait == WAIT_OBJECT_0, "header 1 callback missed\n");
1609 wait = WaitForSingleObject(hevent, 1000);
1610 ok(wait == WAIT_OBJECT_0, "header 2 callback missed\n");
1612 memset(&mmtime, 0, sizeof(mmtime));
1613 mmtime.wType = TIME_BYTES;
1615 rc = waveOutGetPosition(wout, &mmtime, sizeof(mmtime));
1616 ok(rc == MMSYSERR_NOERROR, "waveOutGetPosition failed: %s\n", wave_out_error(rc));
1618 /* windows behavior is inconsistent */
1619 ok(mmtime.u.cb == 88200 ||
1620 mmtime.u.cb == 88196, "after position: %u\n", mmtime.u.cb);
1622 rc = waveOutClose(wout);
1623 ok(rc == MMSYSERR_NOERROR, "waveOutClose failed: %s\n", wave_out_error(rc));
1625 HeapFree(GetProcessHeap(), 0, hdr[0].lpData);
1626 CloseHandle(hevent);
1629 static void CALLBACK test_reentrant_callback_func(HWAVEOUT hwo, UINT uMsg,
1630 DWORD_PTR dwInstance,
1631 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1633 static int wom_done_count = 0;
1635 switch(uMsg){
1636 case WOM_OPEN:
1637 case WOM_CLOSE:
1638 ok(GetCurrentThreadId() == g_tid, "Got different thread ID\n");
1639 break;
1641 case WOM_DONE:
1642 /* verify that WOM_DONE is not sent during the following waveOutWrite */
1643 todo_wine_if(wom_done_count == 1)
1644 ok(g_tid == 0, "callback called reentrantly\n");
1646 g_tid = GetCurrentThreadId();
1648 if(wom_done_count++ == 0){
1649 Sleep(125); /* ensure 2nd header is done playing before waveOutWrite */
1650 waveOutWrite(hwo, (WAVEHDR *)dwParam1, sizeof(WAVEHDR));
1653 break;
1656 g_tid = 0;
1657 SetEvent((HANDLE)dwInstance);
1660 static void test_reentrant_callback(void)
1662 MMRESULT rc;
1663 WAVEHDR hdr[2];
1664 HWAVEOUT wout;
1665 WAVEFORMATEX fmt;
1666 DWORD wait;
1667 HANDLE hevent;
1669 if(waveOutGetNumDevs() == 0)
1670 return;
1672 fmt.wFormatTag = WAVE_FORMAT_PCM;
1673 fmt.nChannels = 2;
1674 fmt.nSamplesPerSec = 44100;
1675 fmt.wBitsPerSample = 16;
1676 fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
1677 fmt.nAvgBytesPerSec = fmt.nBlockAlign * fmt.nSamplesPerSec;
1678 fmt.cbSize = sizeof(WAVEFORMATEX);
1680 hevent = CreateEventW(NULL, FALSE, FALSE, NULL);
1681 g_tid = GetCurrentThreadId();
1683 rc = waveOutOpen(&wout, WAVE_MAPPER, &fmt, (DWORD_PTR)test_reentrant_callback_func,
1684 (DWORD_PTR)hevent, CALLBACK_FUNCTION);
1685 ok(rc == MMSYSERR_NOERROR || rc == WAVERR_BADFORMAT ||
1686 rc == MMSYSERR_INVALFLAG || rc == MMSYSERR_INVALPARAM,
1687 "waveOutOpen(%s) failed: %s\n", dev_name(WAVE_MAPPER), wave_out_error(rc));
1688 if(rc != MMSYSERR_NOERROR){
1689 CloseHandle(hevent);
1690 return;
1693 wait = WaitForSingleObject(hevent, 1000);
1694 ok(wait == WAIT_OBJECT_0, "wave open callback missed\n");
1696 memset(hdr, 0, sizeof(hdr));
1697 hdr[0].dwBufferLength = (fmt.nSamplesPerSec * fmt.nBlockAlign / 10);
1698 hdr[1].dwBufferLength = hdr[0].dwBufferLength;
1699 hdr[1].lpData = hdr[0].lpData =
1700 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, hdr[0].dwBufferLength);
1702 rc = waveOutPrepareHeader(wout, &hdr[0], sizeof(hdr[0]));
1703 ok(rc == MMSYSERR_NOERROR, "waveOutPrepareHeader failed: %s\n", wave_out_error(rc));
1705 rc = waveOutPrepareHeader(wout, &hdr[1], sizeof(hdr[1]));
1706 ok(rc == MMSYSERR_NOERROR, "waveOutPrepareHeader failed: %s\n", wave_out_error(rc));
1708 rc = waveOutWrite(wout, &hdr[0], sizeof(hdr[0]));
1709 ok(rc == MMSYSERR_NOERROR, "waveOutWrite failed: %s\n", wave_out_error(rc));
1711 rc = waveOutWrite(wout, &hdr[1], sizeof(hdr[1]));
1712 ok(rc == MMSYSERR_NOERROR, "waveOutWrite failed: %s\n", wave_out_error(rc));
1714 wait = WaitForSingleObject(hevent, 1000);
1715 ok(wait == WAIT_OBJECT_0, "header 1 callback missed\n");
1717 wait = WaitForSingleObject(hevent, 1000);
1718 ok(wait == WAIT_OBJECT_0, "header 2 callback missed\n");
1720 wait = WaitForSingleObject(hevent, 1000);
1721 ok(wait == WAIT_OBJECT_0, "header 3 callback missed\n");
1723 g_tid = GetCurrentThreadId();
1724 rc = waveOutClose(wout);
1725 ok(rc == MMSYSERR_NOERROR, "waveOutClose failed: %s\n", wave_out_error(rc));
1727 HeapFree(GetProcessHeap(), 0, hdr[0].lpData);
1728 CloseHandle(hevent);
1731 static void create_wav_file(char *temp_file)
1733 WAVEFORMATEX format;
1734 HMMIO h;
1735 MMCKINFO riff_chunk, chunk;
1736 MMRESULT rc;
1737 LONG written;
1738 DWORD length;
1739 char *buffer;
1741 format.wFormatTag=WAVE_FORMAT_PCM;
1742 format.cbSize = 0;
1743 format.nChannels=1;
1744 format.wBitsPerSample=8;
1745 format.nSamplesPerSec=8000;
1746 format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
1747 format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
1749 h = mmioOpenA(temp_file, NULL, MMIO_ALLOCBUF | MMIO_WRITE | MMIO_CREATE);
1750 ok(h != NULL, "Can't open temp_file\n");
1752 riff_chunk.fccType = mmioFOURCC('W','A','V','E');
1753 riff_chunk.cksize = 0;
1754 rc = mmioCreateChunk(h, &riff_chunk, MMIO_CREATERIFF);
1755 ok(rc == MMSYSERR_NOERROR, "mmioCreateChunk failed, got %u\n", rc);
1757 chunk.ckid = mmioFOURCC('f','m','t',' ');
1758 chunk.cksize = 0;
1759 rc = mmioCreateChunk(h, &chunk, 0);
1760 ok(rc == MMSYSERR_NOERROR, "mmioCreateChunk failed, got %u\n", rc);
1761 written = mmioWrite(h, (char*)&format, sizeof(format));
1762 ok(written == sizeof(format), "mmioWrite failed, got %d\n", written);
1763 rc = mmioAscend(h, &chunk, 0);
1764 ok(rc == MMSYSERR_NOERROR, "mmioAscend failed, got %d\n", rc);
1766 chunk.ckid = mmioFOURCC('d','a','t','a');
1767 rc = mmioCreateChunk(h, &chunk, 0);
1768 ok(rc == MMSYSERR_NOERROR, "mmioCreateChunk failed, got %u\n", rc);
1769 buffer = wave_generate_silence(&format, .1, &length);
1770 written = mmioWrite(h, buffer, length);
1771 ok(written == length, "mmioWrite failed, got %d\n", written);
1772 rc = mmioAscend(h, &chunk, 0);
1773 ok(rc == MMSYSERR_NOERROR, "mmioAscend failed, got %d\n", rc);
1774 HeapFree(GetProcessHeap(), 0, buffer);
1776 rc = mmioAscend(h, &riff_chunk, 0);
1777 ok(rc == MMSYSERR_NOERROR, "mmioAscend failed, got %d\n", rc);
1779 rc = mmioClose(h, 0);
1780 ok(rc == MMSYSERR_NOERROR, "mmioClose failed, got %u\n", rc);
1783 static void test_PlaySound(void)
1785 BOOL br;
1786 char test_file[MAX_PATH], temp[MAX_PATH], *exts;
1787 void *psound_ordinal, *psound_name;
1788 HMODULE dll = GetModuleHandleA("winmm.dll");
1790 psound_name = GetProcAddress(dll, "PlaySound");
1791 psound_ordinal = GetProcAddress(dll, (LPCSTR) 2);
1792 ok(psound_name == psound_ordinal, "Expected ordinal 2 to be PlaySound function\n");
1794 if(waveOutGetNumDevs() == 0) {
1795 skip("No output devices available\n");
1796 return;
1799 GetTempPathA(sizeof(test_file), test_file);
1800 strcat(test_file, "mysound.wav");
1801 create_wav_file(test_file);
1803 br = PlaySoundA(test_file, NULL, SND_FILENAME | SND_NODEFAULT);
1804 ok(br, "PlaySound failed, got %d\n", br);
1806 /* SND_ALIAS fallbacks to SND_FILENAME */
1807 br = PlaySoundA(test_file, NULL, SND_ALIAS | SND_NODEFAULT);
1808 ok(br, "PlaySound failed, got %d\n", br);
1810 strcpy(temp, test_file);
1811 exts = strrchr(temp, '.');
1813 /* no extensions */
1814 *exts = '\0';
1815 br = PlaySoundA(temp, NULL, SND_FILENAME | SND_NODEFAULT);
1816 ok(br, "PlaySound failed, got %d\n", br);
1818 /* ends with a dot */
1819 strcpy(exts, ".");
1820 br = PlaySoundA(temp, NULL, SND_FILENAME | SND_NODEFAULT);
1821 ok(!br || broken(br), "PlaySound succeeded, got %d\n", br);
1823 DeleteFileA(test_file);
1826 START_TEST(wave)
1828 test_multiple_waveopens();
1829 wave_out_tests();
1830 test_sndPlaySound();
1831 test_fragmentsize();
1832 test_reentrant_callback();
1833 test_PlaySound();