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