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