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