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