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