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