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