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