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