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