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