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