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