2 * Unit tests for dsound functions
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define NONAMELESSSTRUCT
22 #define NONAMELESSUNION
28 #include "wine/test.h"
33 static const unsigned int formats[][3]={
59 #define NB_FORMATS (sizeof(formats)/sizeof(*formats))
61 /* The time slice determines how often we will service the buffer and the
62 * buffer will be four time slices long
64 #define TIME_SLICE 100
65 #define BUFFER_LEN (4*TIME_SLICE)
66 #define TONE_DURATION (6*TIME_SLICE)
68 /* This test can play a test tone. But this only makes sense if someone
69 * is going to carefully listen to it, and would only bother everyone else.
70 * So this is only done if the test is being run in interactive mode.
73 #define PI 3.14159265358979323846
74 static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
81 nb_samples=(int)(duration*wfx->nSamplesPerSec);
82 *size=nb_samples*wfx->nBlockAlign;
84 for (i=0;i<nb_samples;i++) {
85 double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
86 if (wfx->wBitsPerSample==8) {
87 unsigned char sample=(unsigned char)((double)127.5*(y+1.0));
89 if (wfx->nChannels==2)
92 signed short sample=(signed short)((double)32767.5*y-0.5);
96 if (wfx->nChannels==2) {
106 static HWND get_hwnd()
108 HWND hwnd=GetForegroundWindow();
110 hwnd=GetDesktopWindow();
114 static void init_format(WAVEFORMATEX* wfx, int rate, int depth, int channels)
116 wfx->wFormatTag=WAVE_FORMAT_PCM;
117 wfx->nChannels=channels;
118 wfx->wBitsPerSample=depth;
119 wfx->nSamplesPerSec=rate;
120 wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
121 wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
129 LPDIRECTSOUNDBUFFER dsbo;
138 static int buffer_refill(play_state_t* state, DWORD size)
144 if (size>state->wave_len-state->written)
145 size=state->wave_len-state->written;
147 rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
148 &ptr1,&len1,&ptr2,&len2,0);
149 ok(rc==DS_OK,"Lock: 0x%lx",rc);
153 memcpy(ptr1,state->wave+state->written,len1);
154 state->written+=len1;
156 memcpy(ptr2,state->wave+state->written,len2);
157 state->written+=len2;
159 state->offset=state->written % state->buffer_size;
160 rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
161 ok(rc==DS_OK,"Unlock: 0x%lx",rc);
167 static int buffer_silence(play_state_t* state, DWORD size)
174 rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
175 &ptr1,&len1,&ptr2,&len2,0);
176 ok(rc==DS_OK,"Lock: 0x%lx",rc);
180 s=(state->wfx->wBitsPerSample==8?0x80:0);
185 state->offset=(state->offset+size) % state->buffer_size;
186 rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
187 ok(rc==DS_OK,"Unlock: 0x%lx",rc);
193 static int buffer_service(play_state_t* state)
195 DWORD play_pos,write_pos,buf_free;
198 rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,&write_pos);
199 ok(rc==DS_OK,"GetCurrentPosition: %lx",rc);
204 /* Refill the buffer */
205 if (state->offset<=play_pos) {
206 buf_free=play_pos-state->offset;
208 buf_free=state->buffer_size-state->offset+play_pos;
210 if (winetest_debug > 1)
211 trace("buf pos=%ld free=%ld written=%ld / %ld\n",
212 play_pos,buf_free,state->written,state->wave_len);
216 if (state->written<state->wave_len) {
217 int w=buffer_refill(state,buf_free);
221 if (state->written==state->wave_len) {
222 state->last_pos=(state->offset<play_pos)?play_pos:0;
223 if (winetest_debug > 1)
224 trace("last sound byte at %ld\n",
225 (state->written % state->buffer_size));
228 if (state->last_pos!=0 && play_pos<state->last_pos) {
229 /* We wrapped around the end of the buffer */
232 if (state->last_pos==0 &&
233 play_pos>(state->written % state->buffer_size)) {
234 /* Now everything has been played */
240 /* Fill with silence */
241 if (winetest_debug > 1)
242 trace("writing %ld bytes of silence\n",buf_free);
243 if (buffer_silence(state,buf_free)==-1)
249 if (winetest_debug > 1)
250 trace("stopping playback\n");
251 rc=IDirectSoundBuffer_Stop(state->dsbo);
252 ok(rc==DS_OK,"Stop failed: rc=%ld",rc);
256 static void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo,
257 int is_primary, BOOL set_volume, LONG volume,
258 BOOL set_pan, LONG pan, int play, int buffer3d,
259 LPDIRECTSOUND3DLISTENER listener,
260 int move_listener, int move_sound)
264 WAVEFORMATEX wfx,wfx2;
265 DWORD size,status,freq;
268 /* DSOUND: Error: Invalid caps pointer */
269 rc=IDirectSoundBuffer_GetCaps(dsbo,0);
270 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
272 ZeroMemory(&dsbcaps, sizeof(dsbcaps));
274 /* DSOUND: Error: Invalid caps pointer */
275 rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
276 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
278 dsbcaps.dwSize=sizeof(dsbcaps);
279 rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
280 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
282 trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags,
283 dsbcaps.dwBufferBytes);
286 /* Query the format size. Note that it may not match sizeof(wfx) */
288 rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size);
289 ok(rc==DS_OK && size!=0,
290 "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
293 rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
294 ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
296 trace(" tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
297 wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
298 wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
301 /* DSOUND: Error: Invalid frequency buffer */
302 rc=IDirectSoundBuffer_GetFrequency(dsbo,0);
303 ok(rc==DSERR_INVALIDPARAM,"GetFrequency should have failed: 0x%lx\n",rc);
305 /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */
306 rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq);
307 ok((rc==DS_OK&&!is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) ||
308 (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)),
309 "GetFrequency failed: 0x%lx\n",rc);
311 ok(freq==wfx.nSamplesPerSec,
312 "The frequency returned by GetFrequency %ld does not match the format %ld\n",
313 freq,wfx.nSamplesPerSec);
316 /* DSOUND: Error: Invalid status pointer */
317 rc=IDirectSoundBuffer_GetStatus(dsbo,0);
318 ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc);
320 rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
321 ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
323 trace(" status=0x%04lx\n",status);
327 /* We must call SetCooperativeLevel to be allowed to call SetFormat */
328 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
329 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
330 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
334 /* DSOUND: Error: Invalid format pointer */
335 rc=IDirectSoundBuffer_SetFormat(dsbo,0);
336 ok(rc==DSERR_INVALIDPARAM,"SetFormat should have failed: 0x%lx\n",rc);
338 init_format(&wfx2,11025,16,2);
339 rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2);
340 ok(rc==DS_OK,"SetFormat failed: 0x%lx\n",rc);
342 /* There is no garantee that SetFormat will actually change the
343 * format to what we asked for. It depends on what the soundcard
344 * supports. So we must re-query the format.
346 rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
347 ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
349 trace(" tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
350 wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
351 wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
354 /* Set the CooperativeLevel back to normal */
355 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
356 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
357 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
363 LPDIRECTSOUND3DBUFFER buffer=NULL;
364 DS3DBUFFER buffer_param;
365 DS3DLISTENER listener_param;
366 trace(" Playing 440Hz LA at %ldx%dx%d\n",
367 wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels);
370 /* We must call SetCooperativeLevel to be allowed to call Lock */
371 /* DSOUND: Setting DirectSound cooperative level to DSSCL_WRITEPRIMARY */
372 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_WRITEPRIMARY);
373 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
378 LPDIRECTSOUNDBUFFER temp_buffer;
380 rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer,(LPVOID *)&buffer);
381 ok(rc==DS_OK,"QueryInterface failed: 0x%lx\n",rc);
385 /* check the COM interface */
386 rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
387 ok(rc==DS_OK&&temp_buffer!=NULL,"QueryInterface failed: 0x%lx\n",rc);
388 ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo);
389 ref=IDirectSoundBuffer_Release(temp_buffer);
390 ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
393 rc=IDirectSound3DBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
394 ok(rc==DS_OK&&temp_buffer!=NULL,"IDirectSound3DBuffer_QueryInterface failed: 0x%lx\n",rc);
395 ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo);
396 ref=IDirectSoundBuffer_Release(temp_buffer);
397 ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
399 #if 0 /* FIXME: this works on windows */
400 ref=IDirectSoundBuffer_Release(dsbo);
401 ok(ref==0,"IDirectSoundBuffer_Release has %d references, should have 0\n",ref);
403 rc=IDirectSound3DBuffer_QueryInterface(buffer, &IID_IDirectSoundBuffer,(LPVOID *)&dsbo);
404 ok(rc==DS_OK&&dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface failed: 0x%lx\n",rc);
407 /* DSOUND: Error: Invalid buffer */
408 rc=IDirectSound3DBuffer_GetAllParameters(buffer,0);
409 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc);
411 ZeroMemory(&buffer_param, sizeof(buffer_param));
413 /* DSOUND: Error: Invalid buffer */
414 rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
415 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc);
417 buffer_param.dwSize=sizeof(buffer_param);
418 rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
419 ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc);
422 rc=IDirectSoundBuffer_SetVolume(dsbo,volume);
423 ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
425 rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
426 trace(" volume=%ld\n",volume);
428 if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
429 rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
430 ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc);
432 rc=IDirectSoundBuffer_SetVolume(dsbo,-300);
433 ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
435 rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
436 trace(" volume=%ld\n",volume);
438 /* DSOUND: Error: Buffer does not have CTRLVOLUME */
439 rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
440 ok(rc==DSERR_CONTROLUNAVAIL,"GetVolume should have failed: 0x%lx\n",rc);
445 rc=IDirectSoundBuffer_SetPan(dsbo,pan);
446 ok(rc==DS_OK,"SetPan failed: 0x%lx\n",rc);
448 rc=IDirectSoundBuffer_GetPan(dsbo,&pan);
449 trace(" pan=%ld\n",pan);
451 if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) {
452 rc=IDirectSoundBuffer_GetPan(dsbo,&pan);
453 ok(rc==DS_OK,"GetPan failed: 0x%lx\n",rc);
455 rc=IDirectSoundBuffer_SetPan(dsbo,0);
456 ok(rc==DS_OK,"SetPan failed: 0x%lx\n",rc);
458 rc=IDirectSoundBuffer_GetPan(dsbo,&pan);
459 trace(" pan=%ld\n",pan);
461 /* DSOUND: Error: Buffer does not have CTRLPAN */
462 rc=IDirectSoundBuffer_GetPan(dsbo,&pan);
463 ok(rc==DSERR_CONTROLUNAVAIL,"GetPan should have failed: 0x%lx\n",rc);
467 state.wave=wave_generate_la(&wfx,((double)TONE_DURATION)/1000,&state.wave_len);
471 state.buffer_size=dsbcaps.dwBufferBytes;
472 state.written=state.offset=0;
473 buffer_refill(&state,state.buffer_size);
475 rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING);
476 ok(rc==DS_OK,"Play: 0x%lx\n",rc);
478 rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
479 ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
480 ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
481 "GetStatus: bad status: %lx",status);
484 ZeroMemory(&listener_param,sizeof(listener_param));
485 listener_param.dwSize=sizeof(listener_param);
486 rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param);
487 ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
489 listener_param.vPosition.x = -5.0;
491 listener_param.vPosition.x = 0.0;
492 listener_param.vPosition.y = 0.0;
493 listener_param.vPosition.z = 0.0;
494 rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.x,listener_param.vPosition.y,listener_param.vPosition.z,DS3D_IMMEDIATE);
495 ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc);
499 buffer_param.vPosition.x = 5.0;
501 buffer_param.vPosition.x = 0.0;
502 buffer_param.vPosition.y = 0.0;
503 buffer_param.vPosition.z = 0.0;
504 rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.x,buffer_param.vPosition.y,buffer_param.vPosition.z,DS3D_IMMEDIATE);
505 ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc);
508 while (buffer_service(&state)) {
509 WaitForSingleObject(GetCurrentProcess(),TIME_SLICE/2);
510 if (listener&&move_listener) {
511 listener_param.vPosition.x += 0.5;
512 rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.x,listener_param.vPosition.y,listener_param.vPosition.z,DS3D_IMMEDIATE);
513 ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc);
515 if (buffer3d&&move_sound) {
516 buffer_param.vPosition.x -= 0.5;
517 rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.x,buffer_param.vPosition.y,buffer_param.vPosition.z,DS3D_IMMEDIATE);
518 ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc);
522 if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
523 rc=IDirectSoundBuffer_SetVolume(dsbo,volume);
524 ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
529 /* Set the CooperativeLevel back to normal */
530 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
531 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
532 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
535 ref=IDirectSound3DBuffer_Release(buffer);
536 ok(ref==0,"IDirectSound3DBuffer_Release has %d references, should have 0\n",ref);
541 static HRESULT test_secondary(LPGUID lpGuid, int play,
542 int has_3d, int has_3dbuffer,
543 int has_listener, int has_duplicate,
544 int move_listener, int move_sound)
547 LPDIRECTSOUND dso=NULL;
548 LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
549 LPDIRECTSOUND3DLISTENER listener=NULL;
550 DSBUFFERDESC bufdesc;
555 /* Create the DirectSound object */
556 rc=DirectSoundCreate(lpGuid,&dso,NULL);
557 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
561 /* Get the device capabilities */
562 ZeroMemory(&dscaps, sizeof(dscaps));
563 dscaps.dwSize=sizeof(dscaps);
564 rc=IDirectSound_GetCaps(dso,&dscaps);
565 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
569 /* We must call SetCooperativeLevel before creating primary buffer */
570 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
571 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
572 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
576 ZeroMemory(&bufdesc, sizeof(bufdesc));
577 bufdesc.dwSize=sizeof(bufdesc);
578 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
580 bufdesc.dwFlags|=DSBCAPS_CTRL3D;
582 bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
583 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
584 ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a %sprimary buffer 0x%lx\n",has_3d?"3D ":"", rc);
585 if (rc==DS_OK&&primary!=NULL) {
587 rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener);
588 ok(rc==DS_OK&&listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc);
589 ref=IDirectSoundBuffer_Release(primary);
590 ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
591 if(rc==DS_OK&&listener!=NULL) {
592 DS3DLISTENER listener_param;
593 ZeroMemory(&listener_param,sizeof(listener_param));
594 /* DSOUND: Error: Invalid buffer */
595 rc=IDirectSound3DListener_GetAllParameters(listener,0);
596 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
598 /* DSOUND: Error: Invalid buffer */
599 rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param);
600 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
602 listener_param.dwSize=sizeof(listener_param);
603 rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param);
604 ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
609 for (f=0;f<NB_FORMATS;f++) {
610 init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
612 ZeroMemory(&bufdesc, sizeof(bufdesc));
613 bufdesc.dwSize=sizeof(bufdesc);
614 bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
616 bufdesc.dwFlags|=DSBCAPS_CTRL3D;
618 bufdesc.dwFlags|=(DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
619 bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
620 bufdesc.lpwfxFormat=&wfx;
621 trace(" Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d\n",
622 has_3dbuffer?"3D ":"",
623 has_duplicate?"duplicated ":"",
624 listener!=NULL||move_sound?"with ":"",
625 move_listener?"moving ":"",
626 listener!=NULL?"listener ":"",
627 listener&&move_sound?"and moving sound ":move_sound?"moving sound ":"",
628 wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
629 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
630 ok(rc==DS_OK&&secondary!=NULL,"CreateSoundBuffer failed to create a 3D secondary buffer 0x%lx\n",rc);
631 if (rc==DS_OK&&secondary!=NULL) {
633 LPDIRECTSOUNDBUFFER duplicated=NULL;
635 /* DSOUND: Error: Invalid source buffer */
636 rc=IDirectSound_DuplicateSoundBuffer(dso,0,0);
637 ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
639 /* DSOUND: Error: Invalid dest buffer */
640 rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0);
641 ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
643 /* DSOUND: Error: Invalid source buffer */
644 rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated);
645 ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
648 rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,&duplicated);
649 ok(rc==DS_OK&&duplicated!=NULL,"IDirectSound_DuplicateSoundBuffer failed to duplicate a secondary buffer 0x%lx\n",rc);
651 if (rc==DS_OK&&duplicated!=NULL) {
652 ref=IDirectSoundBuffer_Release(secondary);
653 ok(ref==0,"IDirectSoundBuffer_Release secondary has %d references, should have 0\n",ref);
654 secondary=duplicated;
658 if (rc==DS_OK&&secondary!=NULL) {
659 test_buffer(dso,secondary,0,FALSE,0,FALSE,0,winetest_interactive,has_3dbuffer,listener,move_listener,move_sound);
660 ref=IDirectSoundBuffer_Release(secondary);
661 ok(ref==0,"IDirectSoundBuffer_Release %s has %d references, should have 0\n",has_duplicate?"duplicated":"secondary",ref);
666 ref=IDirectSound3DListener_Release(listener);
667 ok(ref==0,"IDirectSound3dListener_Release listener has %d references, should have 0\n",ref);
669 ref=IDirectSoundBuffer_Release(primary);
670 ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
673 /* Set the CooperativeLevel back to normal */
674 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
675 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
676 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
679 ref=IDirectSound_Release(dso);
680 ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
682 return DSERR_GENERIC;
687 static HRESULT test_dsound(LPGUID lpGuid)
690 LPDIRECTSOUND dso=NULL;
692 DWORD speaker_config, new_speaker_config;
695 /* DSOUND: Error: Invalid interface buffer */
696 rc=DirectSoundCreate(lpGuid,0,NULL);
697 ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate should have failed: 0x%lx\n",rc);
699 /* Create the DirectSound object */
700 rc=DirectSoundCreate(lpGuid,&dso,NULL);
701 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
705 /* DSOUND: Error: Invalid caps buffer */
706 rc=IDirectSound_GetCaps(dso,0);
707 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
709 ZeroMemory(&dscaps, sizeof(dscaps));
711 /* DSOUND: Error: Invalid caps buffer */
712 rc=IDirectSound_GetCaps(dso,&dscaps);
713 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
715 dscaps.dwSize=sizeof(dscaps);
717 /* DSOUND: Running on a certified driver */
718 rc=IDirectSound_GetCaps(dso,&dscaps);
719 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
721 trace(" DirectSound Caps: flags=0x%08lx secondary min=%ld max=%ld\n",
722 dscaps.dwFlags,dscaps.dwMinSecondarySampleRate,
723 dscaps.dwMaxSecondarySampleRate);
726 rc=IDirectSound_GetSpeakerConfig(dso,0);
727 ok(rc==DSERR_INVALIDPARAM,"GetSpeakerConfig should have failed: 0x%lx\n",rc);
729 rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config);
730 ok(rc==DS_OK,"GetSpeakerConfig failed: 0x%lx\n",rc);
732 trace(" DirectSound SpeakerConfig: 0x%08lx\n", speaker_config);
735 speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO,DSSPEAKER_GEOMETRY_WIDE);
736 rc=IDirectSound_SetSpeakerConfig(dso,speaker_config);
737 ok(rc==DS_OK,"SetSpeakerConfig failed: 0x%lx\n",rc);
739 rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config);
740 ok(rc==DS_OK,"GetSpeakerConfig failed: 0x%lx\n",rc);
742 ok(speaker_config==new_speaker_config,"SetSpeakerConfig failed to set speaker config: expected 0x%08lx, got 0x%08lx\n",
743 speaker_config,new_speaker_config);
746 /* Release the DirectSound object */
747 ref=IDirectSound_Release(dso);
748 ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
750 return DSERR_GENERIC;
752 #if 0 /* FIXME: this works on windows */
753 /* Create a DirectSound object */
754 rc=DirectSoundCreate(lpGuid,&dso,NULL);
755 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
757 LPDIRECTSOUND dso1=NULL;
759 /* Create a second DirectSound object */
760 rc=DirectSoundCreate(lpGuid,&dso1,NULL);
761 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
763 /* Release the second DirectSound object */
764 ref=IDirectSound_Release(dso1);
765 ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
766 ok(dso!=dso1,"DirectSound objects should be unique: dso=0x%08lx,dso1=0x%08lx\n",(DWORD)dso,(DWORD)dso1);
769 /* Release the first DirectSound object */
770 ref=IDirectSound_Release(dso);
771 ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
773 return DSERR_GENERIC;
781 static HRESULT test_primary(LPGUID lpGuid)
784 LPDIRECTSOUND dso=NULL;
785 LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL;
786 DSBUFFERDESC bufdesc;
790 /* Create the DirectSound object */
791 rc=DirectSoundCreate(lpGuid,&dso,NULL);
792 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
796 /* Get the device capabilities */
797 ZeroMemory(&dscaps, sizeof(dscaps));
798 dscaps.dwSize=sizeof(dscaps);
799 rc=IDirectSound_GetCaps(dso,&dscaps);
800 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
804 /* DSOUND: Error: Invalid buffer description pointer */
805 rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL);
806 ok(rc==DSERR_INVALIDPARAM,"CreateSoundBuffer should have failed: 0x%lx\n",rc);
808 /* DSOUND: Error: Invalid buffer description pointer */
809 rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL);
810 ok(rc==DSERR_INVALIDPARAM && primary==0,"CreateSoundBuffer should have failed: rc=0x%lx,dsbo=0x%lx\n",rc,(DWORD)primary);
812 /* DSOUND: Error: Invalid buffer description pointer */
813 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,0,NULL);
814 ok(rc==DSERR_INVALIDPARAM && primary==0,"CreateSoundBuffer should have failed: rc=0x%lx,dsbo=0x%lx\n",rc,(DWORD)primary);
816 ZeroMemory(&bufdesc, sizeof(bufdesc));
818 /* DSOUND: Error: Invalid size */
819 /* DSOUND: Error: Invalid buffer description */
820 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
821 ok(rc==DSERR_INVALIDPARAM && primary==0,"CreateSoundBuffer should have failed: rc=0x%lx,primary=0x%lx\n",rc,(DWORD)primary);
823 /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
824 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
825 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
826 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
830 /* Testing the primary buffer */
832 ZeroMemory(&bufdesc, sizeof(bufdesc));
833 bufdesc.dwSize=sizeof(bufdesc);
834 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN;
835 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
836 ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a primary buffer: 0x%lx\n",rc);
837 if (rc==DS_OK&&primary!=NULL) {
838 /* Try to create a second primary buffer */
839 /* DSOUND: Error: The primary buffer already exists. Any changes made to the buffer description will be ignored. */
840 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&second,NULL);
841 ok(rc==DS_OK&&second==primary,"CreateSoundBuffer should have returned original primary buffer: 0x%lx\n",rc);
842 ref=IDirectSoundBuffer_Release(second);
843 ok(ref==1,"IDirectSoundBuffer_Release primary has %d references, should have 1\n",ref);
844 /* Try to duplicate a primary buffer */
845 /* DSOUND: Error: Can't duplicate primary buffers */
846 rc=IDirectSound_DuplicateSoundBuffer(dso,primary,&third);
848 ok(rc!=DS_OK,"IDirectSound_DuplicateSoundBuffer primary buffer should have failed 0x%lx\n",rc);
849 test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,0,0,0);
850 test_buffer(dso,primary,1,TRUE,0,TRUE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,0,0,0);
851 if (winetest_interactive) {
852 LONG volume = DSBVOLUME_MAX;
853 for (i = 0; i < 6; i++) {
854 test_buffer(dso,primary,1,TRUE,volume,TRUE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,0,0,0);
855 volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40);
857 if (winetest_interactive) {
858 LONG pan = DSBPAN_LEFT;
859 for (i = 0; i < 7; i++) {
860 test_buffer(dso,primary,1,TRUE,0,TRUE,pan,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,0,0,0);
861 pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6);
865 ref=IDirectSoundBuffer_Release(primary);
866 ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
869 /* Set the CooperativeLevel back to normal */
870 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
871 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
872 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
875 ref=IDirectSound_Release(dso);
876 ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
878 return DSERR_GENERIC;
883 static HRESULT test_primary_3d(LPGUID lpGuid)
886 LPDIRECTSOUND dso=NULL;
887 LPDIRECTSOUNDBUFFER primary=NULL;
888 DSBUFFERDESC bufdesc;
892 /* Create the DirectSound object */
893 rc=DirectSoundCreate(lpGuid,&dso,NULL);
894 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
898 /* Get the device capabilities */
899 ZeroMemory(&dscaps, sizeof(dscaps));
900 dscaps.dwSize=sizeof(dscaps);
901 rc=IDirectSound_GetCaps(dso,&dscaps);
902 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
906 /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
907 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
908 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
909 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
914 ZeroMemory(&bufdesc, sizeof(bufdesc));
915 bufdesc.dwSize=sizeof(bufdesc);
916 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
917 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
918 ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a primary buffer: 0x%lx\n",rc);
919 if (rc==DS_OK&&primary!=NULL) {
920 ref=IDirectSoundBuffer_Release(primary);
921 ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
923 ZeroMemory(&bufdesc, sizeof(bufdesc));
924 bufdesc.dwSize=sizeof(bufdesc);
925 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
926 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
927 ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer: 0x%lx\n",rc);
928 if (rc==DS_OK&&primary!=NULL) {
929 test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,0,0,0);
930 ref=IDirectSoundBuffer_Release(primary);
931 ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
934 /* Set the CooperativeLevel back to normal */
935 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
936 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
937 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
940 ref=IDirectSound_Release(dso);
941 ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
943 return DSERR_GENERIC;
948 static HRESULT test_primary_3d_with_listener(LPGUID lpGuid)
951 LPDIRECTSOUND dso=NULL;
952 LPDIRECTSOUNDBUFFER primary=NULL;
953 DSBUFFERDESC bufdesc;
957 /* Create the DirectSound object */
958 rc=DirectSoundCreate(lpGuid,&dso,NULL);
959 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
963 /* Get the device capabilities */
964 ZeroMemory(&dscaps, sizeof(dscaps));
965 dscaps.dwSize=sizeof(dscaps);
966 rc=IDirectSound_GetCaps(dso,&dscaps);
967 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
971 /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
972 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
973 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
974 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
978 ZeroMemory(&bufdesc, sizeof(bufdesc));
979 bufdesc.dwSize=sizeof(bufdesc);
980 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
981 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
982 ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer 0x%lx\n",rc);
983 if (rc==DS_OK&&primary!=NULL) {
984 LPDIRECTSOUND3DLISTENER listener=NULL;
985 rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener);
986 ok(rc==DS_OK&&listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc);
987 if (rc==DS_OK&&listener!=NULL) {
988 LPDIRECTSOUNDBUFFER temp_buffer=NULL;
990 /* Checking the COM interface */
991 rc=IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
992 ok(rc==DS_OK&&temp_buffer!=NULL,"IDirectSoundBuffer_QueryInterface failed: 0x%lx\n",rc);
993 ok(temp_buffer==primary,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary);
994 if(rc==DS_OK&&temp_buffer!=NULL) {
995 ref=IDirectSoundBuffer_Release(temp_buffer);
996 ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
999 rc=IDirectSound3DListener_QueryInterface(listener, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
1000 ok(rc==DS_OK&&temp_buffer!=NULL,"IDirectSoundBuffer_QueryInterface failed: 0x%lx\n",rc);
1001 ok(temp_buffer==primary,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary);
1002 ref=IDirectSoundBuffer_Release(temp_buffer);
1003 ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
1005 /* Testing the buffer */
1006 test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,listener,0,0);
1009 /* Testing the reference counting */
1010 ref=IDirectSound3DListener_Release(listener);
1011 ok(ref==0,"IDirectSound3DListener_Release listener has %d references, should have 0\n",ref);
1014 /* Testing the reference counting */
1015 ref=IDirectSoundBuffer_Release(primary);
1016 ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
1020 ref=IDirectSound_Release(dso);
1021 ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
1023 return DSERR_GENERIC;
1028 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
1029 LPCSTR lpcstrModule, LPVOID lpContext)
1033 trace("Testing %s - %s\n",lpcstrDescription,lpcstrModule);
1034 rc=test_dsound(lpGuid);
1035 ok(rc==DS_OK,"DirectSound test failed\n");
1037 trace(" Testing the primary buffer\n");
1038 rc=test_primary(lpGuid);
1039 ok(rc==DS_OK,"Primary Buffer test failed\n");
1041 trace(" Testing 3D primary buffer\n");
1042 rc=test_primary_3d(lpGuid);
1043 ok(rc==DS_OK,"3D Primary Buffer test failed\n");
1045 trace(" Testing 3D primary buffer with listener\n");
1046 rc=test_primary_3d_with_listener(lpGuid);
1047 ok(rc==DS_OK,"3D Primary Buffer with listener test failed\n");
1049 /* Testing secondary buffers */
1050 test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0);
1051 test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0);
1053 /* Testing 3D secondary buffers */
1054 test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0);
1055 test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0);
1056 test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0);
1057 test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0);
1058 test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0);
1059 test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0);
1060 test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0);
1061 test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0);
1062 test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1);
1063 test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1);
1068 static void dsound_tests()
1071 rc=DirectSoundEnumerateA(&dsenum_callback,NULL);
1072 ok(rc==DS_OK,"DirectSoundEnumerate failed: %ld\n",rc);