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