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