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