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