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