Release 1.6-rc2.
[wine/testsucceed.git] / dlls / dsound / tests / ds3d.c
blob0caa33db1d591074aa450f1cfc5dbe1e21272ba8
1 /*
2 * Tests the panning and 3D functions of DirectSound
4 * Part of this test involves playing test tones. But this only makes
5 * sense if someone is going to carefully listen to it, and would only
6 * bother everyone else.
7 * So this is only done if the test is being run in interactive mode.
9 * Copyright (c) 2002-2004 Francois Gouget
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <windows.h>
28 #include <math.h>
30 #include "wine/test.h"
31 #include "dsound.h"
32 #include "mmreg.h"
33 #include "ks.h"
34 #include "ksmedia.h"
35 #include "dsound_test.h"
37 #define PI 3.14159265358979323846
40 static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
41 static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*,
42 LPUNKNOWN)=NULL;
44 char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size, BOOL ieee)
46 int i;
47 int nb_samples;
48 char* buf;
49 char* b;
51 nb_samples=(int)(duration*wfx->nSamplesPerSec);
52 *size=nb_samples*wfx->nBlockAlign;
53 b=buf=HeapAlloc(GetProcessHeap(), 0, *size);
54 for (i=0;i<nb_samples;i++) {
55 double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
56 if (wfx->wBitsPerSample==8) {
57 unsigned char sample=127.5*(y+1.0);
58 *b++=sample;
59 if (wfx->nChannels==2)
60 *b++=sample;
61 } else if (wfx->wBitsPerSample == 16) {
62 signed short sample=32767.5*y-0.5;
63 b[0]=sample & 0xff;
64 b[1]=sample >> 8;
65 b+=2;
66 if (wfx->nChannels==2) {
67 b[0]=sample & 0xff;
68 b[1]=sample >> 8;
69 b+=2;
71 } else if (wfx->wBitsPerSample == 24) {
72 signed int sample=8388607.5*y-0.5;
73 b[0]=sample & 0xff;
74 b[1]=(sample >> 8)&0xff;
75 b[2]=sample >> 16;
76 b+=3;
77 if (wfx->nChannels==2) {
78 b[0]=sample & 0xff;
79 b[1]=(sample >> 8)&0xff;
80 b[2]=sample >> 16;
81 b+=3;
83 } else if (wfx->wBitsPerSample == 32) {
84 if (ieee) {
85 float *ptr = (float *) b;
86 *ptr = y;
88 ptr++;
89 b+=4;
91 if (wfx->nChannels==2) {
92 *ptr = y;
93 b+=4;
95 } else {
96 signed int sample=2147483647.5*y-0.5;
97 b[0]=sample & 0xff;
98 b[1]=(sample >> 8)&0xff;
99 b[2]=(sample >> 16)&0xff;
100 b[3]=sample >> 24;
101 b+=4;
102 if (wfx->nChannels==2) {
103 b[0]=sample & 0xff;
104 b[1]=(sample >> 8)&0xff;
105 b[2]=(sample >> 16)&0xff;
106 b[3]=sample >> 24;
107 b+=4;
112 return buf;
115 const char * getDSBCAPS(DWORD xmask) {
116 static struct {
117 DWORD mask;
118 const char *name;
119 } flags[] = {
120 #define FE(x) { x, #x },
121 FE(DSBCAPS_PRIMARYBUFFER)
122 FE(DSBCAPS_STATIC)
123 FE(DSBCAPS_LOCHARDWARE)
124 FE(DSBCAPS_LOCSOFTWARE)
125 FE(DSBCAPS_CTRL3D)
126 FE(DSBCAPS_CTRLFREQUENCY)
127 FE(DSBCAPS_CTRLPAN)
128 FE(DSBCAPS_CTRLVOLUME)
129 FE(DSBCAPS_CTRLPOSITIONNOTIFY)
130 FE(DSBCAPS_STICKYFOCUS)
131 FE(DSBCAPS_GLOBALFOCUS)
132 FE(DSBCAPS_GETCURRENTPOSITION2)
133 FE(DSBCAPS_MUTE3DATMAXDISTANCE)
134 #undef FE
136 static char buffer[512];
137 unsigned int i;
138 BOOL first = TRUE;
140 buffer[0] = 0;
142 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++) {
143 if ((flags[i].mask & xmask) == flags[i].mask) {
144 if (first)
145 first = FALSE;
146 else
147 strcat(buffer, "|");
148 strcat(buffer, flags[i].name);
152 return buffer;
155 HWND get_hwnd(void)
157 HWND hwnd=GetForegroundWindow();
158 if (!hwnd)
159 hwnd=GetDesktopWindow();
160 return hwnd;
163 void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth,
164 int channels)
166 wfx->wFormatTag=format;
167 wfx->nChannels=channels;
168 wfx->wBitsPerSample=depth;
169 wfx->nSamplesPerSec=rate;
170 wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
171 /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */
172 if (wfx->nBlockAlign==0)
174 /* align compressed formats to byte boundary */
175 wfx->nBlockAlign=1;
177 wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
178 wfx->cbSize=0;
181 typedef struct {
182 char* wave;
183 DWORD wave_len;
185 LPDIRECTSOUNDBUFFER dsbo;
186 LPWAVEFORMATEX wfx;
187 DWORD buffer_size;
188 DWORD written;
189 DWORD played;
190 DWORD offset;
191 } play_state_t;
193 static int buffer_refill(play_state_t* state, DWORD size)
195 LPVOID ptr1,ptr2;
196 DWORD len1,len2;
197 HRESULT rc;
199 if (size>state->wave_len-state->written)
200 size=state->wave_len-state->written;
202 /* some broken apps like Navyfield mistakenly pass NULL for a ppValue */
203 rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
204 &ptr1,NULL,&ptr2,&len2,0);
205 ok(rc==DSERR_INVALIDPARAM,"expected %08x got %08x\n",DSERR_INVALIDPARAM, rc);
206 rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
207 &ptr1,&len1,&ptr2,&len2,0);
208 ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
209 if (rc!=DS_OK)
210 return -1;
212 memcpy(ptr1,state->wave+state->written,len1);
213 state->written+=len1;
214 if (ptr2!=NULL) {
215 memcpy(ptr2,state->wave+state->written,len2);
216 state->written+=len2;
218 state->offset=state->written % state->buffer_size;
219 /* some apps blindly pass &ptr1 instead of ptr1 */
220 rc=IDirectSoundBuffer_Unlock(state->dsbo,&ptr1,len1,ptr2,len2);
221 ok(rc==DSERR_INVALIDPARAM, "IDDirectSoundBuffer_Unlock(): expected %08x got %08x, %p %p\n",DSERR_INVALIDPARAM, rc, &ptr1, ptr1);
222 rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
223 ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
224 if (rc!=DS_OK)
225 return -1;
226 return size;
229 static int buffer_silence(play_state_t* state, DWORD size)
231 LPVOID ptr1,ptr2;
232 DWORD len1,len2;
233 HRESULT rc;
234 BYTE s;
236 rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
237 &ptr1,&len1,&ptr2,&len2,0);
238 ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc);
239 if (rc!=DS_OK)
240 return -1;
242 s=(state->wfx->wBitsPerSample==8?0x80:0);
243 memset(ptr1,s,len1);
244 if (ptr2!=NULL) {
245 memset(ptr2,s,len2);
247 state->offset=(state->offset+size) % state->buffer_size;
248 rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
249 ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc);
250 if (rc!=DS_OK)
251 return -1;
252 return size;
255 static int buffer_service(play_state_t* state)
257 DWORD last_play_pos,play_pos,buf_free;
258 HRESULT rc;
260 rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL);
261 ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %08x\n", rc);
262 if (rc!=DS_OK) {
263 goto STOP;
266 /* Update the amount played */
267 last_play_pos=state->played % state->buffer_size;
268 if (play_pos<last_play_pos)
269 state->played+=state->buffer_size-last_play_pos+play_pos;
270 else
271 state->played+=play_pos-last_play_pos;
273 if (winetest_debug > 1)
274 trace("buf size=%d last_play_pos=%d play_pos=%d played=%d / %d\n",
275 state->buffer_size,last_play_pos,play_pos,state->played,
276 state->wave_len);
278 if (state->played>state->wave_len)
280 /* Everything has been played */
281 goto STOP;
284 /* Refill the buffer */
285 if (state->offset<=play_pos)
286 buf_free=play_pos-state->offset;
287 else
288 buf_free=state->buffer_size-state->offset+play_pos;
290 if (winetest_debug > 1)
291 trace("offset=%d free=%d written=%d / %d\n",
292 state->offset,buf_free,state->written,state->wave_len);
293 if (buf_free==0)
294 return 1;
296 if (state->written<state->wave_len)
298 int w=buffer_refill(state,buf_free);
299 if (w==-1)
300 goto STOP;
301 buf_free-=w;
302 if (state->written==state->wave_len && winetest_debug > 1)
303 trace("last sound byte at %d\n",
304 (state->written % state->buffer_size));
307 if (buf_free>0) {
308 /* Fill with silence */
309 if (winetest_debug > 1)
310 trace("writing %d bytes of silence\n",buf_free);
311 if (buffer_silence(state,buf_free)==-1)
312 goto STOP;
314 return 1;
316 STOP:
317 if (winetest_debug > 1)
318 trace("stopping playback\n");
319 rc=IDirectSoundBuffer_Stop(state->dsbo);
320 ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %08x\n", rc);
321 return 0;
324 void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER *dsbo,
325 BOOL is_primary, BOOL set_volume, LONG volume,
326 BOOL set_pan, LONG pan, BOOL play, double duration,
327 BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener,
328 BOOL move_listener, BOOL move_sound,
329 BOOL set_frequency, DWORD frequency)
331 HRESULT rc;
332 DSBCAPS dsbcaps;
333 WAVEFORMATEX wfx,wfx2;
334 DWORD size,status,freq;
335 BOOL ieee = FALSE;
336 int ref;
338 if (set_frequency) {
339 rc=IDirectSoundBuffer_SetFrequency(*dsbo,frequency);
340 ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL,
341 "IDirectSoundBuffer_SetFrequency() failed to set frequency %08x\n",rc);
342 if (rc!=DS_OK)
343 return;
346 /* DSOUND: Error: Invalid caps pointer */
347 rc=IDirectSoundBuffer_GetCaps(*dsbo,0);
348 ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
349 "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
351 ZeroMemory(&dsbcaps, sizeof(dsbcaps));
353 /* DSOUND: Error: Invalid caps pointer */
354 rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
355 ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have "
356 "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
358 dsbcaps.dwSize=sizeof(dsbcaps);
359 rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps);
360 ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
361 if (rc==DS_OK && winetest_debug > 1) {
362 trace(" Caps: flags=0x%08x size=%d\n",dsbcaps.dwFlags,
363 dsbcaps.dwBufferBytes);
366 /* Query the format size. */
367 size=0;
368 rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size);
369 ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have "
370 "returned the needed size: rc=%08x size=%d\n",rc,size);
372 ok(size == sizeof(WAVEFORMATEX) || size == sizeof(WAVEFORMATEXTENSIBLE),
373 "Expected a correct structure size, got %d\n", size);
375 if (size == sizeof(WAVEFORMATEX)) {
376 rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,size,NULL);
377 ieee = (wfx.wFormatTag == WAVE_FORMAT_IEEE_FLOAT);
379 else if (size == sizeof(WAVEFORMATEXTENSIBLE)) {
380 WAVEFORMATEXTENSIBLE wfxe;
381 rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL);
382 wfx = wfxe.Format;
383 ieee = IsEqualGUID(&wfxe.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
384 } else
385 return;
387 ok(rc==DS_OK,
388 "IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
389 if (rc==DS_OK && winetest_debug > 1) {
390 trace(" Format: %s tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
391 is_primary ? "Primary" : "Secondary",
392 wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
393 wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
396 /* DSOUND: Error: Invalid frequency buffer */
397 rc=IDirectSoundBuffer_GetFrequency(*dsbo,0);
398 ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have "
399 "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
401 /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */
402 rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq);
403 ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) ||
404 (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)),
405 "IDirectSoundBuffer_GetFrequency() failed: %08x\n",rc);
406 if (rc==DS_OK) {
407 DWORD f = set_frequency?frequency:wfx.nSamplesPerSec;
408 ok(freq==f,"The frequency returned by GetFrequency "
409 "%d does not match the format %d\n",freq,f);
412 /* DSOUND: Error: Invalid status pointer */
413 rc=IDirectSoundBuffer_GetStatus(*dsbo,0);
414 ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have "
415 "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
417 rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
418 ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
419 ok(status==0,"status=0x%x instead of 0\n",status);
421 if (is_primary) {
422 DSBCAPS new_dsbcaps;
423 /* We must call SetCooperativeLevel to be allowed to call SetFormat */
424 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
425 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
426 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
427 if (rc!=DS_OK)
428 return;
430 /* DSOUND: Error: Invalid format pointer */
431 rc=IDirectSoundBuffer_SetFormat(*dsbo,0);
432 ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have "
433 "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
435 init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
436 rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2);
437 ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n",
438 format_string(&wfx2), rc);
440 /* There is no guarantee that SetFormat will actually change the
441 * format to what we asked for. It depends on what the soundcard
442 * supports. So we must re-query the format.
444 rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL);
445 ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
446 if (rc==DS_OK &&
447 (wfx.wFormatTag!=wfx2.wFormatTag ||
448 wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
449 wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
450 wfx.nChannels!=wfx2.nChannels)) {
451 trace("Requested format tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
452 wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
453 wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
454 trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
455 wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
456 wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
459 ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps));
460 new_dsbcaps.dwSize = sizeof(new_dsbcaps);
461 rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps);
462 ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc);
463 if (rc==DS_OK && winetest_debug > 1) {
464 trace(" new Caps: flags=0x%08x size=%d\n",new_dsbcaps.dwFlags,
465 new_dsbcaps.dwBufferBytes);
468 /* Check for primary buffer size change */
469 ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes,
470 " buffer size changed after SetFormat() - "
471 "previous size was %u, current size is %u\n",
472 dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes);
473 dsbcaps.dwBufferBytes = new_dsbcaps.dwBufferBytes;
475 /* Check for primary buffer flags change */
476 ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags,
477 " flags changed after SetFormat() - "
478 "previous flags were %08x, current flags are %08x\n",
479 dsbcaps.dwFlags, new_dsbcaps.dwFlags);
481 /* Set the CooperativeLevel back to normal */
482 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
483 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
484 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc);
487 if (play) {
488 play_state_t state;
489 DS3DLISTENER listener_param;
490 LPDIRECTSOUND3DBUFFER buffer=NULL;
491 DS3DBUFFER buffer_param;
492 DWORD start_time,now;
493 LPVOID buffer1;
494 DWORD length1;
496 if (winetest_interactive) {
497 if (set_frequency)
498 trace(" Playing %g second 440Hz tone at %dx%dx%d with a "
499 "frequency of %d (%dHz)\n", duration,
500 wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels,
501 frequency, (440 * frequency) / wfx.nSamplesPerSec);
502 else
503 trace(" Playing %g second 440Hz tone at %dx%dx%d\n", duration,
504 wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels);
507 if (is_primary) {
508 /* We must call SetCooperativeLevel to be allowed to call Lock */
509 /* DSOUND: Setting DirectSound cooperative level to
510 * DSSCL_WRITEPRIMARY */
511 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),
512 DSSCL_WRITEPRIMARY);
513 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) "
514 "failed: %08x\n",rc);
515 if (rc!=DS_OK)
516 return;
518 if (buffer3d) {
519 LPDIRECTSOUNDBUFFER temp_buffer;
521 rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer,
522 (LPVOID *)&buffer);
523 ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
524 if (rc!=DS_OK)
525 return;
527 /* check the COM interface */
528 rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer,
529 (LPVOID *)&temp_buffer);
530 ok(rc==DS_OK && temp_buffer!=NULL,
531 "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
532 ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
533 temp_buffer,*dsbo);
534 ref=IDirectSoundBuffer_Release(temp_buffer);
535 ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
536 "should have 1\n",ref);
538 temp_buffer=NULL;
539 rc=IDirectSound3DBuffer_QueryInterface(*dsbo,
540 &IID_IDirectSoundBuffer,
541 (LPVOID *)&temp_buffer);
542 ok(rc==DS_OK && temp_buffer!=NULL,
543 "IDirectSound3DBuffer_QueryInterface() failed: %08x\n", rc);
544 ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n",
545 temp_buffer,*dsbo);
546 ref=IDirectSoundBuffer_Release(temp_buffer);
547 ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
548 "should have 1\n",ref);
550 ref=IDirectSoundBuffer_Release(*dsbo);
551 ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
552 "should have 0\n",ref);
554 rc=IDirectSound3DBuffer_QueryInterface(buffer,
555 &IID_IDirectSoundBuffer,
556 (LPVOID *)dsbo);
557 ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() "
558 "failed: %08x\n",rc);
560 /* DSOUND: Error: Invalid buffer */
561 rc=IDirectSound3DBuffer_GetAllParameters(buffer,0);
562 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
563 "failed: %08x\n",rc);
565 ZeroMemory(&buffer_param, sizeof(buffer_param));
567 /* DSOUND: Error: Invalid buffer */
568 rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
569 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() "
570 "failed: %08x\n",rc);
572 buffer_param.dwSize=sizeof(buffer_param);
573 rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
574 ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %08x\n", rc);
576 if (set_volume) {
577 if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
578 LONG val;
579 rc=IDirectSoundBuffer_GetVolume(*dsbo,&val);
580 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc);
582 rc=IDirectSoundBuffer_SetVolume(*dsbo,volume);
583 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %08x\n", rc);
584 } else {
585 /* DSOUND: Error: Buffer does not have CTRLVOLUME */
586 rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume);
587 ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() "
588 "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
592 if (set_pan) {
593 if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) {
594 LONG val;
595 rc=IDirectSoundBuffer_GetPan(*dsbo,&val);
596 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %08x\n", rc);
598 rc=IDirectSoundBuffer_SetPan(*dsbo,pan);
599 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %08x\n", rc);
600 } else {
601 /* DSOUND: Error: Buffer does not have CTRLPAN */
602 rc=IDirectSoundBuffer_GetPan(*dsbo,&pan);
603 ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() "
604 "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc);
608 /* try an offset past the end of the buffer */
609 rc = IDirectSoundBuffer_Lock(*dsbo, dsbcaps.dwBufferBytes, 0, &buffer1,
610 &length1, NULL, NULL,
611 DSBLOCK_ENTIREBUFFER);
612 ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
613 "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
615 /* try a size larger than the buffer */
616 rc = IDirectSoundBuffer_Lock(*dsbo, 0, dsbcaps.dwBufferBytes + 1,
617 &buffer1, &length1, NULL, NULL,
618 DSBLOCK_FROMWRITECURSOR);
619 ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have "
620 "returned DSERR_INVALIDPARAM, returned %08x\n", rc);
622 if (set_frequency)
623 state.wave=wave_generate_la(&wfx,(duration*frequency)/wfx.nSamplesPerSec,&state.wave_len,ieee);
624 else
625 state.wave=wave_generate_la(&wfx,duration,&state.wave_len,ieee);
627 state.dsbo=*dsbo;
628 state.wfx=&wfx;
629 state.buffer_size=dsbcaps.dwBufferBytes;
630 state.played=state.written=state.offset=0;
631 buffer_refill(&state,state.buffer_size);
633 rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING);
634 ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %08x\n", rc);
636 rc=IDirectSoundBuffer_GetStatus(*dsbo,&status);
637 ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc);
638 ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
639 "GetStatus: bad status: %x\n",status);
641 if (listener) {
642 ZeroMemory(&listener_param,sizeof(listener_param));
643 listener_param.dwSize=sizeof(listener_param);
644 rc=IDirectSound3DListener_GetAllParameters(listener,
645 &listener_param);
646 ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
647 "failed: %08x\n",rc);
648 if (move_listener) {
649 listener_param.vPosition.x = -5.0f;
650 listener_param.vVelocity.x = (float)(10.0/duration);
652 rc=IDirectSound3DListener_SetAllParameters(listener,
653 &listener_param,
654 DS3D_IMMEDIATE);
655 ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n", rc);
657 if (buffer3d) {
658 if (move_sound) {
659 buffer_param.vPosition.x = 100.0f;
660 buffer_param.vVelocity.x = (float)(-200.0/duration);
662 buffer_param.flMinDistance = 10;
663 rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param,
664 DS3D_IMMEDIATE);
665 ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
668 start_time=GetTickCount();
669 while (buffer_service(&state)) {
670 WaitForSingleObject(GetCurrentProcess(),TIME_SLICE);
671 now=GetTickCount();
672 if (listener && move_listener) {
673 listener_param.vPosition.x = (float)(-5.0+10.0*(now-start_time)/1000/duration);
674 if (winetest_debug>2)
675 trace("listener position=%g\n",listener_param.vPosition.x);
676 rc=IDirectSound3DListener_SetPosition(listener,
677 listener_param.vPosition.x,listener_param.vPosition.y,
678 listener_param.vPosition.z,DS3D_IMMEDIATE);
679 ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n",rc);
681 if (buffer3d && move_sound) {
682 buffer_param.vPosition.x = (float)(100-200.0*(now-start_time)/1000/duration);
683 if (winetest_debug>2)
684 trace("sound position=%g\n",buffer_param.vPosition.x);
685 rc=IDirectSound3DBuffer_SetPosition(buffer,
686 buffer_param.vPosition.x,buffer_param.vPosition.y,
687 buffer_param.vPosition.z,DS3D_IMMEDIATE);
688 ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc);
691 /* Check the sound duration was within 10% of the expected value */
692 now=GetTickCount();
693 ok(fabs(1000*duration-now+start_time)<=100*duration,
694 "The sound played for %d ms instead of %g ms\n",
695 now-start_time,1000*duration);
697 HeapFree(GetProcessHeap(), 0, state.wave);
698 if (is_primary) {
699 /* Set the CooperativeLevel back to normal */
700 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
701 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
702 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) "
703 "failed: %08x\n",rc);
705 if (buffer3d) {
706 ref=IDirectSound3DBuffer_Release(buffer);
707 ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, "
708 "should have 0\n",ref);
713 static HRESULT test_secondary(LPGUID lpGuid, int play,
714 int has_3d, int has_3dbuffer,
715 int has_listener, int has_duplicate,
716 int move_listener, int move_sound)
718 HRESULT rc;
719 LPDIRECTSOUND dso=NULL;
720 LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
721 LPDIRECTSOUND3DLISTENER listener=NULL;
722 DSBUFFERDESC bufdesc;
723 WAVEFORMATEX wfx, wfx1;
724 int ref;
726 /* Create the DirectSound object */
727 rc=pDirectSoundCreate(lpGuid,&dso,NULL);
728 ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
729 if (rc!=DS_OK)
730 return rc;
732 /* We must call SetCooperativeLevel before creating primary buffer */
733 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
734 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
735 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
736 if (rc!=DS_OK)
737 goto EXIT;
739 ZeroMemory(&bufdesc, sizeof(bufdesc));
740 bufdesc.dwSize=sizeof(bufdesc);
741 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
742 if (has_3d)
743 bufdesc.dwFlags|=DSBCAPS_CTRL3D;
744 else
745 bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
746 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
747 ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
748 "IDirectSound_CreateSoundBuffer() failed to create a %sprimary buffer: %08x\n",has_3d?"3D ":"", rc);
749 if (rc==DSERR_CONTROLUNAVAIL)
750 trace(" No Primary\n");
751 else if (rc==DS_OK && primary!=NULL) {
752 rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
753 ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
754 if (rc!=DS_OK)
755 goto EXIT1;
757 if (has_listener) {
758 rc=IDirectSoundBuffer_QueryInterface(primary,
759 &IID_IDirectSound3DListener,
760 (void **)&listener);
761 ok(rc==DS_OK && listener!=NULL,
762 "IDirectSoundBuffer_QueryInterface() failed to get a 3D listener: %08x\n",rc);
763 ref=IDirectSoundBuffer_Release(primary);
764 ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
765 "should have 0\n",ref);
766 if (rc==DS_OK && listener!=NULL) {
767 DS3DLISTENER listener_param;
768 ZeroMemory(&listener_param,sizeof(listener_param));
769 /* DSOUND: Error: Invalid buffer */
770 rc=IDirectSound3DListener_GetAllParameters(listener,0);
771 ok(rc==DSERR_INVALIDPARAM,
772 "IDirectSound3dListener_GetAllParameters() should have "
773 "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
775 /* DSOUND: Error: Invalid buffer */
776 rc=IDirectSound3DListener_GetAllParameters(listener,
777 &listener_param);
778 ok(rc==DSERR_INVALIDPARAM,
779 "IDirectSound3dListener_GetAllParameters() should have "
780 "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
782 listener_param.dwSize=sizeof(listener_param);
783 rc=IDirectSound3DListener_GetAllParameters(listener,
784 &listener_param);
785 ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() "
786 "failed: %08x\n",rc);
787 } else {
788 ok(listener==NULL, "IDirectSoundBuffer_QueryInterface() "
789 "failed but returned a listener anyway\n");
790 ok(rc!=DS_OK, "IDirectSoundBuffer_QueryInterface() succeeded "
791 "but returned a NULL listener\n");
792 if (listener) {
793 ref=IDirectSound3DListener_Release(listener);
794 ok(ref==0,"IDirectSound3dListener_Release() listener has "
795 "%d references, should have 0\n",ref);
797 goto EXIT2;
801 init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2);
802 secondary=NULL;
803 ZeroMemory(&bufdesc, sizeof(bufdesc));
804 bufdesc.dwSize=sizeof(bufdesc);
805 bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
806 if (has_3dbuffer)
807 bufdesc.dwFlags|=DSBCAPS_CTRL3D;
808 else
809 bufdesc.dwFlags|=
810 (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN);
811 bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
812 wfx.nBlockAlign);
813 bufdesc.lpwfxFormat=&wfx;
814 if (winetest_interactive) {
815 trace(" Testing a %s%ssecondary buffer %s%s%s%sat %dx%dx%d "
816 "with a primary buffer at %dx%dx%d\n",
817 has_3dbuffer?"3D ":"",
818 has_duplicate?"duplicated ":"",
819 listener!=NULL||move_sound?"with ":"",
820 move_listener?"moving ":"",
821 listener!=NULL?"listener ":"",
822 listener&&move_sound?"and moving sound ":move_sound?
823 "moving sound ":"",
824 wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
825 wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
827 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
828 ok((rc==DS_OK && secondary!=NULL) || broken(rc == DSERR_CONTROLUNAVAIL), /* vmware drivers on w2k */
829 "IDirectSound_CreateSoundBuffer() failed to create a %s%ssecondary buffer %s%s%s%sat %dx%dx%d (%s): %08x\n",
830 has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"",
831 listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"",
832 listener!=NULL?"listener ":"",
833 listener&&move_sound?"and moving sound ":move_sound?
834 "moving sound ":"",
835 wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
836 getDSBCAPS(bufdesc.dwFlags),rc);
837 if (rc==DS_OK && secondary!=NULL) {
838 IDirectSound3DBuffer *ds3d;
840 rc=IDirectSoundBuffer_QueryInterface(secondary, &IID_IDirectSound3DBuffer, (void**)&ds3d);
841 ok((has_3dbuffer && rc==DS_OK) || (!has_3dbuffer && rc==E_NOINTERFACE),
842 "Wrong return trying to get 3D buffer on %s3D secondary interface: %08x\n", has_3dbuffer ? "" : "non-", rc);
843 if(rc==DS_OK)
844 IDirectSound3DBuffer_Release(ds3d);
846 if (!has_3d) {
847 LONG refvol,vol,refpan,pan;
849 /* Check the initial secondary buffer's volume and pan */
850 rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
851 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: %08x\n",rc);
852 ok(vol==0,"wrong volume for a new secondary buffer: %d\n",vol);
853 rc=IDirectSoundBuffer_GetPan(secondary,&pan);
854 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: %08x\n",rc);
855 ok(pan==0,"wrong pan for a new secondary buffer: %d\n",pan);
857 /* Check that changing the secondary buffer's volume and pan
858 * does not impact the primary buffer's volume and pan
860 rc=IDirectSoundBuffer_GetVolume(primary,&refvol);
861 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc);
862 rc=IDirectSoundBuffer_GetPan(primary,&refpan);
863 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc);
865 rc=IDirectSoundBuffer_SetVolume(secondary,-1000);
866 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
867 rc=IDirectSoundBuffer_GetVolume(secondary,&vol);
868 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
869 ok(vol==-1000,"secondary: wrong volume %d instead of -1000\n",
870 vol);
871 rc=IDirectSoundBuffer_SetPan(secondary,-1000);
872 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
873 rc=IDirectSoundBuffer_GetPan(secondary,&pan);
874 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
875 ok(pan==-1000,"secondary: wrong pan %d instead of -1000\n",
876 pan);
878 rc=IDirectSoundBuffer_GetVolume(primary,&vol);
879 ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc);
880 ok(vol==refvol,"The primary volume changed from %d to %d\n",
881 refvol,vol);
882 rc=IDirectSoundBuffer_GetPan(primary,&pan);
883 ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc);
884 ok(pan==refpan,"The primary pan changed from %d to %d\n",
885 refpan,pan);
887 rc=IDirectSoundBuffer_SetVolume(secondary,0);
888 ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc);
889 rc=IDirectSoundBuffer_SetPan(secondary,0);
890 ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc);
892 if (has_duplicate) {
893 LPDIRECTSOUNDBUFFER duplicated=NULL;
895 /* DSOUND: Error: Invalid source buffer */
896 rc=IDirectSound_DuplicateSoundBuffer(dso,0,0);
897 ok(rc==DSERR_INVALIDPARAM,
898 "IDirectSound_DuplicateSoundBuffer() should have returned "
899 "DSERR_INVALIDPARAM, returned: %08x\n",rc);
901 /* DSOUND: Error: Invalid dest buffer */
902 rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0);
903 ok(rc==DSERR_INVALIDPARAM,
904 "IDirectSound_DuplicateSoundBuffer() should have returned "
905 "DSERR_INVALIDPARAM, returned: %08x\n",rc);
907 /* DSOUND: Error: Invalid source buffer */
908 rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated);
909 ok(rc==DSERR_INVALIDPARAM,
910 "IDirectSound_DuplicateSoundBuffer() should have returned "
911 "DSERR_INVALIDPARAM, returned: %08x\n",rc);
913 duplicated=NULL;
914 rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,
915 &duplicated);
916 ok(rc==DS_OK && duplicated!=NULL,
917 "IDirectSound_DuplicateSoundBuffer() failed to duplicate "
918 "a secondary buffer: %08x\n",rc);
920 if (rc==DS_OK && duplicated!=NULL) {
921 ref=IDirectSoundBuffer_Release(secondary);
922 ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d "
923 "references, should have 0\n",ref);
924 secondary=duplicated;
928 if (rc==DS_OK && secondary!=NULL) {
929 double duration;
930 duration=(move_listener || move_sound?4.0:1.0);
931 test_buffer(dso,&secondary,0,FALSE,0,FALSE,0,
932 winetest_interactive,duration,has_3dbuffer,
933 listener,move_listener,move_sound,FALSE,0);
934 ref=IDirectSoundBuffer_Release(secondary);
935 ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, "
936 "should have 0\n",has_duplicate?"duplicated":"secondary",
937 ref);
940 EXIT1:
941 if (has_listener) {
942 ref=IDirectSound3DListener_Release(listener);
943 ok(ref==0,"IDirectSound3dListener_Release() listener has %d "
944 "references, should have 0\n",ref);
945 } else {
946 ref=IDirectSoundBuffer_Release(primary);
947 ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
948 "should have 0\n",ref);
950 } else {
951 ok(primary==NULL,"IDirectSound_CreateSoundBuffer(primary) failed "
952 "but primary created anyway\n");
953 ok(rc!=DS_OK,"IDirectSound_CreateSoundBuffer(primary) succeeded "
954 "but primary not created\n");
955 if (primary) {
956 ref=IDirectSoundBuffer_Release(primary);
957 ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
958 "should have 0\n",ref);
961 EXIT2:
962 /* Set the CooperativeLevel back to normal */
963 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
964 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
965 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc);
967 EXIT:
968 ref=IDirectSound_Release(dso);
969 ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
970 if (ref!=0)
971 return DSERR_GENERIC;
973 return rc;
976 static HRESULT test_for_driver(LPGUID lpGuid)
978 HRESULT rc;
979 LPDIRECTSOUND dso=NULL;
980 int ref;
982 /* Create the DirectSound object */
983 rc=pDirectSoundCreate(lpGuid,&dso,NULL);
984 ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
985 "DirectSoundCreate() failed: %08x\n",rc);
986 if (rc!=DS_OK)
987 return rc;
989 ref=IDirectSound_Release(dso);
990 ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
991 if (ref!=0)
992 return DSERR_GENERIC;
994 return rc;
997 static HRESULT test_primary(LPGUID lpGuid)
999 HRESULT rc;
1000 LPDIRECTSOUND dso=NULL;
1001 LPDIRECTSOUNDBUFFER primary=NULL;
1002 DSBUFFERDESC bufdesc;
1003 DSCAPS dscaps;
1004 int ref, i;
1006 /* Create the DirectSound object */
1007 rc=pDirectSoundCreate(lpGuid,&dso,NULL);
1008 ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
1009 if (rc!=DS_OK)
1010 return rc;
1012 /* Get the device capabilities */
1013 ZeroMemory(&dscaps, sizeof(dscaps));
1014 dscaps.dwSize=sizeof(dscaps);
1015 rc=IDirectSound_GetCaps(dso,&dscaps);
1016 ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
1017 if (rc!=DS_OK)
1018 goto EXIT;
1020 /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
1021 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
1022 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
1023 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
1024 if (rc!=DS_OK)
1025 goto EXIT;
1027 /* Testing the primary buffer */
1028 primary=NULL;
1029 ZeroMemory(&bufdesc, sizeof(bufdesc));
1030 bufdesc.dwSize=sizeof(bufdesc);
1031 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN;
1032 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
1033 ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
1034 "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc);
1035 if (rc==DSERR_CONTROLUNAVAIL)
1036 trace(" No Primary\n");
1037 else if (rc==DS_OK && primary!=NULL) {
1038 test_buffer(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive &&
1039 !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0,
1040 FALSE,0);
1041 if (winetest_interactive) {
1042 LONG volume,pan;
1044 volume = DSBVOLUME_MAX;
1045 for (i = 0; i < 6; i++) {
1046 test_buffer(dso,&primary,1,TRUE,volume,TRUE,0,
1047 winetest_interactive &&
1048 !(dscaps.dwFlags & DSCAPS_EMULDRIVER),
1049 1.0,0,NULL,0,0,FALSE,0);
1050 volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40);
1053 pan = DSBPAN_LEFT;
1054 for (i = 0; i < 7; i++) {
1055 test_buffer(dso,&primary,1,TRUE,0,TRUE,pan,
1056 winetest_interactive &&
1057 !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,FALSE,0);
1058 pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6);
1061 ref=IDirectSoundBuffer_Release(primary);
1062 ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1063 "should have 0\n",ref);
1066 /* Set the CooperativeLevel back to normal */
1067 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
1068 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
1069 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc);
1071 EXIT:
1072 ref=IDirectSound_Release(dso);
1073 ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
1074 if (ref!=0)
1075 return DSERR_GENERIC;
1077 return rc;
1080 static HRESULT test_primary_3d(LPGUID lpGuid)
1082 HRESULT rc;
1083 LPDIRECTSOUND dso=NULL;
1084 LPDIRECTSOUNDBUFFER primary=NULL;
1085 DSBUFFERDESC bufdesc;
1086 DSCAPS dscaps;
1087 int ref;
1089 /* Create the DirectSound object */
1090 rc=pDirectSoundCreate(lpGuid,&dso,NULL);
1091 ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
1092 if (rc!=DS_OK)
1093 return rc;
1095 /* Get the device capabilities */
1096 ZeroMemory(&dscaps, sizeof(dscaps));
1097 dscaps.dwSize=sizeof(dscaps);
1098 rc=IDirectSound_GetCaps(dso,&dscaps);
1099 ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
1100 if (rc!=DS_OK)
1101 goto EXIT;
1103 /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
1104 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
1105 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
1106 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
1107 if (rc!=DS_OK)
1108 goto EXIT;
1110 primary=NULL;
1111 ZeroMemory(&bufdesc, sizeof(bufdesc));
1112 bufdesc.dwSize=sizeof(bufdesc);
1113 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
1114 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
1115 ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed "
1116 "to create a primary buffer: %08x\n",rc);
1117 if (rc==DS_OK && primary!=NULL) {
1118 ref=IDirectSoundBuffer_Release(primary);
1119 ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1120 "should have 0\n",ref);
1121 primary=NULL;
1122 ZeroMemory(&bufdesc, sizeof(bufdesc));
1123 bufdesc.dwSize=sizeof(bufdesc);
1124 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
1125 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
1126 ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() "
1127 "failed to create a 3D primary buffer: %08x\n",rc);
1128 if (rc==DS_OK && primary!=NULL) {
1129 test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive &&
1130 !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,
1131 FALSE,0);
1132 ref=IDirectSoundBuffer_Release(primary);
1133 ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1134 "should have 0\n",ref);
1137 /* Set the CooperativeLevel back to normal */
1138 /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
1139 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
1140 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc);
1142 EXIT:
1143 ref=IDirectSound_Release(dso);
1144 ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
1145 if (ref!=0)
1146 return DSERR_GENERIC;
1148 return rc;
1151 static HRESULT test_primary_3d_with_listener(LPGUID lpGuid)
1153 HRESULT rc;
1154 LPDIRECTSOUND dso=NULL;
1155 LPDIRECTSOUNDBUFFER primary=NULL;
1156 DSBUFFERDESC bufdesc;
1157 DSCAPS dscaps;
1158 int ref;
1160 /* Create the DirectSound object */
1161 rc=pDirectSoundCreate(lpGuid,&dso,NULL);
1162 ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc);
1163 if (rc!=DS_OK)
1164 return rc;
1166 /* Get the device capabilities */
1167 ZeroMemory(&dscaps, sizeof(dscaps));
1168 dscaps.dwSize=sizeof(dscaps);
1169 rc=IDirectSound_GetCaps(dso,&dscaps);
1170 ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc);
1171 if (rc!=DS_OK)
1172 goto EXIT;
1174 /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
1175 /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
1176 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
1177 ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc);
1178 if (rc!=DS_OK)
1179 goto EXIT;
1180 primary=NULL;
1181 ZeroMemory(&bufdesc, sizeof(bufdesc));
1182 bufdesc.dwSize=sizeof(bufdesc);
1183 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
1184 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
1185 ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed "
1186 "to create a 3D primary buffer: %08x\n",rc);
1187 if (rc==DS_OK && primary!=NULL) {
1188 LPDIRECTSOUND3DLISTENER listener=NULL;
1189 LPDIRECTSOUNDBUFFER temp_buffer=NULL;
1190 rc=IDirectSoundBuffer_QueryInterface(primary,
1191 &IID_IDirectSound3DListener,(void **)&listener);
1192 ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() "
1193 "failed to get a 3D listener: %08x\n",rc);
1194 if (rc==DS_OK && listener!=NULL) {
1195 /* Checking the COM interface */
1196 rc=IDirectSoundBuffer_QueryInterface(primary,
1197 &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
1198 ok(rc==DS_OK && temp_buffer!=NULL,
1199 "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
1200 ok(temp_buffer==primary,
1201 "COM interface broken: %p != %p\n",
1202 temp_buffer,primary);
1203 if (rc==DS_OK && temp_buffer!=NULL) {
1204 ref=IDirectSoundBuffer_Release(temp_buffer);
1205 ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
1206 "should have 1\n",ref);
1208 temp_buffer=NULL;
1209 rc=IDirectSound3DListener_QueryInterface(listener,
1210 &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
1211 ok(rc==DS_OK && temp_buffer!=NULL,
1212 "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc);
1213 ok(temp_buffer==primary,
1214 "COM interface broken: %p != %p\n",
1215 temp_buffer,primary);
1216 ref=IDirectSoundBuffer_Release(temp_buffer);
1217 ok(ref==1,"IDirectSoundBuffer_Release() has %d references, "
1218 "should have 1\n",ref);
1220 /* Testing the buffer */
1221 test_buffer(dso,&primary,1,FALSE,0,FALSE,0,
1222 winetest_interactive &&
1223 !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,
1224 listener,0,0,FALSE,0);
1226 temp_buffer = NULL;
1227 rc = IDirectSound3DListener_QueryInterface(listener, &IID_IKsPropertySet,
1228 (void **)&temp_buffer);
1229 ok(rc==DS_OK && temp_buffer!=NULL,
1230 "IDirectSound3DListener_QueryInterface didn't handle IKsPropertySet: ret = %08x\n", rc);
1231 if(temp_buffer)
1232 IKsPropertySet_Release(temp_buffer);
1235 /* Testing the reference counting */
1236 ref=IDirectSound3DListener_Release(listener);
1237 ok(ref==0,"IDirectSound3DListener_Release() listener has %d "
1238 "references, should have 0\n",ref);
1241 temp_buffer = NULL;
1242 rc = IDirectSoundBuffer_QueryInterface(primary, &IID_IKsPropertySet, (void **)&temp_buffer);
1243 ok(rc==DS_OK && temp_buffer!=NULL,
1244 "IDirectSoundBuffer_QueryInterface didn't handle IKsPropertySet on primary buffer: ret = %08x\n", rc);
1245 if(temp_buffer)
1246 IKsPropertySet_Release(temp_buffer);
1248 /* Testing the reference counting */
1249 ref=IDirectSoundBuffer_Release(primary);
1250 ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
1251 "should have 0\n",ref);
1254 EXIT:
1255 ref=IDirectSound_Release(dso);
1256 ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
1257 if (ref!=0)
1258 return DSERR_GENERIC;
1260 return rc;
1263 static unsigned driver_count = 0;
1265 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
1266 LPCSTR lpcstrModule, LPVOID lpContext)
1268 HRESULT rc;
1269 trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
1270 driver_count++;
1272 rc = test_for_driver(lpGuid);
1273 if (rc == DSERR_NODRIVER) {
1274 trace(" No Driver\n");
1275 return 1;
1276 } else if (rc == DSERR_ALLOCATED) {
1277 trace(" Already In Use\n");
1278 return 1;
1279 } else if (rc == E_FAIL) {
1280 trace(" No Device\n");
1281 return 1;
1284 trace(" Testing the primary buffer\n");
1285 test_primary(lpGuid);
1287 trace(" Testing 3D primary buffer\n");
1288 test_primary_3d(lpGuid);
1290 trace(" Testing 3D primary buffer with listener\n");
1291 test_primary_3d_with_listener(lpGuid);
1293 /* Testing secondary buffers */
1294 test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0);
1295 test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0);
1297 /* Testing 3D secondary buffers */
1298 test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0);
1299 test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0);
1300 test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0);
1301 test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0);
1302 test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0);
1303 test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0);
1304 test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0);
1305 test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0);
1306 test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1);
1307 test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1);
1309 return 1;
1312 static void ds3d_tests(void)
1314 HRESULT rc;
1315 rc=pDirectSoundEnumerateA(&dsenum_callback,NULL);
1316 ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc);
1317 trace("tested %u DirectSound drivers\n", driver_count);
1320 START_TEST(ds3d)
1322 HMODULE hDsound;
1324 CoInitialize(NULL);
1326 hDsound = LoadLibrary("dsound.dll");
1327 if (hDsound)
1330 pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound,
1331 "DirectSoundEnumerateA");
1332 pDirectSoundCreate = (void*)GetProcAddress(hDsound,
1333 "DirectSoundCreate");
1335 ds3d_tests();
1337 FreeLibrary(hDsound);
1339 else
1340 skip("dsound.dll not found - skipping all tests\n");
1342 CoUninitialize();