INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
24 #include <windows.h>
25
26 #include <math.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 #include "wine/test.h"
31 #include "windef.h"
32 #include "wingdi.h"
33 #include "dsound.h"
34 #include "mmreg.h"
35
36 static const unsigned int formats[][3]={
37     { 8000,  8, 1},
38     { 8000,  8, 2},
39     { 8000, 16, 1},
40     { 8000, 16, 2},
41     {11025,  8, 1},
42     {11025,  8, 2},
43     {11025, 16, 1},
44     {11025, 16, 2},
45     {22050,  8, 1},
46     {22050,  8, 2},
47     {22050, 16, 1},
48     {22050, 16, 2},
49     {44100,  8, 1},
50     {44100,  8, 2},
51     {44100, 16, 1},
52     {44100, 16, 2},
53     {48000,  8, 1},
54     {48000,  8, 2},
55     {48000, 16, 1},
56     {48000, 16, 2},
57     {96000,  8, 1},
58     {96000,  8, 2},
59     {96000, 16, 1},
60     {96000, 16, 2}
61 };
62 #define NB_FORMATS (sizeof(formats)/sizeof(*formats))
63
64 #define NOTIFICATIONS    5
65
66 static void init_format(WAVEFORMATEX* wfx, int format, int rate, int depth, int channels)
67 {
68     wfx->wFormatTag=format;
69     wfx->nChannels=channels;
70     wfx->wBitsPerSample=depth;
71     wfx->nSamplesPerSec=rate;
72     wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
73     if (wfx->nBlockAlign==0)    /* align compressed formats to byte boundry */
74         wfx->nBlockAlign=1;
75     wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nChannels*wfx->wBitsPerSample/8;
76     wfx->cbSize=0;
77 }
78
79 static char * format_string(WAVEFORMATEX* wfx)
80 {
81     static char str[64];
82
83     sprintf(str, "%ldx%dx%d %s",
84         wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels,
85         wfx->wFormatTag == WAVE_FORMAT_PCM ? "PCM" :
86         wfx->wFormatTag == WAVE_FORMAT_MULAW ? "MULAW" :
87         wfx->wFormatTag == WAVE_FORMAT_IMA_ADPCM ? "IMA ADPCM" : "Unknown");
88
89     return str;
90 }
91
92 typedef struct {
93     char* wave;
94     DWORD wave_len;
95
96     LPDIRECTSOUNDCAPTUREBUFFER dscbo;
97     LPWAVEFORMATEX wfx;
98     DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS];
99     HANDLE event[NOTIFICATIONS];
100     LPDIRECTSOUNDNOTIFY notify;
101
102     DWORD buffer_size;
103     DWORD read;
104     DWORD offset;
105     DWORD size;
106
107     DWORD last_pos;
108 } capture_state_t;
109
110 static int capture_buffer_service(capture_state_t* state)
111 {
112     HRESULT rc;
113     LPVOID ptr1,ptr2;
114     DWORD len1,len2;
115     DWORD capture_pos,read_pos;
116
117     rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos,&read_pos);
118     ok(rc==DS_OK,"GetCurrentPosition failed: 0x%lx\n",rc);
119     if (rc!=DS_OK)
120         return 0;
121
122     rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size,&ptr1,&len1,&ptr2,&len2,0);
123     ok(rc==DS_OK,"Lock failed: 0x%lx\n",rc);
124     if (rc!=DS_OK)
125         return 0;
126
127     rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2);
128     ok(rc==DS_OK,"Unlock failed: 0x%lx\n",rc);
129     if (rc!=DS_OK)
130         return 0;
131
132     state->offset = (state->offset + state->size) % state->buffer_size;
133
134     return 1;
135 }
136
137 static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, 
138                                 LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record)
139 {
140     HRESULT rc;
141     DSCBCAPS dscbcaps;
142     WAVEFORMATEX wfx;
143     DWORD size,status;
144     capture_state_t state;
145     int i;
146
147     /* Private dsound.dll: Error: Invalid caps pointer */
148     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0);
149     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
150
151     /* Private dsound.dll: Error: Invalid caps pointer */
152     dscbcaps.dwSize=0;
153     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
154     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
155
156     dscbcaps.dwSize=sizeof(dscbcaps);
157     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
158     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
159     if (rc==DS_OK) {
160         trace("    Caps: size = %ld flags=0x%08lx buffer size=%ld\n",
161             dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes);
162     }
163
164     /* Query the format size. Note that it may not match sizeof(wfx) */
165     /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must be non-NULL */
166     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL);
167     ok(rc==DSERR_INVALIDPARAM,
168        "GetFormat should have returned an error: rc=0x%lx\n",rc);
169
170     size=0;
171     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size);
172     ok(rc==DS_OK && size!=0,
173        "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
174        rc,size);
175
176     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL);
177     ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
178     if (rc==DS_OK) {
179         trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
180               wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
181               wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
182     }
183
184     /* Private dsound.dll: Error: Invalid status pointer */
185     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0);
186     ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc);
187
188     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
189     ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
190     if (rc==DS_OK) {
191         trace("    status=0x%04lx\n",status);
192     }
193
194     ZeroMemory(&state, sizeof(state));
195     state.dscbo=dscbo;
196     state.wfx=&wfx;
197     state.buffer_size = dscbcaps.dwBufferBytes;
198     for (i = 0; i < NOTIFICATIONS; i++)
199         state.event[i] = CreateEvent( NULL, FALSE, FALSE, NULL );
200     state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS;
201
202     rc=IDirectSoundCaptureBuffer_QueryInterface(dscbo,&IID_IDirectSoundNotify,(void **)&(state.notify));
203     ok((rc==DS_OK)&&(state.notify!=NULL),"QueryInterface failed: 0x%lx\n",rc);
204     if (rc!=DS_OK)
205         return;
206
207     for (i = 0; i < NOTIFICATIONS; i++) {
208         state.posnotify[i].dwOffset = (i * state.size) + state.size - 1;
209         state.posnotify[i].hEventNotify = state.event[i];
210     }
211
212     rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS,state.posnotify);
213     ok(rc==DS_OK,"SetNotificationPositions failed: 0x%lx\n",rc);
214     if (rc!=DS_OK)
215         return;
216
217     rc=IDirectSoundNotify_Release(state.notify);
218     ok(rc==0,"Release: 0x%lx\n",rc);
219     if (rc!=0)
220         return;
221
222     if (record) {
223         rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING);
224         ok(rc==DS_OK,"Start: 0x%lx\n",rc);
225         if (rc!=DS_OK)
226             return;
227
228         rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
229         ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
230         ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING),
231            "GetStatus: bad status: %lx",status);
232         if (rc!=DS_OK)
233             return;
234
235         /* wait for the notifications */
236         for (i = 0; i < (NOTIFICATIONS * 2); i++) {
237             rc=MsgWaitForMultipleObjects( NOTIFICATIONS, state.event, FALSE, 3000, QS_ALLEVENTS );
238             ok(rc==(WAIT_OBJECT_0+(i%NOTIFICATIONS)),"MsgWaitForMultipleObjects failed: 0x%lx\n",rc);
239             if (rc!=(WAIT_OBJECT_0+(i%NOTIFICATIONS))) {
240                 ok((rc==WAIT_TIMEOUT)||(rc==WAIT_FAILED),"Wrong notification: should be %d, got %ld\n", 
241                     i%NOTIFICATIONS,rc-WAIT_OBJECT_0);
242             } else
243                 break;
244             if (!capture_buffer_service(&state))
245                 break;
246         }
247
248         rc=IDirectSoundCaptureBuffer_Stop(dscbo);
249         ok(rc==DS_OK,"Stop: 0x%lx\n",rc);
250         if (rc!=DS_OK)
251             return;
252     }
253 }
254
255 static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
256                                     LPCSTR lpcstrModule, LPVOID lpContext)
257 {
258     HRESULT rc;
259     LPDIRECTSOUNDCAPTURE dsco=NULL;
260     LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL;
261     DSCBUFFERDESC bufdesc;
262     WAVEFORMATEX wfx;
263     DSCCAPS dsccaps;
264     int f, ref;
265
266     /* Private dsound.dll: Error: Invalid interface buffer */
267     trace("Testing %s - %s\n",lpcstrDescription,lpcstrModule);
268     rc=DirectSoundCaptureCreate(lpGuid,NULL,NULL);
269     ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate didn't fail: 0x%lx\n",rc);
270     if (rc==DS_OK) {
271         ref=IDirectSoundCapture_Release(dsco);
272         ok(ref==0,"IDirectSoundCapture_Release has %d references, should have 0\n",ref);
273     }
274
275     rc=DirectSoundCaptureCreate(lpGuid,&dsco,NULL);
276     ok((rc==DS_OK)||(rc==DSERR_NODRIVER),"DirectSoundCaptureCreate failed: 0x%lx\n",rc);
277     if (rc!=DS_OK)
278         goto EXIT;
279
280     /* Private dsound.dll: Error: Invalid caps buffer */
281     rc=IDirectSoundCapture_GetCaps(dsco,NULL);
282     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
283
284     /* Private dsound.dll: Error: Invalid caps buffer */
285     dsccaps.dwSize=0;
286     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
287     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
288
289     dsccaps.dwSize=sizeof(dsccaps);
290     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
291     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
292     if (rc==DS_OK) {
293         trace("  DirectSoundCapture Caps: size=%ld flags=0x%08lx formats=%05lx channels=%ld\n",
294               dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats,dsccaps.dwChannels);
295     }
296
297     /* Private dsound.dll: Error: Invalid size */
298     /* Private dsound.dll: Error: Invalid capture buffer description */
299     ZeroMemory(&bufdesc, sizeof(bufdesc));
300     bufdesc.dwSize=0;
301     bufdesc.dwFlags=0;
302     bufdesc.dwBufferBytes=0;
303     bufdesc.dwReserved=0;
304     bufdesc.lpwfxFormat=NULL;
305     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
306     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
307     if (rc==DS_OK) {
308         ref=IDirectSoundCaptureBuffer_Release(dscbo);
309         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
310     }
311
312     /* Private dsound.dll: Error: Invalid buffer size */
313     /* Private dsound.dll: Error: Invalid capture buffer description */
314     ZeroMemory(&bufdesc, sizeof(bufdesc));
315     bufdesc.dwSize=sizeof(bufdesc);
316     bufdesc.dwFlags=0;
317     bufdesc.dwBufferBytes=0;
318     bufdesc.dwReserved=0;
319     bufdesc.lpwfxFormat=NULL;
320     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
321     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
322     if (rc==DS_OK) {
323         ref=IDirectSoundCaptureBuffer_Release(dscbo);
324         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
325     }
326
327     /* Private dsound.dll: Error: Invalid buffer size */
328     /* Private dsound.dll: Error: Invalid capture buffer description */
329     ZeroMemory(&bufdesc, sizeof(bufdesc));
330     ZeroMemory(&wfx, sizeof(wfx));
331     bufdesc.dwSize=sizeof(bufdesc);
332     bufdesc.dwFlags=0;
333     bufdesc.dwBufferBytes=0;
334     bufdesc.dwReserved=0;
335     bufdesc.lpwfxFormat=&wfx;
336     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
337     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
338     if (rc==DS_OK) {
339         ref=IDirectSoundCaptureBuffer_Release(dscbo);
340         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
341     }
342
343     /* Private dsound.dll: Error: Invalid buffer size */
344     /* Private dsound.dll: Error: Invalid capture buffer description */
345     init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1);
346     ZeroMemory(&bufdesc, sizeof(bufdesc));
347     bufdesc.dwSize=sizeof(bufdesc);
348     bufdesc.dwFlags=0;
349     bufdesc.dwBufferBytes=0;
350     bufdesc.dwReserved=0;
351     bufdesc.lpwfxFormat=&wfx;
352     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
353     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
354     if (rc==DS_OK) {
355         ref=IDirectSoundCaptureBuffer_Release(dscbo);
356         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
357     }
358
359     for (f=0;f<NB_FORMATS;f++) {
360         dscbo=NULL;
361         init_format(&wfx,WAVE_FORMAT_PCM,formats[f][0],formats[f][1],formats[f][2]);
362         ZeroMemory(&bufdesc, sizeof(bufdesc));
363         bufdesc.dwSize=sizeof(bufdesc);
364         bufdesc.dwFlags=0;
365         bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
366         bufdesc.dwReserved=0;
367         bufdesc.lpwfxFormat=&wfx;
368         trace("  Testing the capture buffer at %s\n", format_string(&wfx));
369         rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
370         ok((rc==DS_OK)&&(dscbo!=NULL),"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
371         if (rc==DS_OK) {
372             test_capture_buffer(dsco, dscbo, winetest_interactive);
373             ref=IDirectSoundCaptureBuffer_Release(dscbo);
374             ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
375         }
376     }
377
378     /* try a non PCM format */
379 #if 0
380     init_format(&wfx,WAVE_FORMAT_MULAW,8000,8,1);
381     ZeroMemory(&bufdesc, sizeof(bufdesc));
382     bufdesc.dwSize=sizeof(bufdesc);
383     bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
384     bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
385     bufdesc.dwReserved=0;
386     bufdesc.lpwfxFormat=&wfx;
387     trace("  Testing the capture buffer at %s\n", format_string(&wfx));
388     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
389     ok((rc==DS_OK)&&(dscbo!=NULL),"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
390     if ((rc==DS_OK)&&(dscbo!=NULL)) {
391         test_capture_buffer(dsco, dscbo, winetest_interactive);
392         ref=IDirectSoundCaptureBuffer_Release(dscbo);
393         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
394     }
395 #endif
396
397     /* Try an invalid format to test error handling */
398 #if 0
399     init_format(&wfx,WAVE_FORMAT_PCM,2000000,16,2);
400     ZeroMemory(&bufdesc, sizeof(bufdesc));
401     bufdesc.dwSize=sizeof(bufdesc);
402     bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
403     bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
404     bufdesc.dwReserved=0;
405     bufdesc.lpwfxFormat=&wfx;
406     trace("  Testing the capture buffer at %s\n", format_string(&wfx));
407     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
408     ok(rc!=DS_OK,"CreateCaptureBuffer should have failed at 2 MHz 0x%lx\n",rc);
409 #endif
410
411 EXIT:
412     if (dsco!=NULL) {
413         ref=IDirectSoundCapture_Release(dsco);
414         ok(ref==0,"IDirectSoundCapture_Release has %d references, should have 0\n",ref);
415     }
416
417     return TRUE;
418 }
419
420 static void capture_tests()
421 {
422     HRESULT rc;
423     rc=DirectSoundCaptureEnumerateA(&dscenum_callback,NULL);
424     ok(rc==DS_OK,"DirectSoundCaptureEnumerate failed: %ld\n",rc);
425 }
426
427 START_TEST(capture)
428 {
429     capture_tests();
430 }