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