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