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