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 "dsound_test.h"
29 
30 #include <initguid.h>
31 #include <mmdeviceapi.h>
32 
33 static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
34 static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL;
35 
align(int length,int align)36 int align(int length, int align)
37 {
38     return (length / align) * align;
39 }
40 
IDirectSound8_test(LPDIRECTSOUND8 dso,BOOL initialized,LPCGUID lpGuid)41 static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized,
42                                LPCGUID lpGuid)
43 {
44     HRESULT rc;
45     DSCAPS dscaps;
46     int ref;
47     IUnknown * unknown;
48     IDirectSound * ds;
49     IDirectSound8 * ds8;
50     DWORD speaker_config, new_speaker_config, ref_speaker_config;
51     DWORD certified;
52 
53     /* Try to Query for objects */
54     rc=IDirectSound8_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown);
55     ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IUnknown) failed: %08x\n", rc);
56     if (rc==DS_OK)
57         IDirectSound8_Release(unknown);
58 
59     rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds);
60     ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound) failed: %08x\n", rc);
61     if (rc==DS_OK)
62         IDirectSound_Release(ds);
63 
64     rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8);
65     ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound8) "
66        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
67     if (rc==DS_OK)
68         IDirectSound8_Release(ds8);
69 
70     if (initialized == FALSE) {
71         /* try uninitialized object */
72         rc=IDirectSound8_GetCaps(dso,0);
73         ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps(NULL) "
74            "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
75 
76         rc=IDirectSound8_GetCaps(dso,&dscaps);
77         ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps() "
78            "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
79 
80         rc=IDirectSound8_Compact(dso);
81         ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_Compact() "
82            "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
83 
84         rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config);
85         ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetSpeakerConfig() "
86            "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
87 
88         rc=IDirectSound8_VerifyCertification(dso, &certified);
89         ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_VerifyCertification() "
90            "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
91 
92         rc=IDirectSound8_Initialize(dso,lpGuid);
93         ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
94            "IDirectSound8_Initialize() failed: %08x\n",rc);
95         if (rc==DSERR_NODRIVER) {
96             trace("  No Driver\n");
97             goto EXIT;
98         } else if (rc==E_FAIL) {
99             trace("  No Device\n");
100             goto EXIT;
101         } else if (rc==DSERR_ALLOCATED) {
102             trace("  Already In Use\n");
103             goto EXIT;
104         }
105     }
106 
107     rc=IDirectSound8_Initialize(dso,lpGuid);
108     ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound8_Initialize() "
109        "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc);
110 
111     /* DSOUND: Error: Invalid caps buffer */
112     rc=IDirectSound8_GetCaps(dso,0);
113     ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() "
114        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
115 
116     ZeroMemory(&dscaps, sizeof(dscaps));
117 
118     /* DSOUND: Error: Invalid caps buffer */
119     rc=IDirectSound8_GetCaps(dso,&dscaps);
120     ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() "
121        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
122 
123     dscaps.dwSize=sizeof(dscaps);
124 
125     /* DSOUND: Running on a certified driver */
126     rc=IDirectSound8_GetCaps(dso,&dscaps);
127     ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
128 
129     rc=IDirectSound8_Compact(dso);
130     ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound8_Compact() failed: %08x\n", rc);
131 
132     rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
133     ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
134 
135     rc=IDirectSound8_Compact(dso);
136     ok(rc==DS_OK,"IDirectSound8_Compact() failed: %08x\n",rc);
137 
138     rc=IDirectSound8_GetSpeakerConfig(dso,0);
139     ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetSpeakerConfig(NULL) "
140        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
141 
142     rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config);
143     ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc);
144     ref_speaker_config = speaker_config;
145 
146     speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO,
147                                         DSSPEAKER_GEOMETRY_WIDE);
148     if (speaker_config == ref_speaker_config)
149         speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO,
150                                             DSSPEAKER_GEOMETRY_NARROW);
151     if(rc==DS_OK) {
152         rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config);
153         ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %08x\n", rc);
154     }
155     if (rc==DS_OK) {
156         rc=IDirectSound8_GetSpeakerConfig(dso,&new_speaker_config);
157         ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc);
158         if (rc==DS_OK && speaker_config!=new_speaker_config)
159                trace("IDirectSound8_GetSpeakerConfig() failed to set speaker "
160                "config: expected 0x%08x, got 0x%08x\n",
161                speaker_config,new_speaker_config);
162         IDirectSound8_SetSpeakerConfig(dso,ref_speaker_config);
163     }
164 
165     rc=IDirectSound8_VerifyCertification(dso, &certified);
166     ok(rc==DS_OK||rc==E_NOTIMPL,"IDirectSound8_VerifyCertification() failed: %08x\n", rc);
167 
168 EXIT:
169     ref=IDirectSound8_Release(dso);
170     ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
171 }
172 
IDirectSound8_tests(void)173 static void IDirectSound8_tests(void)
174 {
175     HRESULT rc;
176     LPDIRECTSOUND8 dso=NULL;
177     LPCLASSFACTORY cf=NULL;
178 
179     trace("Testing IDirectSound8\n");
180 
181     rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL,
182                         &IID_IClassFactory, (void**)&cf);
183     ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IClassFactory) "
184        "failed: %08x\n", rc);
185 
186     rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL,
187                         &IID_IUnknown, (void**)&cf);
188     ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IUnknown) "
189        "failed: %08x\n", rc);
190 
191     /* try the COM class factory method of creation with no device specified */
192     rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
193                         &IID_IDirectSound8, (void**)&dso);
194     ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance() failed: %08x\n", rc);
195     if (rc==REGDB_E_CLASSNOTREG) {
196         trace("  Class Not Registered\n");
197         return;
198     }
199     if (dso)
200         IDirectSound8_test(dso, FALSE, NULL);
201 
202     /* try the COM class factory method of creation with default playback
203      *  device specified */
204     rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
205                         &IID_IDirectSound8, (void**)&dso);
206     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", rc);
207     if (dso)
208         IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultPlayback);
209 
210     /* try the COM class factory method of creation with default voice
211      * playback device specified */
212     rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
213                         &IID_IDirectSound8, (void**)&dso);
214     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", 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: %08x\n",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: %08x\n",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||rc==E_FAIL,
237        "DirectSoundCreate8() failed: %08x\n",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||rc==E_FAIL,
244        "DirectSoundCreate8() failed: %08x\n",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||rc==E_FAIL,
251        "DirectSoundCreate8() failed: %08x\n",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: %08x\n",rc);
259 }
260 
test_dsound8(LPGUID lpGuid)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: %08x\n",rc);
271 
272     /* Create the DirectSound8 object */
273     rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
274     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
275        "DirectSoundCreate8() failed: %08x\n",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: %08x\n", rc);
286     if (dso)
287         IDirectSound8_test(dso, FALSE, lpGuid);
288 
289     /* Create a DirectSound8 object */
290     rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
291     ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc);
292     if (rc==DS_OK) {
293         LPDIRECTSOUND8 dso1=NULL;
294 
295         /* Create a second DirectSound8 object */
296         rc=pDirectSoundCreate8(lpGuid,&dso1,NULL);
297         ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc);
298         if (rc==DS_OK) {
299             /* Release the second DirectSound8 object */
300             ref=IDirectSound8_Release(dso1);
301             ok(ref==0,"IDirectSound8_Release() has %d references, "
302                "should have 0\n",ref);
303             ok(dso!=dso1,"DirectSound8 objects should be unique: "
304                "dso=%p,dso1=%p\n",dso,dso1);
305         }
306 
307         /* Release the first DirectSound8 object */
308         ref=IDirectSound8_Release(dso);
309         ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",
310            ref);
311         if (ref!=0)
312             return DSERR_GENERIC;
313     } else
314         return rc;
315 
316     /* Create a DirectSound8 object */
317     rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
318     ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc);
319     if (rc==DS_OK) {
320         LPDIRECTSOUNDBUFFER secondary;
321         DSBUFFERDESC bufdesc;
322         WAVEFORMATEX wfx;
323 
324         init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1);
325         ZeroMemory(&bufdesc, sizeof(bufdesc));
326         bufdesc.dwSize=sizeof(bufdesc);
327         bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D;
328         bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
329                                     wfx.nBlockAlign);
330         bufdesc.lpwfxFormat=&wfx;
331         rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
332         ok(rc==DS_OK && secondary!=NULL,
333            "IDirectSound8_CreateSoundBuffer() failed to create a secondary "
334            "buffer: %08x\n",rc);
335         if (rc==DS_OK && secondary!=NULL) {
336             LPDIRECTSOUND3DBUFFER buffer3d;
337             LPDIRECTSOUNDBUFFER8 buffer8;
338             rc=IDirectSound8_QueryInterface(secondary,
339                                             &IID_IDirectSound3DBuffer,
340                                             (void **)&buffer3d);
341             ok(rc==DS_OK && buffer3d!=NULL,
342                "IDirectSound8_QueryInterface() failed: %08x\n", rc);
343             if (rc==DS_OK && buffer3d!=NULL) {
344                 ref=IDirectSound3DBuffer_AddRef(buffer3d);
345                 ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, "
346                    "should have 2\n",ref);
347             }
348             rc=IDirectSound8_QueryInterface(secondary,
349                                             &IID_IDirectSoundBuffer8,
350                                             (void **)&buffer8);
351             if (rc==DS_OK && buffer8!=NULL) {
352                 ok(buffer8==(IDirectSoundBuffer8*)secondary,
353                    "IDirectSoundBuffer8 iface different from IDirectSoundBuffer.\n");
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 
test_primary8(LPGUID lpGuid)374 static HRESULT test_primary8(LPGUID lpGuid)
375 {
376     HRESULT rc;
377     LPDIRECTSOUND8 dso=NULL;
378     LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL;
379     LPDIRECTSOUNDBUFFER8 pb8 = NULL;
380     DSBUFFERDESC bufdesc;
381     DSCAPS dscaps;
382     WAVEFORMATEX wfx;
383     int ref;
384 
385     /* Create the DirectSound object */
386     rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
387     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
388        "DirectSoundCreate8() failed: %08x\n",rc);
389     if (rc!=DS_OK)
390         return rc;
391 
392     /* Get the device capabilities */
393     ZeroMemory(&dscaps, sizeof(dscaps));
394     dscaps.dwSize=sizeof(dscaps);
395     rc=IDirectSound8_GetCaps(dso,&dscaps);
396     ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
397     if (rc!=DS_OK)
398         goto EXIT;
399 
400     /* DSOUND: Error: Invalid buffer description pointer */
401     rc=IDirectSound8_CreateSoundBuffer(dso,0,0,NULL);
402     ok(rc==DSERR_INVALIDPARAM,
403        "IDirectSound8_CreateSoundBuffer should have returned "
404        "DSERR_INVALIDPARAM, returned: %08x\n",rc);
405 
406     /* DSOUND: Error: Invalid buffer description pointer */
407     rc=IDirectSound8_CreateSoundBuffer(dso,0,&primary,NULL);
408     ok(rc==DSERR_INVALIDPARAM && primary==0,
409        "IDirectSound8_CreateSoundBuffer() should have returned "
410        "DSERR_INVALIDPARAM, returned: rc=%08x,dsbo=%p\n",
411        rc,primary);
412 
413     ZeroMemory(&bufdesc, sizeof(bufdesc));
414     bufdesc.dwSize = sizeof(DSBUFFERDESC);
415 
416     /* DSOUND: Error: Invalid dsound buffer interface pointer */
417     rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,0,NULL);
418     ok(rc==DSERR_INVALIDPARAM && primary==0,
419        "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x,"
420        "dsbo=%p\n",rc,primary);
421 
422     ZeroMemory(&bufdesc, sizeof(bufdesc));
423 
424     /* DSOUND: Error: Invalid size */
425     /* DSOUND: Error: Invalid buffer description */
426     rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
427     ok(rc==DSERR_INVALIDPARAM && primary==0,
428        "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x,"
429        "primary=%p\n",rc,primary);
430 
431     /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
432     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
433     rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
434     ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
435     if (rc!=DS_OK)
436         goto EXIT;
437 
438     /* Testing the primary buffer */
439     primary=NULL;
440     ZeroMemory(&bufdesc, sizeof(bufdesc));
441     bufdesc.dwSize=sizeof(bufdesc);
442     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
443     bufdesc.lpwfxFormat = &wfx;
444     init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2);
445     rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
446     ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() should have "
447        "returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
448     if (rc==DS_OK && primary!=NULL)
449         IDirectSoundBuffer_Release(primary);
450 
451     primary=NULL;
452     ZeroMemory(&bufdesc, sizeof(bufdesc));
453     bufdesc.dwSize=sizeof(bufdesc);
454     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME;
455     rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
456     ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL),
457        "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: "
458        "%08x\n",rc);
459     if (rc==DSERR_CONTROLUNAVAIL)
460         trace("  No Primary\n");
461     else if (rc==DS_OK && primary!=NULL) {
462         LONG vol;
463 
464         /* Try to create a second primary buffer */
465         /* DSOUND: Error: The primary buffer already exists.
466          * Any changes made to the buffer description will be ignored. */
467         rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&second,NULL);
468         ok(rc==DS_OK && second==primary,
469            "IDirectSound8_CreateSoundBuffer() should have returned original "
470            "primary buffer: %08x\n",rc);
471         ref=IDirectSoundBuffer_Release(second);
472         ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, "
473            "should have 1\n",ref);
474 
475         /* Try to duplicate a primary buffer */
476         /* DSOUND: Error: Can't duplicate primary buffers */
477         rc=IDirectSound8_DuplicateSoundBuffer(dso,primary,&third);
478         /* rc=0x88780032 */
479         ok(rc!=DS_OK,"IDirectSound8_DuplicateSoundBuffer() primary buffer "
480            "should have failed %08x\n",rc);
481 
482         /* Primary buffers don't have an IDirectSoundBuffer8 */
483         rc = IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer8, (LPVOID*)&pb8);
484         ok(FAILED(rc), "Primary buffer does have an IDirectSoundBuffer8: %08x\n", rc);
485 
486         rc=IDirectSoundBuffer_GetVolume(primary,&vol);
487         ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc);
488 
489         if (winetest_interactive) {
490             trace("Playing a 5 seconds reference tone at the current volume.\n");
491             if (rc==DS_OK)
492                 trace("(the current volume is %d according to DirectSound)\n",
493                       vol);
494             trace("All subsequent tones should be identical to this one.\n");
495             trace("Listen for stutter, changes in pitch, volume, etc.\n");
496         }
497         test_buffer8(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive &&
498                      !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0);
499 
500         ref=IDirectSoundBuffer_Release(primary);
501         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
502            "should have 0\n",ref);
503     }
504 
505     /* Set the CooperativeLevel back to normal */
506     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
507     rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
508     ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
509 
510 EXIT:
511     ref=IDirectSound8_Release(dso);
512     ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
513     if (ref!=0)
514         return DSERR_GENERIC;
515 
516     return rc;
517 }
518 
519 /*
520  * Test the primary buffer at different formats while keeping the
521  * secondary buffer at a constant format.
522  */
test_primary_secondary8(LPGUID lpGuid)523 static HRESULT test_primary_secondary8(LPGUID lpGuid)
524 {
525     HRESULT rc;
526     LPDIRECTSOUND8 dso=NULL;
527     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
528     DSBUFFERDESC bufdesc;
529     DSCAPS dscaps;
530     WAVEFORMATEX wfx, wfx2;
531     int ref;
532     unsigned int f, tag;
533 
534     /* Create the DirectSound object */
535     rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
536     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
537        "DirectSoundCreate8() failed: %08x\n",rc);
538     if (rc!=DS_OK)
539         return rc;
540 
541     /* Get the device capabilities */
542     ZeroMemory(&dscaps, sizeof(dscaps));
543     dscaps.dwSize=sizeof(dscaps);
544     rc=IDirectSound8_GetCaps(dso,&dscaps);
545     ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
546     if (rc!=DS_OK)
547         goto EXIT;
548 
549     /* We must call SetCooperativeLevel before creating primary buffer */
550     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
551     rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
552     ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
553     if (rc!=DS_OK)
554         goto EXIT;
555 
556     ZeroMemory(&bufdesc, sizeof(bufdesc));
557     bufdesc.dwSize=sizeof(bufdesc);
558     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
559     rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
560     ok(rc==DS_OK && primary!=NULL,
561        "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer "
562        "%08x\n",rc);
563 
564     if (rc==DS_OK && primary!=NULL) {
565         for (f=0;f<NB_FORMATS;f++) {
566           for (tag=0;tag<NB_TAGS;tag++) {
567             /* if float, we only want to test 32-bit */
568             if ((format_tags[tag] == WAVE_FORMAT_IEEE_FLOAT) && (formats[f][1] != 32))
569                 continue;
570 
571             /* We must call SetCooperativeLevel to be allowed to call
572              * SetFormat */
573             /* DSOUND: Setting DirectSound cooperative level to
574              * DSSCL_PRIORITY */
575             rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
576             ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
577             if (rc!=DS_OK)
578                 goto EXIT;
579 
580             init_format(&wfx,format_tags[tag],formats[f][0],formats[f][1],
581                         formats[f][2]);
582             wfx2=wfx;
583             rc=IDirectSoundBuffer_SetFormat(primary,&wfx);
584             ok(rc==DS_OK
585                || rc==DSERR_INVALIDPARAM, /* 2003 */
586                "IDirectSoundBuffer_SetFormat(%s) failed: %08x\n",
587                format_string(&wfx), rc);
588 
589             /* There is no guarantee that SetFormat will actually change the
590              * format to what we asked for. It depends on what the soundcard
591              * supports. So we must re-query the format.
592              */
593             rc=IDirectSoundBuffer_GetFormat(primary,&wfx,sizeof(wfx),NULL);
594             ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc);
595             if (rc==DS_OK &&
596                 (wfx.wFormatTag!=wfx2.wFormatTag ||
597                  wfx.nSamplesPerSec!=wfx2.nSamplesPerSec ||
598                  wfx.wBitsPerSample!=wfx2.wBitsPerSample ||
599                  wfx.nChannels!=wfx2.nChannels)) {
600                 trace("Requested primary format tag=0x%04x %dx%dx%d "
601                       "avg.B/s=%d align=%d\n",
602                       wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample,
603                       wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign);
604                 trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
605                       wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
606                       wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
607             }
608 
609             /* Set the CooperativeLevel back to normal */
610             /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
611             rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
612             ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
613 
614             init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2);
615 
616             secondary=NULL;
617             ZeroMemory(&bufdesc, sizeof(bufdesc));
618             bufdesc.dwSize=sizeof(bufdesc);
619             bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
620             bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
621                                         wfx.nBlockAlign);
622             bufdesc.lpwfxFormat=&wfx2;
623             if (winetest_interactive) {
624                 trace("  Testing a primary buffer at %dx%dx%d (fmt=%d) with a "
625                       "secondary buffer at %dx%dx%d\n",
626                       wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,format_tags[tag],
627                       wfx2.nSamplesPerSec,wfx2.wBitsPerSample,wfx2.nChannels);
628             }
629             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
630             ok(rc==DS_OK && secondary!=NULL,
631                "IDirectSound_CreateSoundBuffer() failed to create a secondary "
632                "buffer %08x\n",rc);
633 
634             if (rc==DS_OK && secondary!=NULL) {
635                 test_buffer8(dso,&secondary,0,FALSE,0,FALSE,0,
636                              winetest_interactive,1.0,0,NULL,0,0);
637 
638                 ref=IDirectSoundBuffer_Release(secondary);
639                 ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
640                    "should have 0\n",ref);
641             }
642           }
643         }
644 
645         ref=IDirectSoundBuffer_Release(primary);
646         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
647            "should have 0\n",ref);
648     }
649 
650     /* Set the CooperativeLevel back to normal */
651     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
652     rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
653     ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
654 
655 EXIT:
656     ref=IDirectSound8_Release(dso);
657     ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
658     if (ref!=0)
659         return DSERR_GENERIC;
660 
661     return rc;
662 }
663 
test_secondary8(LPGUID lpGuid)664 static HRESULT test_secondary8(LPGUID lpGuid)
665 {
666     HRESULT rc;
667     LPDIRECTSOUND8 dso=NULL;
668     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
669     DSBUFFERDESC bufdesc;
670     DSCAPS dscaps;
671     WAVEFORMATEX wfx, wfx1;
672     DWORD f, tag;
673     int ref;
674 
675     /* Create the DirectSound object */
676     rc=pDirectSoundCreate8(lpGuid,&dso,NULL);
677     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED,
678        "DirectSoundCreate8() failed: %08x\n",rc);
679     if (rc!=DS_OK)
680         return rc;
681 
682     /* Get the device capabilities */
683     ZeroMemory(&dscaps, sizeof(dscaps));
684     dscaps.dwSize=sizeof(dscaps);
685     rc=IDirectSound8_GetCaps(dso,&dscaps);
686     ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc);
687     if (rc!=DS_OK)
688         goto EXIT;
689 
690     /* We must call SetCooperativeLevel before creating primary buffer */
691     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
692     rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
693     ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
694     if (rc!=DS_OK)
695         goto EXIT;
696 
697     ZeroMemory(&bufdesc, sizeof(bufdesc));
698     bufdesc.dwSize=sizeof(bufdesc);
699     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
700     rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
701     ok(rc==DS_OK && primary!=NULL,
702        "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer "
703        "%08x\n",rc);
704 
705     if (rc==DS_OK && primary!=NULL) {
706         rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL);
707         ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc);
708         if (rc!=DS_OK)
709             goto EXIT1;
710 
711         for (f=0;f<NB_FORMATS;f++) {
712           for (tag=0;tag<NB_TAGS;tag++) {
713             WAVEFORMATEXTENSIBLE wfxe;
714 
715             /* if float, we only want to test 32-bit */
716             if ((format_tags[tag] == WAVE_FORMAT_IEEE_FLOAT) && (formats[f][1] != 32))
717                 continue;
718 
719             init_format(&wfx,format_tags[tag],formats[f][0],formats[f][1],
720                         formats[f][2]);
721             secondary=NULL;
722             ZeroMemory(&bufdesc, sizeof(bufdesc));
723             bufdesc.dwSize=sizeof(bufdesc);
724             bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
725             bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
726                                         wfx.nBlockAlign);
727             rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
728             ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() "
729                "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
730             if (rc==DS_OK && secondary!=NULL)
731                 IDirectSoundBuffer_Release(secondary);
732 
733             secondary=NULL;
734             ZeroMemory(&bufdesc, sizeof(bufdesc));
735             bufdesc.dwSize=sizeof(bufdesc);
736             bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2;
737             bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000,
738                                         wfx.nBlockAlign);
739             bufdesc.lpwfxFormat=&wfx;
740             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
741             if (wfx.wBitsPerSample != 8 && wfx.wBitsPerSample != 16)
742                 ok(((rc == DSERR_CONTROLUNAVAIL || rc == DSERR_INVALIDCALL || rc == DSERR_INVALIDPARAM /* 2003 */) && !secondary)
743                     || rc == DS_OK, /* driver dependent? */
744                     "IDirectSound_CreateSoundBuffer() "
745                     "should have returned (DSERR_CONTROLUNAVAIL or DSERR_INVALIDCALL) "
746                     "and NULL, returned: %08x %p\n", rc, secondary);
747             else
748                 ok(rc==DS_OK && secondary!=NULL,
749                     "IDirectSound_CreateSoundBuffer() failed to create a secondary "
750                     "buffer %08x\n",rc);
751             if (secondary)
752                 IDirectSoundBuffer_Release(secondary);
753             secondary = NULL;
754 
755             bufdesc.lpwfxFormat=(WAVEFORMATEX*)&wfxe;
756             wfxe.Format = wfx;
757             wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
758             wfxe.SubFormat = (format_tags[tag] == WAVE_FORMAT_PCM ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
759             wfxe.Format.cbSize = 1;
760             wfxe.Samples.wValidBitsPerSample = wfx.wBitsPerSample;
761             wfxe.dwChannelMask = (wfx.nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO);
762 
763             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
764             ok(rc==DSERR_INVALIDPARAM && !secondary,
765                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
766                 rc, secondary);
767             if (secondary)
768             {
769                 IDirectSoundBuffer_Release(secondary);
770                 secondary=NULL;
771             }
772 
773             wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx) + 1;
774 
775             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
776             ok(((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL /* 2003 */) && !secondary)
777                 || rc==DS_OK /* driver dependent? */,
778                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
779                 rc, secondary);
780             if (secondary)
781             {
782                 IDirectSoundBuffer_Release(secondary);
783                 secondary=NULL;
784             }
785 
786             wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx);
787             wfxe.SubFormat = GUID_NULL;
788             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
789             ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL) && !secondary,
790                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
791                 rc, secondary);
792             if (secondary)
793             {
794                 IDirectSoundBuffer_Release(secondary);
795                 secondary=NULL;
796             }
797 
798             wfxe.Format.cbSize = sizeof(wfxe);
799             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
800             ok((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL || rc==E_INVALIDARG) && !secondary,
801                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
802                 rc, secondary);
803             if (secondary)
804             {
805                 IDirectSoundBuffer_Release(secondary);
806                 secondary=NULL;
807             }
808 
809             wfxe.SubFormat = (format_tags[tag] == WAVE_FORMAT_PCM ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
810             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
811             ok(rc==DS_OK && secondary,
812                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
813                 rc, secondary);
814             if (secondary)
815             {
816                 IDirectSoundBuffer_Release(secondary);
817                 secondary=NULL;
818             }
819 
820             wfxe.Format.cbSize = sizeof(wfxe) + 1;
821             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
822             ok(((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL /* 2003 */) && !secondary)
823                 || rc==DS_OK /* driver dependent? */,
824                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
825                 rc, secondary);
826             if (secondary)
827             {
828                 IDirectSoundBuffer_Release(secondary);
829                 secondary=NULL;
830             }
831 
832             wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx);
833             ++wfxe.Samples.wValidBitsPerSample;
834             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
835             ok(rc==DSERR_INVALIDPARAM && !secondary,
836                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
837                 rc, secondary);
838             if (secondary)
839             {
840                 IDirectSoundBuffer_Release(secondary);
841                 secondary=NULL;
842             }
843             --wfxe.Samples.wValidBitsPerSample;
844 
845             wfxe.Samples.wValidBitsPerSample = 0;
846             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
847             ok(rc==DS_OK && secondary,
848                 "IDirectSound_CreateSoundBuffer() returned: %08x %p\n",
849                 rc, secondary);
850             if (secondary)
851             {
852                 IDirectSoundBuffer_Release(secondary);
853                 secondary=NULL;
854             }
855             wfxe.Samples.wValidBitsPerSample = wfxe.Format.wBitsPerSample;
856 
857             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
858             ok(rc==DS_OK && secondary!=NULL,
859                 "IDirectSound_CreateSoundBuffer() failed to create a secondary "
860                 "buffer %08x\n",rc);
861 
862             if (rc==DS_OK && secondary!=NULL) {
863                 if (winetest_interactive) {
864                     trace("  Testing a secondary buffer at %dx%dx%d (fmt=%d) "
865                         "with a primary buffer at %dx%dx%d\n",
866                         wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,format_tags[tag],
867                         wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels);
868                 }
869                 test_buffer8(dso,&secondary,0,FALSE,0,FALSE,0,
870                              winetest_interactive,1.0,0,NULL,0,0);
871 
872                 ref=IDirectSoundBuffer_Release(secondary);
873                 ok(ref==0,"IDirectSoundBuffer_Release() has %d references, "
874                    "should have 0\n",ref);
875             }
876           }
877         }
878 EXIT1:
879         ref=IDirectSoundBuffer_Release(primary);
880         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
881            "should have 0\n",ref);
882     }
883 
884     /* Set the CooperativeLevel back to normal */
885     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
886     rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
887     ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc);
888 
889 EXIT:
890     ref=IDirectSound8_Release(dso);
891     ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref);
892     if (ref!=0)
893         return DSERR_GENERIC;
894 
895     return rc;
896 }
897 
dsenum_callback(LPGUID lpGuid,LPCSTR lpcstrDescription,LPCSTR lpcstrModule,LPVOID lpContext)898 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
899                                    LPCSTR lpcstrModule, LPVOID lpContext)
900 {
901     HRESULT rc;
902     trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
903     rc = test_dsound8(lpGuid);
904     if (rc == DSERR_NODRIVER)
905         trace("  No Driver\n");
906     else if (rc == DSERR_ALLOCATED)
907         trace("  Already In Use\n");
908     else if (rc == E_FAIL)
909         trace("  No Device\n");
910     else {
911         test_primary8(lpGuid);
912         test_primary_secondary8(lpGuid);
913         test_secondary8(lpGuid);
914     }
915 
916     return 1;
917 }
918 
dsound8_tests(void)919 static void dsound8_tests(void)
920 {
921     HRESULT rc;
922     rc=pDirectSoundEnumerateA(&dsenum_callback,NULL);
923     ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc);
924 }
925 
test_hw_buffers(void)926 static void test_hw_buffers(void)
927 {
928     IDirectSound8 *ds;
929     IDirectSoundBuffer *primary, *primary2, **secondaries, *secondary;
930     IDirectSoundBuffer8 *buf8;
931     DSCAPS caps;
932     DSBCAPS bufcaps;
933     DSBUFFERDESC bufdesc;
934     WAVEFORMATEX fmt;
935     UINT i;
936     HRESULT hr;
937 
938     hr = pDirectSoundCreate8(NULL, &ds, NULL);
939     ok(hr == S_OK || hr == DSERR_NODRIVER || hr == DSERR_ALLOCATED || hr == E_FAIL,
940             "DirectSoundCreate8 failed: %08x\n", hr);
941     if(hr != S_OK)
942         return;
943 
944     caps.dwSize = sizeof(caps);
945 
946     hr = IDirectSound8_GetCaps(ds, &caps);
947     ok(hr == S_OK, "GetCaps failed: %08x\n", hr);
948 
949     ok(caps.dwPrimaryBuffers == 1, "Got wrong number of primary buffers: %u\n",
950             caps.dwPrimaryBuffers);
951 
952     /* DSBCAPS_LOC* is ignored for primary buffers */
953     bufdesc.dwSize = sizeof(bufdesc);
954     bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE |
955         DSBCAPS_PRIMARYBUFFER;
956     bufdesc.dwBufferBytes = 0;
957     bufdesc.dwReserved = 0;
958     bufdesc.lpwfxFormat = NULL;
959     bufdesc.guid3DAlgorithm = GUID_NULL;
960 
961     hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &primary, NULL);
962     ok(hr == S_OK, "CreateSoundBuffer failed: %08x\n", hr);
963     if(hr != S_OK){
964         IDirectSound8_Release(ds);
965         return;
966     }
967 
968     bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE |
969         DSBCAPS_PRIMARYBUFFER;
970 
971     hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &primary2, NULL);
972     ok(hr == S_OK, "CreateSoundBuffer failed: %08x\n", hr);
973     ok(primary == primary2, "Got different primary buffers: %p, %p\n", primary, primary2);
974     if(hr == S_OK)
975         IDirectSoundBuffer_Release(primary2);
976 
977     buf8 = (IDirectSoundBuffer8 *)0xDEADBEEF;
978     hr = IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer8,
979             (void**)&buf8);
980     ok(hr == E_NOINTERFACE, "QueryInterface gave wrong failure: %08x\n", hr);
981     ok(buf8 == NULL, "Pointer didn't get set to NULL\n");
982 
983     fmt.wFormatTag = WAVE_FORMAT_PCM;
984     fmt.nChannels = 2;
985     fmt.nSamplesPerSec = 48000;
986     fmt.wBitsPerSample = 16;
987     fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
988     fmt.nAvgBytesPerSec = fmt.nBlockAlign * fmt.nSamplesPerSec;
989     fmt.cbSize = 0;
990 
991     bufdesc.lpwfxFormat = &fmt;
992     bufdesc.dwBufferBytes = fmt.nSamplesPerSec * fmt.nBlockAlign / 10;
993     bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE |
994         DSBCAPS_CTRLVOLUME;
995 
996     secondaries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
997             sizeof(IDirectSoundBuffer *) * caps.dwMaxHwMixingAllBuffers);
998 
999     /* try to fill all of the hw buffers */
1000     trace("dwMaxHwMixingAllBuffers: %u\n", caps.dwMaxHwMixingAllBuffers);
1001     trace("dwMaxHwMixingStaticBuffers: %u\n", caps.dwMaxHwMixingStaticBuffers);
1002     trace("dwMaxHwMixingStreamingBuffers: %u\n", caps.dwMaxHwMixingStreamingBuffers);
1003     for(i = 0; i < caps.dwMaxHwMixingAllBuffers; ++i){
1004         hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &secondaries[i], NULL);
1005         ok(hr == S_OK || hr == E_NOTIMPL || broken(hr == DSERR_CONTROLUNAVAIL) || broken(hr == E_FAIL),
1006                 "CreateSoundBuffer(%u) failed: %08x\n", i, hr);
1007         if(hr != S_OK)
1008             break;
1009 
1010         bufcaps.dwSize = sizeof(bufcaps);
1011         hr = IDirectSoundBuffer_GetCaps(secondaries[i], &bufcaps);
1012         ok(hr == S_OK, "GetCaps failed: %08x\n", hr);
1013         ok((bufcaps.dwFlags & DSBCAPS_LOCHARDWARE) != 0,
1014                 "Buffer wasn't allocated in hardware, dwFlags: %x\n", bufcaps.dwFlags);
1015     }
1016 
1017     /* see if we can create one more */
1018     hr = IDirectSound8_CreateSoundBuffer(ds, &bufdesc, &secondary, NULL);
1019     ok((i == caps.dwMaxHwMixingAllBuffers && hr == DSERR_ALLOCATED) || /* out of hw buffers */
1020             (caps.dwMaxHwMixingAllBuffers == 0 && hr == DSERR_INVALIDCALL) || /* no hw buffers at all */
1021             hr == E_NOTIMPL || /* don't support hw buffers */
1022             broken(hr == DSERR_CONTROLUNAVAIL) || /* vmware winxp, others? */
1023             broken(hr == E_FAIL) || /* broken AC97 driver */
1024             broken(hr == S_OK) /* broken driver allows more hw bufs than dscaps claims */,
1025             "CreateSoundBuffer(%u) gave wrong error: %08x\n", i, hr);
1026     if(hr == S_OK)
1027         IDirectSoundBuffer_Release(secondary);
1028 
1029     for(i = 0; i < caps.dwMaxHwMixingAllBuffers; ++i)
1030         if(secondaries[i])
1031             IDirectSoundBuffer_Release(secondaries[i]);
1032 
1033     HeapFree(GetProcessHeap(), 0, secondaries);
1034 
1035     IDirectSoundBuffer_Release(primary);
1036     IDirectSound8_Release(ds);
1037 }
1038 
1039 static struct {
1040     UINT dev_count;
1041     GUID guid;
1042 } default_info = { 0 };
1043 
default_device_cb(GUID * guid,const char * desc,const char * module,void * user)1044 static BOOL WINAPI default_device_cb(GUID *guid, const char *desc,
1045         const char *module, void *user)
1046 {
1047     trace("guid: %p, desc: %s\n", guid, desc);
1048     if(!guid)
1049         ok(default_info.dev_count == 0, "Got NULL GUID not in first position\n");
1050     else{
1051         if(default_info.dev_count == 0){
1052             ok(IsEqualGUID(guid, &default_info.guid), "Expected default device GUID\n");
1053         }else{
1054             ok(!IsEqualGUID(guid, &default_info.guid), "Got default GUID at unexpected location: %u\n",
1055                     default_info.dev_count);
1056         }
1057 
1058         /* only count real devices */
1059         ++default_info.dev_count;
1060     }
1061 
1062     return TRUE;
1063 }
1064 
test_first_device(void)1065 static void test_first_device(void)
1066 {
1067     IMMDeviceEnumerator *devenum;
1068     IMMDevice *defdev;
1069     IPropertyStore *ps;
1070     PROPVARIANT pv;
1071     HRESULT hr;
1072 
1073     hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL,
1074             CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&devenum);
1075     if(FAILED(hr)){
1076         win_skip("MMDevAPI is not available, skipping default device test\n");
1077         return;
1078     }
1079 
1080     hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender,
1081             eMultimedia, &defdev);
1082     if (hr == E_NOTFOUND) {
1083         win_skip("No default device found\n");
1084         return;
1085     }
1086     ok(hr == S_OK, "GetDefaultAudioEndpoint failed: %08x\n", hr);
1087 
1088     hr = IMMDevice_OpenPropertyStore(defdev, STGM_READ, &ps);
1089     ok(hr == S_OK, "OpenPropertyStore failed: %08x\n", hr);
1090 
1091     PropVariantInit(&pv);
1092 
1093     hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pv);
1094     ok(hr == S_OK, "GetValue failed: %08x\n", hr);
1095 
1096     CLSIDFromString(pv.pwszVal, &default_info.guid);
1097 
1098     PropVariantClear(&pv);
1099     IPropertyStore_Release(ps);
1100     IMMDevice_Release(defdev);
1101     IMMDeviceEnumerator_Release(devenum);
1102 
1103     hr = pDirectSoundEnumerateA(&default_device_cb, NULL);
1104     ok(hr == S_OK, "DirectSoundEnumerateA failed: %08x\n", hr);
1105 }
1106 
test_COM(void)1107 static void test_COM(void)
1108 {
1109     IDirectSound *ds;
1110     IDirectSound8 *ds8 = (IDirectSound8*)0xdeadbeef;
1111     IUnknown *unk, *unk8;
1112     ULONG refcount;
1113     HRESULT hr;
1114 
1115     /* COM aggregation */
1116     hr = CoCreateInstance(&CLSID_DirectSound8, (IUnknown*)&ds, CLSCTX_INPROC_SERVER,
1117             &IID_IUnknown, (void**)&ds8);
1118     ok(hr == CLASS_E_NOAGGREGATION,
1119             "DirectSound create failed: %08x, expected CLASS_E_NOAGGREGATION\n", hr);
1120     ok(!ds8, "ds8 = %p\n", ds8);
1121 
1122     /* Invalid RIID */
1123     hr = CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER,
1124             &IID_IDirectSound3DBuffer, (void**)&ds8);
1125     ok(hr == E_NOINTERFACE,
1126             "DirectSound create failed: %08x, expected E_NOINTERFACE\n", hr);
1127 
1128     /* Same refcount for IDirectSound and IDirectSound8 */
1129     hr = CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound8,
1130             (void**)&ds8);
1131     ok(hr == S_OK, "DirectSound create failed: %08x, expected S_OK\n", hr);
1132     refcount = IDirectSound8_AddRef(ds8);
1133     ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
1134     hr = IDirectSound8_QueryInterface(ds8, &IID_IDirectSound, (void**)&ds);
1135     ok(hr == S_OK, "QueryInterface for IID_IDirectSound failed: %08x\n", hr);
1136     refcount = IDirectSound8_AddRef(ds8);
1137     ok(refcount == 4, "refcount == %u, expected 4\n", refcount);
1138     refcount = IDirectSound_AddRef(ds);
1139     ok(refcount == 5, "refcount == %u, expected 5\n", refcount);
1140 
1141     /* Separate refcount for IUnknown */
1142     hr = IDirectSound_QueryInterface(ds, &IID_IUnknown, (void**)&unk);
1143     ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr);
1144     refcount = IUnknown_AddRef(unk);
1145     ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
1146     hr = IDirectSound_QueryInterface(ds8, &IID_IUnknown, (void**)&unk8);
1147     ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr);
1148     refcount = IUnknown_AddRef(unk8);
1149     ok(refcount == 4, "refcount == %u, expected 4\n", refcount);
1150     refcount = IDirectSound_AddRef(ds);
1151     ok(refcount == 6, "refcount == %u, expected 6\n", refcount);
1152 
1153     while (IDirectSound_Release(ds));
1154     while (IUnknown_Release(unk));
1155 }
1156 
START_TEST(dsound8)1157 START_TEST(dsound8)
1158 {
1159     HMODULE hDsound;
1160 
1161     CoInitialize(NULL);
1162 
1163     hDsound = LoadLibrary("dsound.dll");
1164     if (hDsound)
1165     {
1166 
1167         pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound,
1168             "DirectSoundEnumerateA");
1169         pDirectSoundCreate8 = (void*)GetProcAddress(hDsound,
1170             "DirectSoundCreate8");
1171         if (pDirectSoundCreate8)
1172         {
1173             test_COM();
1174             IDirectSound8_tests();
1175             dsound8_tests();
1176             test_hw_buffers();
1177             test_first_device();
1178         }
1179         else
1180             skip("DirectSoundCreate8 missing - skipping all tests\n");
1181 
1182         FreeLibrary(hDsound);
1183     }
1184     else
1185         skip("dsound.dll not found - skipping all tests\n");
1186 
1187     CoUninitialize();
1188 }
1189