1 /*
2  * Unit tests for capture functions
3  *
4  * Copyright (c) 2002 Francois Gouget
5  * Copyright (c) 2003 Robert Reif
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "dsound_test.h"
23 
24 #include <stdio.h>
25 
26 #define NOTIFICATIONS    5
27 
28 static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID,LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL;
29 static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL;
30 
31 static const char * get_format_str(WORD format)
32 {
33     static char msg[32];
34 #define WAVE_FORMAT(f) case f: return #f
35     switch (format) {
36     WAVE_FORMAT(WAVE_FORMAT_PCM);
37     WAVE_FORMAT(WAVE_FORMAT_ADPCM);
38     WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD);
39     WAVE_FORMAT(WAVE_FORMAT_ALAW);
40     WAVE_FORMAT(WAVE_FORMAT_MULAW);
41     WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM);
42     WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM);
43     WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM);
44     WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM);
45     WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM);
46     WAVE_FORMAT(WAVE_FORMAT_DIGISTD);
47     WAVE_FORMAT(WAVE_FORMAT_DIGIFIX);
48     WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM);
49     WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM);
50     WAVE_FORMAT(WAVE_FORMAT_SONARC);
51     WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH);
52     WAVE_FORMAT(WAVE_FORMAT_ECHOSC1);
53     WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36);
54     WAVE_FORMAT(WAVE_FORMAT_APTX);
55     WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10);
56     WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2);
57     WAVE_FORMAT(WAVE_FORMAT_GSM610);
58     WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME);
59     WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC);
60     WAVE_FORMAT(WAVE_FORMAT_DIGIREAL);
61     WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM);
62     WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10);
63     WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM);
64     WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM);
65     WAVE_FORMAT(WAVE_FORMAT_MPEG);
66     WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3);
67     WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM);
68     WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8);
69     WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10);
70     WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND);
71     WAVE_FORMAT(WAVE_FORMAT_OLIGSM);
72     WAVE_FORMAT(WAVE_FORMAT_OLIADPCM);
73     WAVE_FORMAT(WAVE_FORMAT_OLICELP);
74     WAVE_FORMAT(WAVE_FORMAT_OLISBC);
75     WAVE_FORMAT(WAVE_FORMAT_OLIOPR);
76     WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT);
77     WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE);
78     }
79 #undef WAVE_FORMAT
80     sprintf(msg, "Unknown(0x%04x)", format);
81     return msg;
82 }
83 
84 const char * format_string(const WAVEFORMATEX* wfx)
85 {
86     static char str[64];
87 
88     sprintf(str, "%5dx%2dx%d %s",
89 	wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels,
90         get_format_str(wfx->wFormatTag));
91 
92     return str;
93 }
94 
95 static void IDirectSoundCapture_test(LPDIRECTSOUNDCAPTURE dsco,
96                                      BOOL initialized, LPCGUID lpGuid)
97 {
98     HRESULT rc;
99     DSCCAPS dsccaps;
100     int ref;
101     IUnknown * unknown;
102     IDirectSoundCapture * dsc;
103 
104     /* Try to Query for objects */
105     rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IUnknown,
106                                           (LPVOID*)&unknown);
107     ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IUnknown) "
108        "failed: %08x\n", rc);
109     if (rc==DS_OK)
110         IDirectSoundCapture_Release(unknown);
111 
112     rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IDirectSoundCapture,
113                                           (LPVOID*)&dsc);
114     ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IDirectSoundCapture) "
115        "failed: %08x\n", rc);
116     if (rc==DS_OK)
117         IDirectSoundCapture_Release(dsc);
118 
119     if (initialized == FALSE) {
120         /* try uninitialized object */
121         rc=IDirectSoundCapture_GetCaps(dsco,0);
122         ok(rc==DSERR_UNINITIALIZED||rc==E_INVALIDARG,
123            "IDirectSoundCapture_GetCaps(NULL) should have returned "
124            "DSERR_UNINITIALIZED or E_INVALIDARG, returned: %08x\n", rc);
125 
126         rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps);
127         ok(rc==DSERR_UNINITIALIZED,"IDirectSoundCapture_GetCaps() "
128            "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc);
129 
130         rc=IDirectSoundCapture_Initialize(dsco, lpGuid);
131         ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||
132            rc==E_FAIL||rc==E_INVALIDARG,
133            "IDirectSoundCapture_Initialize() failed: %08x\n", rc);
134         if (rc==DSERR_NODRIVER||rc==E_INVALIDARG) {
135             trace("  No Driver\n");
136             goto EXIT;
137         } else if (rc==E_FAIL) {
138             trace("  No Device\n");
139             goto EXIT;
140         } else if (rc==DSERR_ALLOCATED) {
141             trace("  Already In Use\n");
142             goto EXIT;
143         }
144     }
145 
146     rc=IDirectSoundCapture_Initialize(dsco, lpGuid);
147     ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSoundCapture_Initialize() "
148        "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc);
149 
150     /* DSOUND: Error: Invalid caps buffer */
151     rc=IDirectSoundCapture_GetCaps(dsco, 0);
152     ok(rc==DSERR_INVALIDPARAM, "IDirectSoundCapture_GetCaps(NULL) "
153        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
154 
155     ZeroMemory(&dsccaps, sizeof(dsccaps));
156 
157     /* DSOUND: Error: Invalid caps buffer */
158     rc=IDirectSound_GetCaps(dsco, &dsccaps);
159     ok(rc==DSERR_INVALIDPARAM, "IDirectSound_GetCaps() "
160        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
161 
162     dsccaps.dwSize=sizeof(dsccaps);
163 
164     /* DSOUND: Running on a certified driver */
165     rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps);
166     ok(rc==DS_OK, "IDirectSoundCapture_GetCaps() failed: %08x\n", rc);
167 
168 EXIT:
169     ref=IDirectSoundCapture_Release(dsco);
170     ok(ref==0, "IDirectSoundCapture_Release() has %d references, "
171        "should have 0\n", ref);
172 }
173 
174 static void test_capture(void)
175 {
176     HRESULT rc;
177     LPDIRECTSOUNDCAPTURE dsco=NULL;
178     LPCLASSFACTORY cf=NULL;
179 
180     trace("Testing IDirectSoundCapture\n");
181 
182     rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL,
183                         &IID_IClassFactory, (void**)&cf);
184     ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) "
185        "failed: %08x\n", rc);
186 
187     rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL,
188                         &IID_IUnknown, (void**)&cf);
189     ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IUnknown) "
190        "failed: %08x\n", rc);
191 
192     /* try the COM class factory method of creation with no device specified */
193     rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
194                         &IID_IDirectSoundCapture, (void**)&dsco);
195     ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc);
196     if (rc==REGDB_E_CLASSNOTREG) {
197         trace("  Class Not Registered\n");
198         return;
199     }
200     if (dsco)
201         IDirectSoundCapture_test(dsco, FALSE, NULL);
202 
203     /* try the COM class factory method of creation with default capture
204      * device specified */
205     rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
206                         &IID_IDirectSoundCapture, (void**)&dsco);
207     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc);
208     if (dsco)
209         IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultCapture);
210 
211     /* try the COM class factory method of creation with default voice
212      * capture device specified */
213     rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
214                         &IID_IDirectSoundCapture, (void**)&dsco);
215     ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc);
216     if (dsco)
217         IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultVoiceCapture);
218 
219     /* try the COM class factory method of creation with a bad
220      * IID specified */
221     rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
222                         &CLSID_DirectSoundPrivate, (void**)&dsco);
223     ok(rc==E_NOINTERFACE,
224        "CoCreateInstance(CLSID_DirectSoundCapture,CLSID_DirectSoundPrivate) "
225        "should have failed: %08x\n",rc);
226 
227     /* try with no device specified */
228     rc=pDirectSoundCaptureCreate(NULL,&dsco,NULL);
229     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
230        "DirectSoundCaptureCreate(NULL) failed: %08x\n",rc);
231     if (rc==S_OK && dsco)
232         IDirectSoundCapture_test(dsco, TRUE, NULL);
233 
234     /* try with default capture device specified */
235     rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultCapture,&dsco,NULL);
236     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
237        "DirectSoundCaptureCreate(DSDEVID_DefaultCapture) failed: %08x\n", rc);
238     if (rc==DS_OK && dsco)
239         IDirectSoundCapture_test(dsco, TRUE, NULL);
240 
241     /* try with default voice capture device specified */
242     rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoiceCapture,&dsco,NULL);
243     ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL,
244        "DirectSoundCaptureCreate(DSDEVID_DefaultVoiceCapture) failed: %08x\n", rc);
245     if (rc==DS_OK && dsco)
246         IDirectSoundCapture_test(dsco, TRUE, NULL);
247 
248     /* try with a bad device specified */
249     rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoicePlayback,&dsco,NULL);
250     ok(rc==DSERR_NODRIVER,
251        "DirectSoundCaptureCreate(DSDEVID_DefaultVoicePlatback) "
252        "should have failed: %08x\n",rc);
253     if (rc==DS_OK && dsco)
254         IDirectSoundCapture_Release(dsco);
255 }
256 
257 typedef struct {
258     char* wave;
259     DWORD wave_len;
260 
261     LPDIRECTSOUNDCAPTUREBUFFER dscbo;
262     LPWAVEFORMATEX wfx;
263     DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS];
264     HANDLE event[NOTIFICATIONS];
265     LPDIRECTSOUNDNOTIFY notify;
266 
267     DWORD buffer_size;
268     DWORD read;
269     DWORD offset;
270     DWORD size;
271 
272     DWORD last_pos;
273 } capture_state_t;
274 
275 static int capture_buffer_service(capture_state_t* state)
276 {
277     HRESULT rc;
278     LPVOID ptr1,ptr2;
279     DWORD len1,len2;
280     DWORD capture_pos,read_pos;
281 
282     rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos,
283                                                     &read_pos);
284     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCurrentPosition() failed: %08x\n", rc);
285     if (rc!=DS_OK)
286 	return 0;
287 
288     rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size,
289                                       &ptr1,&len1,&ptr2,&len2,0);
290     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Lock() failed: %08x\n", rc);
291     if (rc!=DS_OK)
292 	return 0;
293 
294     rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2);
295     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Unlock() failed: %08x\n", rc);
296     if (rc!=DS_OK)
297 	return 0;
298 
299     state->offset = (state->offset + state->size) % state->buffer_size;
300 
301     return 1;
302 }
303 
304 static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco,
305 				LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record)
306 {
307     HRESULT rc;
308     DSCBCAPS dscbcaps;
309     WAVEFORMATEX wfx;
310     DWORD size,status;
311     capture_state_t state;
312     int i, ref;
313 
314     /* Private dsound.dll: Error: Invalid caps pointer */
315     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0);
316     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should "
317        "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
318 
319     /* Private dsound.dll: Error: Invalid caps pointer */
320     dscbcaps.dwSize=0;
321     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
322     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should "
323        "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
324 
325     dscbcaps.dwSize=sizeof(dscbcaps);
326     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
327     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCaps() failed: %08x\n", rc);
328     if (rc==DS_OK && winetest_debug > 1) {
329 	trace("    Caps: size = %d flags=0x%08x buffer size=%d\n",
330 	    dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes);
331     }
332 
333     /* Query the format size. Note that it may not match sizeof(wfx) */
334     /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must
335      * be non-NULL */
336     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL);
337     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetFormat() should "
338        "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
339 
340     size=0;
341     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size);
342     ok(rc==DS_OK && size!=0,"IDirectSoundCaptureBuffer_GetFormat() should "
343        "have returned the needed size: rc=%08x, size=%d\n", rc,size);
344 
345     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL);
346     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetFormat() failed: %08x\n", rc);
347     if (rc==DS_OK && winetest_debug > 1) {
348 	trace("    Format: tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n",
349 	      wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
350 	      wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
351     }
352 
353     /* Private dsound.dll: Error: Invalid status pointer */
354     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0);
355     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetStatus() should "
356        "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
357 
358     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
359     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc);
360     if (rc==DS_OK && winetest_debug > 1) {
361 	trace("    Status=0x%04x\n",status);
362     }
363 
364     ZeroMemory(&state, sizeof(state));
365     state.dscbo=dscbo;
366     state.wfx=&wfx;
367     state.buffer_size = dscbcaps.dwBufferBytes;
368     for (i = 0; i < NOTIFICATIONS; i++)
369 	state.event[i] = CreateEvent( NULL, FALSE, FALSE, NULL );
370     state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS;
371 
372     rc=IDirectSoundCaptureBuffer_QueryInterface(dscbo,&IID_IDirectSoundNotify,
373                                                 (void **)&(state.notify));
374     ok((rc==DS_OK)&&(state.notify!=NULL),
375        "IDirectSoundCaptureBuffer_QueryInterface() failed: %08x\n", rc);
376 
377     for (i = 0; i < NOTIFICATIONS; i++) {
378 	state.posnotify[i].dwOffset = (i * state.size) + state.size - 1;
379 	state.posnotify[i].hEventNotify = state.event[i];
380     }
381 
382     rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS,
383                                                    state.posnotify);
384     ok(rc==DS_OK,"IDirectSoundNotify_SetNotificationPositions() failed: %08x\n", rc);
385 
386     ref=IDirectSoundNotify_Release(state.notify);
387     ok(ref==0,"IDirectSoundNotify_Release(): has %d references, should have "
388        "0\n",ref);
389 
390     rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING);
391     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Start() failed: %08x\n", rc);
392 
393     rc=IDirectSoundCaptureBuffer_Start(dscbo,0);
394     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Start() failed: %08x\n", rc);
395 
396     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
397     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc);
398     ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING) || broken(status==DSCBSTATUS_CAPTURING),
399        "GetStatus: bad status: %x\n",status);
400 
401     if (record) {
402 	/* wait for the notifications */
403 	for (i = 0; i < (NOTIFICATIONS * 2); i++) {
404 	    rc=WaitForMultipleObjects(NOTIFICATIONS,state.event,FALSE,3000);
405 	    ok(rc==(WAIT_OBJECT_0+(i%NOTIFICATIONS)),
406                "WaitForMultipleObjects failed: 0x%x\n",rc);
407 	    if (rc!=(WAIT_OBJECT_0+(i%NOTIFICATIONS))) {
408 		ok((rc==WAIT_TIMEOUT)||(rc==WAIT_FAILED),
409                    "Wrong notification: should be %d, got %d\n",
410 		    i%NOTIFICATIONS,rc-WAIT_OBJECT_0);
411 	    }
412 	    if (!capture_buffer_service(&state))
413 		break;
414 	}
415 
416     }
417     rc=IDirectSoundCaptureBuffer_Stop(dscbo);
418     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Stop() failed: %08x\n", rc);
419 
420     rc=IDirectSoundCaptureBuffer_Stop(dscbo);
421     ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Stop() failed: %08x\n", rc);
422 }
423 
424 static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
425 				    LPCSTR lpcstrModule, LPVOID lpContext)
426 {
427     HRESULT rc;
428     LPDIRECTSOUNDCAPTURE dsco=NULL;
429     LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL;
430     DSCBUFFERDESC bufdesc;
431     WAVEFORMATEX wfx;
432     DSCCAPS dsccaps;
433     DWORD f;
434     int ref;
435 
436     /* Private dsound.dll: Error: Invalid interface buffer */
437     trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule);
438     rc=pDirectSoundCaptureCreate(lpGuid,NULL,NULL);
439     ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate() should have "
440        "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
441 
442     rc=pDirectSoundCaptureCreate(lpGuid,&dsco,NULL);
443     ok((rc==DS_OK)||(rc==DSERR_NODRIVER)||(rc==E_FAIL)||(rc==DSERR_ALLOCATED),
444        "DirectSoundCaptureCreate() failed: %08x\n",rc);
445     if (rc!=DS_OK) {
446         if (rc==DSERR_NODRIVER)
447             trace("  No Driver\n");
448         else if (rc==E_FAIL)
449             trace("  No Device\n");
450         else if (rc==DSERR_ALLOCATED)
451             trace("  Already In Use\n");
452 	goto EXIT;
453     }
454 
455     /* Private dsound.dll: Error: Invalid caps buffer */
456     rc=IDirectSoundCapture_GetCaps(dsco,NULL);
457     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have "
458        "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
459 
460     /* Private dsound.dll: Error: Invalid caps buffer */
461     dsccaps.dwSize=0;
462     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
463     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have "
464        "returned DSERR_INVALIDPARAM, returned: %08x\n",rc);
465 
466     dsccaps.dwSize=sizeof(dsccaps);
467     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
468     ok(rc==DS_OK,"IDirectSoundCapture_GetCaps() failed: %08x\n", rc);
469     if (rc==DS_OK && winetest_debug > 1) {
470 	trace("  Caps: size=%d flags=0x%08x formats=%05x channels=%d\n",
471 	      dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats,
472               dsccaps.dwChannels);
473     }
474 
475     /* Private dsound.dll: Error: Invalid size */
476     /* Private dsound.dll: Error: Invalid capture buffer description */
477     ZeroMemory(&bufdesc, sizeof(bufdesc));
478     bufdesc.dwSize=0;
479     bufdesc.dwFlags=0;
480     bufdesc.dwBufferBytes=0;
481     bufdesc.dwReserved=0;
482     bufdesc.lpwfxFormat=NULL;
483     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
484     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() "
485        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
486     if (rc==DS_OK) {
487 	ref=IDirectSoundCaptureBuffer_Release(dscbo);
488 	ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
489            "should have 0\n",ref);
490     }
491 
492     /* Private dsound.dll: Error: Invalid buffer size */
493     /* Private dsound.dll: Error: Invalid capture buffer description */
494     ZeroMemory(&bufdesc, sizeof(bufdesc));
495     bufdesc.dwSize=sizeof(bufdesc);
496     bufdesc.dwFlags=0;
497     bufdesc.dwBufferBytes=0;
498     bufdesc.dwReserved=0;
499     bufdesc.lpwfxFormat=NULL;
500     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
501     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() "
502        "should have returned DSERR_INVALIDPARAM, returned %08x\n", rc);
503     if (rc==DS_OK) {
504 	ref=IDirectSoundCaptureBuffer_Release(dscbo);
505 	ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
506            "should have 0\n",ref);
507     }
508 
509     /* Private dsound.dll: Error: Invalid buffer size */
510     /* Private dsound.dll: Error: Invalid capture buffer description */
511     ZeroMemory(&bufdesc, sizeof(bufdesc));
512     ZeroMemory(&wfx, sizeof(wfx));
513     bufdesc.dwSize=sizeof(bufdesc);
514     bufdesc.dwFlags=0;
515     bufdesc.dwBufferBytes=0;
516     bufdesc.dwReserved=0;
517     bufdesc.lpwfxFormat=&wfx;
518     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
519     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() "
520        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
521     if (rc==DS_OK) {
522 	ref=IDirectSoundCaptureBuffer_Release(dscbo);
523 	ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
524            "should have 0\n",ref);
525     }
526 
527     /* Private dsound.dll: Error: Invalid buffer size */
528     /* Private dsound.dll: Error: Invalid capture buffer description */
529     init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1);
530     ZeroMemory(&bufdesc, sizeof(bufdesc));
531     bufdesc.dwSize=sizeof(bufdesc);
532     bufdesc.dwFlags=0;
533     bufdesc.dwBufferBytes=0;
534     bufdesc.dwReserved=0;
535     bufdesc.lpwfxFormat=&wfx;
536     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
537     ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() "
538        "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc);
539     if (rc==DS_OK) {
540 	ref=IDirectSoundCaptureBuffer_Release(dscbo);
541 	ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
542            "should have 0\n",ref);
543     }
544 
545     for (f=0;f<NB_FORMATS;f++) {
546 	dscbo=NULL;
547 	init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],
548                     formats[f][2]);
549 	ZeroMemory(&bufdesc, sizeof(bufdesc));
550 	bufdesc.dwSize=sizeof(bufdesc);
551 	bufdesc.dwFlags=0;
552 	bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
553 	bufdesc.dwReserved=0;
554 	bufdesc.lpwfxFormat=&wfx;
555         if (winetest_interactive)
556 	    trace("  Testing the capture buffer at %s\n", format_string(&wfx));
557 	rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
558 	ok(((rc==DS_OK)&&(dscbo!=NULL))
559            || rc==DSERR_BADFORMAT || rc==DSERR_INVALIDCALL || rc==DSERR_NODRIVER
560            || rc==DSERR_ALLOCATED || rc==E_INVALIDARG || rc==E_FAIL,
561            "IDirectSoundCapture_CreateCaptureBuffer() failed to create a "
562            "%s capture buffer: %08x\n",format_string(&wfx),rc);
563 	if (rc==DS_OK) {
564 	    test_capture_buffer(dsco, dscbo, winetest_interactive);
565 	    ref=IDirectSoundCaptureBuffer_Release(dscbo);
566 	    ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
567                "should have 0\n",ref);
568 	} else if (rc==DSERR_BADFORMAT) {
569             ok(!(dsccaps.dwFormats & formats[f][3]),
570                "IDirectSoundCapture_CreateCaptureBuffer() failed to create a "
571                "capture buffer: format listed as supported but using it failed\n");
572             if (!(dsccaps.dwFormats & formats[f][3]))
573                 trace("  Format not supported: %s\n", format_string(&wfx));
574         } else if (rc==DSERR_NODRIVER) {
575             trace("  No Driver\n");
576         } else if (rc==DSERR_ALLOCATED) {
577             trace("  Already In Use\n");
578         } else if (rc==E_INVALIDARG) { /* try the old version struct */
579             DSCBUFFERDESC1 bufdesc1;
580 	    ZeroMemory(&bufdesc1, sizeof(bufdesc1));
581 	    bufdesc1.dwSize=sizeof(bufdesc1);
582 	    bufdesc1.dwFlags=0;
583 	    bufdesc1.dwBufferBytes=wfx.nAvgBytesPerSec;
584 	    bufdesc1.dwReserved=0;
585 	    bufdesc1.lpwfxFormat=&wfx;
586 	    rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,
587                 (DSCBUFFERDESC*)&bufdesc1,&dscbo,NULL);
588             ok(rc==DS_OK || broken(rc==DSERR_INVALIDPARAM),
589                "IDirectSoundCapture_CreateCaptureBuffer() failed to create a "
590                "%s capture buffer: %08x\n",format_string(&wfx), rc);
591             if (rc==DSERR_INVALIDPARAM) {
592                 skip("broken driver\n");
593                 goto EXIT;
594             }
595             if (rc==DS_OK) {
596 	        test_capture_buffer(dsco, dscbo, winetest_interactive);
597 	        ref=IDirectSoundCaptureBuffer_Release(dscbo);
598 	        ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d "
599                    "references, should have 0\n",ref);
600             }
601         } else if (rc==E_FAIL) {
602             /* WAVE_FORMAT_PCM only allows 8 and 16 bits per sample, so only
603              * report a failure if the bits per sample is 8 or 16
604              */
605             if (wfx.wBitsPerSample == 8 || wfx.wBitsPerSample == 16)
606                 ok(FALSE,"Should not fail for 8 or 16 bits per sample\n");
607         }
608     }
609 
610     /* try a non PCM format */
611     if (0)
612     {
613     /* FIXME: Why is this commented out? */
614     init_format(&wfx,WAVE_FORMAT_MULAW,8000,8,1);
615     ZeroMemory(&bufdesc, sizeof(bufdesc));
616     bufdesc.dwSize=sizeof(bufdesc);
617     bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
618     bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
619     bufdesc.dwReserved=0;
620     bufdesc.lpwfxFormat=&wfx;
621     if (winetest_interactive)
622         trace("  Testing the capture buffer at %s\n", format_string(&wfx));
623     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
624     ok((rc==DS_OK)&&(dscbo!=NULL),"IDirectSoundCapture_CreateCaptureBuffer() "
625        "failed to create a capture buffer: %08x\n",rc);
626     if ((rc==DS_OK)&&(dscbo!=NULL)) {
627 	test_capture_buffer(dsco, dscbo, winetest_interactive);
628 	ref=IDirectSoundCaptureBuffer_Release(dscbo);
629 	ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, "
630            "should have 0\n",ref);
631     }
632     }
633 
634     /* Try an invalid format to test error handling */
635     if (0)
636     {
637     /* FIXME: Remove this test altogether? */
638     init_format(&wfx,WAVE_FORMAT_PCM,2000000,16,2);
639     ZeroMemory(&bufdesc, sizeof(bufdesc));
640     bufdesc.dwSize=sizeof(bufdesc);
641     bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
642     bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
643     bufdesc.dwReserved=0;
644     bufdesc.lpwfxFormat=&wfx;
645     if (winetest_interactive)
646         trace("  Testing the capture buffer at %s\n", format_string(&wfx));
647     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
648     ok(rc!=DS_OK,"IDirectSoundCapture_CreateCaptureBuffer() should have failed "
649        "at 2 MHz %08x\n",rc);
650     }
651 
652 EXIT:
653     if (dsco!=NULL) {
654 	ref=IDirectSoundCapture_Release(dsco);
655 	ok(ref==0,"IDirectSoundCapture_Release() has %d references, should "
656            "have 0\n",ref);
657     }
658 
659     return TRUE;
660 }
661 
662 static void test_enumerate(void)
663 {
664     HRESULT rc;
665     rc=pDirectSoundCaptureEnumerateA(&dscenum_callback,NULL);
666     ok(rc==DS_OK,"DirectSoundCaptureEnumerateA() failed: %08x\n", rc);
667 }
668 
669 static void test_COM(void)
670 {
671     IDirectSoundCapture *dsc = (IDirectSoundCapture*)0xdeadbeef;
672     IDirectSoundCaptureBuffer *buffer = (IDirectSoundCaptureBuffer*)0xdeadbeef;
673     IDirectSoundNotify *notify;
674     IUnknown *unk;
675     DSCBUFFERDESC bufdesc;
676     WAVEFORMATEX wfx;
677     HRESULT hr;
678     ULONG refcount;
679 
680     hr = pDirectSoundCaptureCreate(NULL, &dsc, (IUnknown*)0xdeadbeef);
681     ok(hr == DSERR_NOAGGREGATION,
682        "DirectSoundCaptureCreate failed: %08x, expected DSERR_NOAGGREGATION\n", hr);
683     ok(dsc == (IDirectSoundCapture*)0xdeadbeef, "dsc = %p\n", dsc);
684 
685     hr = pDirectSoundCaptureCreate(NULL, &dsc, NULL);
686     if (hr == DSERR_NODRIVER) {
687         skip("No driver\n");
688         return;
689     }
690     ok(hr == DS_OK, "DirectSoundCaptureCreate failed: %08x, expected DS_OK\n", hr);
691 
692     /* Different refcount for IDirectSoundCapture and for IUnknown */
693     refcount = IDirectSoundCapture_AddRef(dsc);
694     ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
695     hr = IDirectSoundCapture_QueryInterface(dsc, &IID_IUnknown, (void**)&unk);
696     ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr);
697     refcount = IUnknown_AddRef(unk);
698     ok(refcount == 2, "refcount == %u, expected 2\n", refcount);
699     IUnknown_Release(unk);
700     IUnknown_Release(unk);
701     IDirectSoundCapture_Release(dsc);
702 
703     init_format(&wfx, WAVE_FORMAT_PCM, 44100, 16, 1);
704     ZeroMemory(&bufdesc, sizeof(bufdesc));
705     bufdesc.dwSize = sizeof(bufdesc);
706     bufdesc.dwBufferBytes = wfx.nAvgBytesPerSec;
707     bufdesc.lpwfxFormat = &wfx;
708 
709     hr = IDirectSoundCapture_CreateCaptureBuffer(dsc, &bufdesc, &buffer, (IUnknown*)0xdeadbeef);
710     if (hr == E_INVALIDARG) {
711         /* Old DirectX has only the 1st version of the DSCBUFFERDESC struct */
712         bufdesc.dwSize = sizeof(DSCBUFFERDESC1);
713         hr = IDirectSoundCapture_CreateCaptureBuffer(dsc, &bufdesc, &buffer, (IUnknown*)0xdeadbeef);
714     }
715     ok(hr == DSERR_NOAGGREGATION,
716        "IDirectSoundCapture_CreateCaptureBuffer failed: %08x, expected DSERR_NOAGGREGATION\n", hr);
717     ok(buffer == (IDirectSoundCaptureBuffer*)0xdeadbeef || !buffer /* Win2k without DirectX9 */,
718        "buffer = %p\n", buffer);
719 
720     hr = IDirectSoundCapture_CreateCaptureBuffer(dsc, &bufdesc, &buffer, NULL);
721     ok(hr == DS_OK, "IDirectSoundCapture_CreateCaptureBuffer failed: %08x, expected DS_OK\n", hr);
722 
723     /* IDirectSoundCaptureBuffer and IDirectSoundNotify have separate refcounts */
724     IDirectSoundCaptureBuffer_AddRef(buffer);
725     refcount = IDirectSoundCaptureBuffer_AddRef(buffer);
726     ok(refcount == 3, "IDirectSoundCaptureBuffer refcount is %u, expected 3\n", refcount);
727     hr = IDirectSoundCaptureBuffer_QueryInterface(buffer, &IID_IDirectSoundNotify, (void**)&notify);
728     ok(hr == DS_OK, "IDirectSoundCapture_QueryInterface failed: %08x, expected DS_OK\n", hr);
729     refcount = IDirectSoundNotify_AddRef(notify);
730     ok(refcount == 2, "IDirectSoundNotify refcount is %u, expected 2\n", refcount);
731     IDirectSoundCaptureBuffer_AddRef(buffer);
732     refcount = IDirectSoundCaptureBuffer_Release(buffer);
733     ok(refcount == 3, "IDirectSoundCaptureBuffer refcount is %u, expected 3\n", refcount);
734 
735     /* Release IDirectSoundCaptureBuffer while keeping IDirectSoundNotify alive */
736     while (IDirectSoundCaptureBuffer_Release(buffer) > 0);
737     refcount = IDirectSoundNotify_AddRef(notify);
738     ok(refcount == 3, "IDirectSoundNotify refcount is %u, expected 3\n", refcount);
739     refcount = IDirectSoundCaptureBuffer_AddRef(buffer);
740     ok(refcount == 1, "IDirectSoundCaptureBuffer refcount is %u, expected 1\n", refcount);
741 
742     while (IDirectSoundNotify_Release(notify) > 0);
743     refcount = IDirectSoundCaptureBuffer_Release(buffer);
744     ok(refcount == 0, "IDirectSoundCaptureBuffer refcount is %u, expected 0\n", refcount);
745     refcount = IDirectSoundCapture_Release(dsc);
746     ok(refcount == 0, "IDirectSoundCapture refcount is %u, expected 0\n", refcount);
747 }
748 
749 START_TEST(capture)
750 {
751     HMODULE hDsound;
752 
753     CoInitialize(NULL);
754 
755     hDsound = LoadLibrary("dsound.dll");
756     if (!hDsound) {
757         skip("dsound.dll not found - skipping all tests\n");
758         return;
759     }
760 
761     pDirectSoundCaptureCreate = (void*)GetProcAddress(hDsound, "DirectSoundCaptureCreate");
762     pDirectSoundCaptureEnumerateA = (void*)GetProcAddress(hDsound, "DirectSoundCaptureEnumerateA");
763     if (!pDirectSoundCaptureCreate || !pDirectSoundCaptureEnumerateA) {
764         skip("DirectSoundCapture{Create,Enumerate} missing - skipping all tests\n");
765         return;
766     }
767 
768     test_COM();
769     test_capture();
770     test_enumerate();
771 
772     FreeLibrary(hDsound);
773     CoUninitialize();
774 }
775