Initialize and uninitialize COM properly.
[wine] / dlls / dsound / tests / dsound.c
1 /*
2  * Tests basic sound playback in DirectSound.
3  * In particular we test each standard Windows sound format to make sure
4  * we handle the sound card/driver quirks correctly.
5  *
6  * Part of this test involves playing test tones. But this only makes
7  * sense if someone is going to carefully listen to it, and would only
8  * bother everyone else.
9  * So this is only done if the test is being run in interactive mode.
10  *
11  * Copyright (c) 2002-2004 Francois Gouget
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27
28 #define NONAMELESSSTRUCT
29 #define NONAMELESSUNION
30 #include <windows.h>
31
32 #include <math.h>
33 #include <stdlib.h>
34
35 #include "wine/test.h"
36 #include "windef.h"
37 #include "wingdi.h"
38 #include "dsound.h"
39 #include "dxerr8.h"
40 #include "dsconf.h"
41
42 #include "dsound_test.h"
43
44 static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized,
45                               LPCGUID lpGuid)
46 {
47     HRESULT rc;
48     DSCAPS dscaps;
49     int ref;
50     IUnknown * unknown;
51     IDirectSound * ds;
52     IDirectSound8 * ds8;
53     DWORD speaker_config, new_speaker_config;
54
55     /* Try to Query for objects */
56     rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown);
57     ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IUnknown) failed: %s\n",
58        DXGetErrorString8(rc));
59     if (rc==DS_OK)
60         IDirectSound_Release(unknown);
61
62     rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds);
63     ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IDirectSound) failed: %s\n",
64        DXGetErrorString8(rc));
65     if (rc==DS_OK)
66         IDirectSound_Release(ds);
67
68     rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8);
69     ok(rc==E_NOINTERFACE,"IDirectSound_QueryInterface(IID_IDirectSound8) "
70        "should have failed: %s\n",DXGetErrorString8(rc));
71     if (rc==DS_OK)
72         IDirectSound8_Release(ds8);
73
74     if (initialized == FALSE) {
75         /* try unitialized object */
76         rc=IDirectSound_GetCaps(dso,0);
77         ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps(NULL) "
78            "should have returned DSERR_UNINITIALIZED, returned: %s\n",
79            DXGetErrorString8(rc));
80
81         rc=IDirectSound_GetCaps(dso,&dscaps);
82         ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps() "
83            "should have returned DSERR_UNINITIALIZED, returned: %s\n",
84            DXGetErrorString8(rc));
85
86         rc=IDirectSound_Compact(dso);
87         ok(rc==DSERR_UNINITIALIZED,"IDirectSound_Compact() "
88            "should have returned DSERR_UNINITIALIZED, returned: %s\n",
89            DXGetErrorString8(rc));
90
91         rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config);
92         ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetSpeakerConfig() "
93            "should have returned DSERR_UNINITIALIZED, returned: %s\n",
94            DXGetErrorString8(rc));
95
96         rc=IDirectSound_Initialize(dso,lpGuid);
97         ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
98            "IDirectSound_Initialize() failed: %s\n",DXGetErrorString8(rc));
99         if (rc==DSERR_NODRIVER) {
100             trace("  No Driver\n");
101             return;
102         } else if (rc==DSERR_ALLOCATED) {
103             trace("  Already Allocated\n");
104             return;
105         }
106     }
107
108     /* DSOUND: Error: Invalid caps buffer */
109     rc=IDirectSound_GetCaps(dso,0);
110     ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps(NULL) "
111        "should have returned DSERR_INVALIDPARAM, returned: %s\n",
112        DXGetErrorString8(rc));
113
114     ZeroMemory(&dscaps, sizeof(dscaps));
115
116     /* DSOUND: Error: Invalid caps buffer */
117     rc=IDirectSound_GetCaps(dso,&dscaps);
118     ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps() "
119        "should have returned DSERR_INVALIDPARAM, returned: %s\n",
120        DXGetErrorString8(rc));
121
122     dscaps.dwSize=sizeof(dscaps);
123
124     /* DSOUND: Running on a certified driver */
125     rc=IDirectSound_GetCaps(dso,&dscaps);
126     ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc));
127
128     rc=IDirectSound_Compact(dso);
129     ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound_Compact() failed: %s\n",
130        DXGetErrorString8(rc));
131
132     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
133     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
134        DXGetErrorString8(rc));
135
136     rc=IDirectSound_Compact(dso);
137     ok(rc==DS_OK,"IDirectSound_Compact() failed: %s\n",DXGetErrorString8(rc));
138
139     rc=IDirectSound_GetSpeakerConfig(dso,0);
140     ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetSpeakerConfig(NULL) "
141        "should have returned DSERR_INVALIDPARAM, returned: %s\n",
142        DXGetErrorString8(rc));
143
144     rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config);
145     ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %s\n",
146        DXGetErrorString8(rc));
147
148     speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO,
149                                         DSSPEAKER_GEOMETRY_WIDE);
150     rc=IDirectSound_SetSpeakerConfig(dso,speaker_config);
151     ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %s\n",
152        DXGetErrorString8(rc));
153     if (rc==DS_OK) {
154         rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config);
155         ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %s\n",
156            DXGetErrorString8(rc));
157         if (rc==DS_OK && speaker_config!=new_speaker_config)
158                trace("IDirectSound_GetSpeakerConfig() failed to set speaker "
159                "config: expected 0x%08lx, got 0x%08lx\n",
160                speaker_config,new_speaker_config);
161     }
162
163     ref=IDirectSound_Release(dso);
164     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
165 }
166
167 static void IDirectSound_tests()
168 {
169     HRESULT rc;
170     LPDIRECTSOUND dso=NULL;
171
172     trace("Testing IDirectSound\n");
173
174     /* try the COM class factory method of creation with no device specified */
175     rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
176                         &IID_IDirectSound, (void**)&dso);
177     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n",
178        DXGetErrorString8(rc));
179     if (dso)
180         IDirectSound_test(dso, FALSE, NULL);
181
182     /* try the COM class factory method of creation with default playback
183      * device specified */
184     rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
185                         &IID_IDirectSound, (void**)&dso);
186     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n",
187        DXGetErrorString8(rc));
188     if (dso)
189         IDirectSound_test(dso, FALSE, &DSDEVID_DefaultPlayback);
190
191     /* try the COM class factory method of creation with default voice
192      * playback device specified */
193     rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
194                         &IID_IDirectSound, (void**)&dso);
195     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n",
196        DXGetErrorString8(rc));
197     if (dso)
198         IDirectSound_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback);
199
200     /* try the COM class factory method of creation with a bad
201      * IID specified */
202     rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
203                         &CLSID_DirectSoundPrivate, (void**)&dso);
204     ok(rc==E_NOINTERFACE,
205        "CoCreateInstance(CLSID_DirectSound,CLSID_DirectSoundPrivate) "
206        "should have failed: %s\n",DXGetErrorString8(rc));
207
208     /* try the COM class factory method of creation with a bad
209      * GUID and IID specified */
210     rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER,
211                         &IID_IDirectSound, (void**)&dso);
212     ok(rc==REGDB_E_CLASSNOTREG,
213        "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound) "
214        "should have failed: %s\n",DXGetErrorString8(rc));
215
216     /* try with no device specified */
217     rc=DirectSoundCreate(NULL,&dso,NULL);
218     ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
219        "DirectSoundCreate(NULL) failed: %s\n",DXGetErrorString8(rc));
220     if (rc==S_OK && dso)
221         IDirectSound_test(dso, TRUE, NULL);
222
223     /* try with default playback device specified */
224     rc=DirectSoundCreate(&DSDEVID_DefaultPlayback,&dso,NULL);
225     ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
226        "DirectSoundCreate(DSDEVID_DefaultPlayback) failed: %s\n",
227        DXGetErrorString8(rc));
228     if (rc==DS_OK && dso)
229         IDirectSound_test(dso, TRUE, NULL);
230
231     /* try with default voice playback device specified */
232     rc=DirectSoundCreate(&DSDEVID_DefaultVoicePlayback,&dso,NULL);
233     ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
234        "DirectSoundCreate(DSDEVID_DefaultVoicePlayback) failed: %s\n",
235        DXGetErrorString8(rc));
236     if (rc==DS_OK && dso)
237         IDirectSound_test(dso, TRUE, NULL);
238
239     /* try with a bad device specified */
240     rc=DirectSoundCreate(&DSDEVID_DefaultVoiceCapture,&dso,NULL);
241     ok(rc==DSERR_NODRIVER,"DirectSoundCreate(DSDEVID_DefaultVoiceCapture) "
242        "should have failed: %s\n",DXGetErrorString8(rc));
243 }
244
245 static HRESULT test_dsound(LPGUID lpGuid)
246 {
247     HRESULT rc;
248     LPDIRECTSOUND dso=NULL;
249     int ref;
250
251     /* DSOUND: Error: Invalid interface buffer */
252     rc=DirectSoundCreate(lpGuid,0,NULL);
253     ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate() should have returned "
254        "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc));
255
256     /* Create the DirectSound object */
257     rc=DirectSoundCreate(lpGuid,&dso,NULL);
258     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
259        "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
260     if (rc!=DS_OK)
261         return rc;
262
263     /* Try the enumerated device */
264     IDirectSound_test(dso, TRUE, lpGuid);
265
266     /* Try the COM class factory method of creation with enumerated device */
267     rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
268                         &IID_IDirectSound, (void**)&dso);
269     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n",
270        DXGetErrorString8(rc));
271     if (dso)
272         IDirectSound_test(dso, FALSE, lpGuid);
273
274     /* Create a DirectSound object */
275     rc=DirectSoundCreate(lpGuid,&dso,NULL);
276     ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
277     if (rc==DS_OK) {
278         LPDIRECTSOUND dso1=NULL;
279
280         /* Create a second DirectSound object */
281         rc=DirectSoundCreate(lpGuid,&dso1,NULL);
282         ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
283         if (rc==DS_OK) {
284             /* Release the second DirectSound object */
285             ref=IDirectSound_Release(dso1);
286             ok(ref==0,"IDirectSound_Release() has %d references, should have "
287                "0\n",ref);
288             ok(dso!=dso1,"DirectSound objects should be unique: "
289                "dso=0x%08lx,dso1=0x%08lx\n",(DWORD)dso,(DWORD)dso1);
290         }
291
292         /* Release the first DirectSound object */
293         ref=IDirectSound_Release(dso);
294         ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",
295            ref);
296         if (ref!=0)
297             return DSERR_GENERIC;
298     } else
299         return rc;
300
301     /* Create a DirectSound object */
302     rc=DirectSoundCreate(lpGuid,&dso,NULL);
303     ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
304     if (rc==DS_OK) {
305         LPDIRECTSOUNDBUFFER secondary;
306         DSBUFFERDESC bufdesc;
307         WAVEFORMATEX wfx;
308
309         init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1);
310         ZeroMemory(&bufdesc, sizeof(bufdesc));
311         bufdesc.dwSize=sizeof(bufdesc);
312         bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D;
313         bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
314         bufdesc.lpwfxFormat=&wfx;
315         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
316         ok(rc==DS_OK && secondary!=NULL,
317            "IDirectSound_CreateSoundBuffer() failed to create a secondary "
318            "buffer %s\n",DXGetErrorString8(rc));
319         if (rc==DS_OK && secondary!=NULL) {
320             LPDIRECTSOUND3DBUFFER buffer3d;
321             rc=IDirectSound_QueryInterface(secondary, &IID_IDirectSound3DBuffer,
322                                            (void **)&buffer3d);
323             ok(rc==DS_OK && buffer3d!=NULL,"IDirectSound_QueryInterface() "
324                "failed:  %s\n",DXGetErrorString8(rc));
325             if (rc==DS_OK && buffer3d!=NULL) {
326                 ref=IDirectSound3DBuffer_AddRef(buffer3d);
327                 ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, "
328                    "should have 2\n",ref);
329             }
330             ref=IDirectSoundBuffer_AddRef(secondary);
331             ok(ref==2,"IDirectSoundBuffer_AddRef() has %d references, "
332                "should have 2\n",ref);
333         }
334         /* release with buffer */
335         ref=IDirectSound_Release(dso);
336         ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",
337            ref);
338         if (ref!=0)
339             return DSERR_GENERIC;
340     } else
341         return rc;
342
343     return DS_OK;
344 }
345
346 static HRESULT test_primary(LPGUID lpGuid)
347 {
348     HRESULT rc;
349     LPDIRECTSOUND dso=NULL;
350     LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL;
351     DSBUFFERDESC bufdesc;
352     DSCAPS dscaps;
353     WAVEFORMATEX wfx;
354     int ref;
355
356     /* Create the DirectSound object */
357     rc=DirectSoundCreate(lpGuid,&dso,NULL);
358     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
359        "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
360     if (rc!=DS_OK)
361         return rc;
362
363     /* Get the device capabilities */
364     ZeroMemory(&dscaps, sizeof(dscaps));
365     dscaps.dwSize=sizeof(dscaps);
366     rc=IDirectSound_GetCaps(dso,&dscaps);
367     ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc));
368     if (rc!=DS_OK)
369         goto EXIT;
370
371     /* DSOUND: Error: Invalid buffer description pointer */
372     rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL);
373     ok(rc==DSERR_INVALIDPARAM,
374        "IDirectSound_CreateSoundBuffer() should have failed: %s\n",
375        DXGetErrorString8(rc));
376
377     /* DSOUND: Error: Invalid buffer description pointer */
378     rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL);
379     ok(rc==DSERR_INVALIDPARAM && primary==0,
380        "IDirectSound_CreateSoundBuffer() should have failed: rc=%s,"
381        "dsbo=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary);
382
383     /* DSOUND: Error: Invalid buffer description pointer */
384     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,0,NULL);
385     ok(rc==DSERR_INVALIDPARAM && primary==0,
386        "IDirectSound_CreateSoundBuffer() should have failed: rc=%s,"
387        "dsbo=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary);
388
389     ZeroMemory(&bufdesc, sizeof(bufdesc));
390
391     /* DSOUND: Error: Invalid size */
392     /* DSOUND: Error: Invalid buffer description */
393     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
394     ok(rc==DSERR_INVALIDPARAM && primary==0,
395        "IDirectSound_CreateSoundBuffer() should have failed: rc=%s,"
396        "primary=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary);
397
398     /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
399     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
400     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
401     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
402        DXGetErrorString8(rc));
403     if (rc!=DS_OK)
404         goto EXIT;
405
406     /* Testing the primary buffer */
407     primary=NULL;
408     ZeroMemory(&bufdesc, sizeof(bufdesc));
409     bufdesc.dwSize=sizeof(bufdesc);
410     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
411     bufdesc.lpwfxFormat = &wfx;
412     init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2);
413     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
414     ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() should have "
415        "returned DSERR_INVALIDPARAM, returned: %s\n", DXGetErrorString8(rc));
416     if (rc==DS_OK && primary!=NULL)
417         IDirectSoundBuffer_Release(primary);
418
419     primary=NULL;
420     ZeroMemory(&bufdesc, sizeof(bufdesc));
421     bufdesc.dwSize=sizeof(bufdesc);
422     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
423     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
424     ok(rc==DS_OK && primary!=NULL,
425        "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: "
426        "%s\n",DXGetErrorString8(rc));
427     if (rc==DS_OK && primary!=NULL) {
428         LONG vol;
429
430         /* Try to create a second primary buffer */
431         /* DSOUND: Error: The primary buffer already exists.
432          * Any changes made to the buffer description will be ignored. */
433         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&second,NULL);
434         ok(rc==DS_OK && second==primary,
435            "IDirectSound_CreateSoundBuffer() should have returned original "
436            "primary buffer: %s\n",DXGetErrorString8(rc));
437         ref=IDirectSoundBuffer_Release(second);
438         ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, "
439            "should have 1\n",ref);
440
441         /* Try to duplicate a primary buffer */
442         /* DSOUND: Error: Can't duplicate primary buffers */
443         rc=IDirectSound_DuplicateSoundBuffer(dso,primary,&third);
444         /* rc=0x88780032 */
445         ok(rc!=DS_OK,"IDirectSound_DuplicateSoundBuffer() primary buffer "
446            "should have failed %s\n",DXGetErrorString8(rc));
447
448         rc=IDirectSoundBuffer_GetVolume(primary,&vol);
449         ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n",
450            DXGetErrorString8(rc));
451
452         if (winetest_interactive) {
453             trace("Playing a 5 seconds reference tone at the current "
454                   "volume.\n");
455             if (rc==DS_OK)
456                 trace("(the current volume is %ld according to DirectSound)\n",
457                       vol);
458             trace("All subsequent tones should be identical to this one.\n");
459             trace("Listen for stutter, changes in pitch, volume, etc.\n");
460         }
461         test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive &&
462                     !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0);
463
464         ref=IDirectSoundBuffer_Release(primary);
465         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
466            "should have 0\n",ref);
467     }
468
469     /* Set the CooperativeLevel back to normal */
470     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
471     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
472     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
473        DXGetErrorString8(rc));
474
475 EXIT:
476     ref=IDirectSound_Release(dso);
477     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
478     if (ref!=0)
479         return DSERR_GENERIC;
480
481     return rc;
482 }
483
484 /*
485  * Test the primary buffer at different formats while keeping the
486  * secondary buffer at a constant format.
487  */
488 static HRESULT test_primary_secondary(LPGUID lpGuid)
489 {
490     HRESULT rc;
491     LPDIRECTSOUND dso=NULL;
492     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
493     DSBUFFERDESC bufdesc;
494     DSCAPS dscaps;
495     WAVEFORMATEX wfx, wfx2;
496     int f,ref;
497
498     /* Create the DirectSound object */
499     rc=DirectSoundCreate(lpGuid,&dso,NULL);
500     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
501        "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
502     if (rc!=DS_OK)
503         return rc;
504
505     /* Get the device capabilities */
506     ZeroMemory(&dscaps, sizeof(dscaps));
507     dscaps.dwSize=sizeof(dscaps);
508     rc=IDirectSound_GetCaps(dso,&dscaps);
509     ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc));
510     if (rc!=DS_OK)
511         goto EXIT;
512
513     /* We must call SetCooperativeLevel before creating primary buffer */
514     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
515     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
516     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
517        DXGetErrorString8(rc));
518     if (rc!=DS_OK)
519         goto EXIT;
520
521     ZeroMemory(&bufdesc, sizeof(bufdesc));
522     bufdesc.dwSize=sizeof(bufdesc);
523     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
524     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
525     ok(rc==DS_OK && primary!=NULL,
526        "IDirectSound_CreateSoundBuffer() failed to create a primary buffer "
527        "%s\n",DXGetErrorString8(rc));
528
529     if (rc==DS_OK && primary!=NULL) {
530         for (f=0;f<NB_FORMATS;f++) {
531             /* We must call SetCooperativeLevel to be allowed to call
532              * SetFormat */
533             /* DSOUND: Setting DirectSound cooperative level to
534              * DSSCL_PRIORITY */
535             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
536             ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
537                DXGetErrorString8(rc));
538             if (rc!=DS_OK)
539                 goto EXIT;
540
541             init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
542                         formats[f][2]);
543             wfx2=wfx;
544             rc=IDirectSoundBuffer_SetFormat(primary,&wfx);
545             ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat() failed: %s\n",
546                DXGetErrorString8(rc));
547
548             /* There is no garantee that SetFormat will actually change the
549              * format to what we asked for. It depends on what the soundcard
550              * supports. So we must re-query the format.
551              */
552             rc=IDirectSoundBuffer_GetFormat(primary,&wfx,sizeof(wfx),NULL);
553             ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n",
554                DXGetErrorString8(rc));
555             if (rc==DS_OK &&
556                 (wfx.wFormatTag!=wfx2.wFormatTag ||
557                  wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
558                  wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
559                  wfx.nChannels!=wfx2.nChannels)) {
560                 trace("Requested primary format tag=0x%04x %ldx%dx%d "
561                       "avg.B/s=%ld align=%d\n",
562                       wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
563                       wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
564                 trace("Got tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
565                       wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
566                       wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
567             }
568
569             /* Set the CooperativeLevel back to normal */
570             /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
571             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
572             ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
573                DXGetErrorString8(rc));
574
575             init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
576
577             secondary=NULL;
578             ZeroMemory(&bufdesc, sizeof(bufdesc));
579             bufdesc.dwSize=sizeof(bufdesc);
580             bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
581             bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
582             bufdesc.lpwfxFormat=&wfx2;
583             if (winetest_interactive) {
584                 trace("  Testing a primary buffer at %ldx%dx%d with a "
585                       "secondary buffer at %ldx%dx%d\n",
586                       wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
587                       wfx2.nSamplesPerSec,wfx2.wBitsPerSample,wfx2.nChannels);
588             }
589             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
590             ok(rc==DS_OK && secondary!=NULL,
591                "IDirectSound_CreateSoundBuffer() failed to create a secondary "
592                "buffer %s\n",DXGetErrorString8(rc));
593
594             if (rc==DS_OK && secondary!=NULL) {
595                 test_buffer(dso,secondary,0,FALSE,0,FALSE,0,
596                             winetest_interactive,1.0,0,NULL,0,0);
597
598                 ref=IDirectSoundBuffer_Release(secondary);
599                 ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
600                    "should have 0\n",ref);
601             }
602         }
603
604         ref=IDirectSoundBuffer_Release(primary);
605         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
606            "should have 0\n",ref);
607     }
608
609     /* Set the CooperativeLevel back to normal */
610     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
611     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
612     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
613        DXGetErrorString8(rc));
614
615 EXIT:
616     ref=IDirectSound_Release(dso);
617     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
618     if (ref!=0)
619         return DSERR_GENERIC;
620
621     return rc;
622 }
623
624 static HRESULT test_secondary(LPGUID lpGuid)
625 {
626     HRESULT rc;
627     LPDIRECTSOUND dso=NULL;
628     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
629     DSBUFFERDESC bufdesc;
630     DSCAPS dscaps;
631     WAVEFORMATEX wfx;
632     DWORD f;
633     int ref;
634
635     /* Create the DirectSound object */
636     rc=DirectSoundCreate(lpGuid,&dso,NULL);
637     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
638        "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc));
639     if (rc!=DS_OK)
640         return rc;
641
642     /* Get the device capabilities */
643     ZeroMemory(&dscaps, sizeof(dscaps));
644     dscaps.dwSize=sizeof(dscaps);
645     rc=IDirectSound_GetCaps(dso,&dscaps);
646     ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc));
647     if (rc!=DS_OK)
648         goto EXIT;
649
650     /* We must call SetCooperativeLevel before creating primary buffer */
651     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
652     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
653     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
654        DXGetErrorString8(rc));
655     if (rc!=DS_OK)
656         goto EXIT;
657
658     ZeroMemory(&bufdesc, sizeof(bufdesc));
659     bufdesc.dwSize=sizeof(bufdesc);
660     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
661     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
662     ok(rc==DS_OK && primary!=NULL,
663        "IDirectSound_CreateSoundBuffer() failed to create a primary buffer "
664        "%s\n",DXGetErrorString8(rc));
665
666     if (rc==DS_OK && primary!=NULL) {
667         for (f=0;f<NB_FORMATS;f++) {
668             init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
669                         formats[f][2]);
670             secondary=NULL;
671             ZeroMemory(&bufdesc, sizeof(bufdesc));
672             bufdesc.dwSize=sizeof(bufdesc);
673             bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
674             bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
675             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
676             ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() "
677                "should have returned DSERR_INVALIDPARAM, returned: %s\n",
678                DXGetErrorString8(rc));
679             if (rc==DS_OK && secondary!=NULL)
680                 IDirectSoundBuffer_Release(secondary);
681
682             secondary=NULL;
683             ZeroMemory(&bufdesc, sizeof(bufdesc));
684             bufdesc.dwSize=sizeof(bufdesc);
685             bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
686             bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
687             bufdesc.lpwfxFormat=&wfx;
688             if (winetest_interactive) {
689                 trace("  Testing a secondary buffer at %ldx%dx%d\n",
690                       wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
691             }
692             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
693             ok(rc==DS_OK && secondary!=NULL,
694                "IDirectSound_CreateSoundBuffer() failed to create a secondary "
695                "buffer %s\n",DXGetErrorString8(rc));
696
697             if (rc==DS_OK && secondary!=NULL) {
698                 test_buffer(dso,secondary,0,FALSE,0,FALSE,0,
699                             winetest_interactive,1.0,0,NULL,0,0);
700
701                 ref=IDirectSoundBuffer_Release(secondary);
702                 ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
703                    "should have 0\n",ref);
704             }
705         }
706
707         ref=IDirectSoundBuffer_Release(primary);
708         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
709            "should have 0\n",ref);
710     }
711
712     /* Set the CooperativeLevel back to normal */
713     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
714     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
715     ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n",
716        DXGetErrorString8(rc));
717
718 EXIT:
719     ref=IDirectSound_Release(dso);
720     ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref);
721     if (ref!=0)
722         return DSERR_GENERIC;
723
724     return rc;
725 }
726
727 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
728                                    LPCSTR lpcstrModule, LPVOID lpContext)
729 {
730     HRESULT rc;
731     trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
732     rc = test_dsound(lpGuid);
733     if (rc == DSERR_NODRIVER)
734         trace("  No Driver\n");
735     else if (rc == DSERR_ALLOCATED)
736         trace("  Already In Use\n");
737     else {
738         test_primary(lpGuid);
739         test_primary_secondary(lpGuid);
740         test_secondary(lpGuid);
741     }
742
743     return 1;
744 }
745
746 static void dsound_tests()
747 {
748     HRESULT rc;
749     rc=DirectSoundEnumerateA(&dsenum_callback,NULL);
750     ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc));
751 }
752
753 START_TEST(dsound)
754 {
755     CoInitialize(NULL);
756
757     IDirectSound_tests();
758     dsound_tests();
759
760     CoUninitialize();
761 }