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