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