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