Align data to proper size.
[wine] / dlls / dsound / tests / dsound.c
1 /*
2  * Unit tests for dsound functions
3  *
4  * Copyright (c) 2002 Francois Gouget
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <math.h>
22 #include <stdlib.h>
23
24 #include "wine/test.h"
25 #include "wine/debug.h"
26
27 #include "objbase.h"
28 #include "initguid.h"
29 #include "dsound.h"
30
31 static const unsigned int formats[][3]={
32     { 8000,  8, 1},
33     { 8000,  8, 2},
34     { 8000, 16, 1},
35     { 8000, 16, 2},
36     {11025,  8, 1},
37     {11025,  8, 2},
38     {11025, 16, 1},
39     {11025, 16, 2},
40     {22050,  8, 1},
41     {22050,  8, 2},
42     {22050, 16, 1},
43     {22050, 16, 2},
44     {44100,  8, 1},
45     {44100,  8, 2},
46     {44100, 16, 1},
47     {44100, 16, 2},
48     {48000,  8, 1},
49     {48000,  8, 2},
50     {48000, 16, 1},
51     {48000, 16, 2},
52     {96000,  8, 1},
53     {96000,  8, 2},
54     {96000, 16, 1},
55     {96000, 16, 2}
56 };
57 #define NB_FORMATS (sizeof(formats)/sizeof(*formats))
58
59 /* The time slice determines how often we will service the buffer and the
60  * buffer will be four time slices long
61  */
62 #define TIME_SLICE    100
63 #define BUFFER_LEN    (4*TIME_SLICE)
64 #define TONE_DURATION (6*TIME_SLICE)
65
66 /* This test can play a test tone. But this only makes sense if someone
67  * is going to carefully listen to it, and would only bother everyone else.
68  * So this is only done if the test is being run in interactive mode.
69  */
70
71 #define PI 3.14159265358979323846
72 static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
73 {
74     int i;
75     int nb_samples;
76     char* buf;
77     char* b;
78
79     nb_samples=(int)(duration*wfx->nSamplesPerSec);
80     *size=nb_samples*wfx->nBlockAlign;
81     b=buf=malloc(*size);
82     for (i=0;i<nb_samples;i++) {
83         double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
84         if (wfx->wBitsPerSample==8) {
85             unsigned char sample=(unsigned char)((double)127.5*(y+1.0));
86             *b++=sample;
87             if (wfx->nChannels==2)
88                *b++=sample;
89         } else {
90             signed short sample=(signed short)((double)32767.5*y-0.5);
91             b[0]=sample & 0xff;
92             b[1]=sample >> 8;
93             b+=2;
94             if (wfx->nChannels==2) {
95                 b[0]=sample & 0xff;
96                 b[1]=sample >> 8;
97                 b+=2;
98             }
99         }
100     }
101     return buf;
102 }
103
104 static HWND get_hwnd()
105 {
106     HWND hwnd=GetForegroundWindow();
107     if (!hwnd)
108         hwnd=GetDesktopWindow();
109     return hwnd;
110 }
111
112 static void init_format(WAVEFORMATEX* wfx, int rate, int depth, int channels)
113 {
114     wfx->wFormatTag=WAVE_FORMAT_PCM;
115     wfx->nChannels=channels;
116     wfx->wBitsPerSample=depth;
117     wfx->nSamplesPerSec=rate;
118     wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
119     wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
120     wfx->cbSize=0;
121 }
122
123 typedef struct {
124     char* wave;
125     DWORD wave_len;
126
127     LPDIRECTSOUNDBUFFER dsbo;
128     LPWAVEFORMATEX wfx;
129     DWORD buffer_size;
130     DWORD written;
131     DWORD offset;
132
133     DWORD last_pos;
134 } play_state_t;
135
136 static int buffer_refill(play_state_t* state, DWORD size)
137 {
138     LPVOID ptr1,ptr2;
139     DWORD len1,len2;
140     HRESULT rc;
141
142     if (size>state->wave_len-state->written)
143         size=state->wave_len-state->written;
144
145     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
146                                &ptr1,&len1,&ptr2,&len2,0);
147     ok(rc==DS_OK,"Lock: 0x%lx",rc);
148     if (rc!=DS_OK)
149         return -1;
150
151     memcpy(ptr1,state->wave+state->written,len1);
152     state->written+=len1;
153     if (ptr2!=NULL) {
154         memcpy(ptr2,state->wave+state->written,len2);
155         state->written+=len2;
156     }
157     state->offset=state->written % state->buffer_size;
158     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
159     ok(rc==DS_OK,"Unlock: 0x%lx",rc);
160     if (rc!=DS_OK)
161         return -1;
162     return size;
163 }
164
165 static int buffer_silence(play_state_t* state, DWORD size)
166 {
167     LPVOID ptr1,ptr2;
168     DWORD len1,len2;
169     HRESULT rc;
170     BYTE s;
171
172     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
173                                &ptr1,&len1,&ptr2,&len2,0);
174     ok(rc==DS_OK,"Lock: 0x%lx",rc);
175     if (rc!=DS_OK)
176         return -1;
177
178     s=(state->wfx->wBitsPerSample==8?0x80:0);
179     memset(ptr1,s,len1);
180     if (ptr2!=NULL) {
181         memset(ptr2,s,len2);
182     }
183     state->offset=(state->offset+size) % state->buffer_size;
184     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
185     ok(rc==DS_OK,"Unlock: 0x%lx",rc);
186     if (rc!=DS_OK)
187         return -1;
188     return size;
189 }
190
191 static int buffer_service(play_state_t* state)
192 {
193     DWORD play_pos,write_pos,buf_free;
194     HRESULT rc;
195
196     rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,&write_pos);
197     ok(rc==DS_OK,"GetCurrentPosition: %lx",rc);
198     if (rc!=DS_OK) {
199         goto STOP;
200     }
201
202     /* Refill the buffer */
203     if (state->offset<=play_pos) {
204         buf_free=play_pos-state->offset;
205     } else {
206         buf_free=state->buffer_size-state->offset+play_pos;
207     }
208     if (winetest_debug > 1)
209         trace("buf pos=%ld free=%ld written=%ld / %ld\n",
210               play_pos,buf_free,state->written,state->wave_len);
211     if (buf_free==0)
212         return 1;
213
214     if (state->written<state->wave_len) {
215         int w=buffer_refill(state,buf_free);
216         if (w==-1)
217             goto STOP;
218         buf_free-=w;
219         if (state->written==state->wave_len) {
220             state->last_pos=(state->offset<play_pos)?play_pos:0;
221             if (winetest_debug > 1)
222                 trace("last sound byte at %ld\n",
223                       (state->written % state->buffer_size));
224         }
225     } else {
226         if (state->last_pos!=0 && play_pos<state->last_pos) {
227             /* We wrapped around the end of the buffer */
228             state->last_pos=0;
229         }
230         if (state->last_pos==0 &&
231             play_pos>(state->written % state->buffer_size)) {
232             /* Now everything has been played */
233             goto STOP;
234         }
235     }
236
237     if (buf_free>0) {
238         /* Fill with silence */
239         if (winetest_debug > 1)
240             trace("writing %ld bytes of silence\n",buf_free);
241         if (buffer_silence(state,buf_free)==-1)
242             goto STOP;
243     }
244     return 1;
245
246 STOP:
247     if (winetest_debug > 1)
248         trace("stopping playback\n");
249     rc=IDirectSoundBuffer_Stop(state->dsbo);
250     ok(rc==DS_OK,"Stop failed: rc=%ld",rc);
251     return 0;
252 }
253
254 static void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo,
255                         int primary, int play)
256 {
257     HRESULT rc;
258     DSBCAPS dsbcaps;
259     WAVEFORMATEX wfx,wfx2;
260     DWORD size,status,freq;
261
262     dsbcaps.dwSize=0;
263     rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
264     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
265
266     dsbcaps.dwSize=sizeof(dsbcaps);
267     rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
268     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
269     if (rc==DS_OK) {
270         trace("    Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags,
271               dsbcaps.dwBufferBytes);
272     }
273
274     /* Query the format size. Note that it may not match sizeof(wfx) */
275     size=0;
276     rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size);
277     ok(rc==DS_OK && size!=0,
278        "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
279        rc,size);
280
281     rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
282     ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
283     if (rc==DS_OK) {
284         trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
285               wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
286               wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
287     }
288
289     rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq);
290     ok(rc==DS_OK || rc==DSERR_CONTROLUNAVAIL,"GetFrequency failed: 0x%lx\n",rc);
291     if (rc==DS_OK) {
292         ok(freq==wfx.nSamplesPerSec,
293            "The frequency returned by GetFrequency %ld does not match the format %ld\n",
294            freq,wfx.nSamplesPerSec);
295     }
296
297     rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
298     ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
299     if (rc==DS_OK) {
300         trace("    status=0x%04lx\n",status);
301     }
302
303     if (primary) {
304         /* We must call SetCooperativeLevel to be allowed to call SetFormat */
305         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
306         ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
307         if (rc!=DS_OK)
308             return;
309
310         init_format(&wfx2,11025,16,2);
311         rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2);
312         ok(rc==DS_OK,"SetFormat failed: 0x%lx\n",rc);
313
314         /* There is no garantee that SetFormat will actually change the
315          * format to what we asked for. It depends on what the soundcard
316          * supports. So we must re-query the format.
317          */
318         rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
319         ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
320         if (rc==DS_OK) {
321             trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
322                   wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
323                   wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
324     }
325
326         /* Set the CooperativeLevel back to normal */
327         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
328         ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
329     }
330
331     if (play) {
332         play_state_t state;
333         LONG volume;
334
335         trace("    Playing 440Hz LA at %ldx%2dx%d\n",
336               wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels);
337
338         if (primary) {
339             /* We must call SetCooperativeLevel to be allowed to call Lock */
340             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_WRITEPRIMARY);
341             ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
342             if (rc!=DS_OK)
343                 return;
344         }
345
346         if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
347             rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
348             ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc);
349
350             rc=IDirectSoundBuffer_SetVolume(dsbo,-300);
351             ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
352         }
353         rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
354         ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc);
355         if (rc==DS_OK) {
356             trace("    volume=%ld\n",volume);
357         }
358
359         state.wave=wave_generate_la(&wfx,((double)TONE_DURATION)/1000,&state.wave_len);
360
361         state.dsbo=dsbo;
362         state.wfx=&wfx;
363         state.buffer_size=dsbcaps.dwBufferBytes;
364         state.written=state.offset=0;
365         buffer_refill(&state,state.buffer_size);
366
367         rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING);
368         ok(rc==DS_OK,"Play: 0x%lx\n",rc);
369
370         rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
371         ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
372         ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
373            "GetStatus: bad status: %lx",status);
374
375         while (buffer_service(&state)) {
376             WaitForSingleObject(GetCurrentProcess(),TIME_SLICE/2);
377         }
378
379         if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
380             rc=IDirectSoundBuffer_SetVolume(dsbo,volume);
381             ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
382         }
383
384         free(state.wave);
385         if (primary) {
386             /* Set the CooperativeLevel back to normal */
387             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
388             ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
389         }
390     }
391 }
392
393 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
394                                    LPCSTR lpcstrModule, LPVOID lpContext)
395 {
396     HRESULT rc;
397     LPDIRECTSOUND dso=NULL;
398     LPDIRECTSOUNDBUFFER dsbo=NULL;
399     DSBUFFERDESC bufdesc;
400     WAVEFORMATEX wfx;
401     DSCAPS dscaps;
402     int f;
403
404     trace("Testing %s - %s : %s\n",lpcstrDescription,lpcstrModule,wine_dbgstr_guid(lpGuid));
405     rc=DirectSoundCreate(lpGuid,&dso,NULL);
406     ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
407     if (rc!=DS_OK)
408         goto EXIT;
409
410     dscaps.dwSize=0;
411     rc=IDirectSound_GetCaps(dso,&dscaps);
412     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
413
414     dscaps.dwSize=sizeof(dscaps);
415     rc=IDirectSound_GetCaps(dso,&dscaps);
416     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
417     if (rc==DS_OK) {
418         trace("  DirectSound Caps: flags=0x%08lx secondary min=%ld max=%ld\n",
419               dscaps.dwFlags,dscaps.dwMinSecondarySampleRate,
420               dscaps.dwMaxSecondarySampleRate);
421     }
422
423     /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
424     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
425     ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
426     if (rc!=DS_OK)
427         goto EXIT;
428
429     /* Testing the primary buffer */
430     bufdesc.dwSize=sizeof(bufdesc);
431     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
432     bufdesc.dwBufferBytes=0;
433     bufdesc.dwReserved=0;
434     bufdesc.lpwfxFormat=NULL;
435     trace("  Testing the primary buffer\n");
436     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&dsbo,NULL);
437     ok(rc==DS_OK,"CreateSoundBuffer failed to create a primary buffer 0x%lx\n",rc);
438     if (rc==DS_OK) {
439         test_buffer(dso,dsbo,1,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER));
440         IDirectSoundBuffer_Release(dsbo);
441     }
442
443     /* Set the CooperativeLevel back to normal */
444     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
445     ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
446     if (rc!=DS_OK)
447         goto EXIT;
448
449     /* Testing secondary buffers */
450     for (f=0;f<NB_FORMATS;f++) {
451         init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
452         bufdesc.dwSize=sizeof(bufdesc);
453         bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2;
454         bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
455         bufdesc.dwReserved=0;
456         bufdesc.lpwfxFormat=&wfx;
457         trace("  Testing a secondary buffer at %ldx%dx%d\n",
458             wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
459         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&dsbo,NULL);
460         ok(rc==DS_OK,"CreateSoundBuffer failed to create a secondary buffer 0x%lx\n",rc);
461         if (rc==DS_OK) {
462             test_buffer(dso,dsbo,0,winetest_interactive);
463             IDirectSoundBuffer_Release(dsbo);
464         }
465     }
466
467 EXIT:
468     if (dso!=NULL)
469         IDirectSound_Release(dso);
470     return 1;
471 }
472
473 static void dsound_out_tests()
474 {
475     HRESULT rc;
476     rc=DirectSoundEnumerateA(&dsenum_callback,NULL);
477     ok(rc==DS_OK,"DirectSoundEnumerate failed: %ld\n",rc);
478 }
479
480 #define NOTIFICATIONS    5
481
482 typedef struct {
483     char* wave;
484     DWORD wave_len;
485
486     LPDIRECTSOUNDCAPTUREBUFFER dscbo;
487     LPWAVEFORMATEX wfx;
488     DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS];
489     HANDLE event;
490     LPDIRECTSOUNDNOTIFY notify;
491
492     DWORD buffer_size;
493     DWORD read;
494     DWORD offset;
495     DWORD size;
496
497     DWORD last_pos;
498 } capture_state_t;
499
500 static int capture_buffer_service(capture_state_t* state)
501 {
502     HRESULT rc;
503     LPVOID ptr1,ptr2;
504     DWORD len1,len2;
505     DWORD capture_pos,read_pos;
506
507     rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos,&read_pos);
508     ok(rc==DS_OK,"GetCurrentPosition failed: 0x%lx\n",rc);
509     if (rc!=DS_OK)
510         return 0;
511
512     rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size,&ptr1,&len1,&ptr2,&len2,0);
513     ok(rc==DS_OK,"Lock failed: 0x%lx\n",rc);
514     if (rc!=DS_OK)
515         return 0;
516
517     rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2);
518     ok(rc==DS_OK,"Unlock failed: 0x%lx\n",rc);
519     if (rc!=DS_OK)
520         return 0;
521
522     state->offset = (state->offset + state->size) % state->buffer_size;
523
524     return 1;
525 }
526
527 static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, LPDIRECTSOUNDCAPTUREBUFFER dscbo)
528 {
529     HRESULT rc;
530     DSCBCAPS dscbcaps;
531     WAVEFORMATEX wfx;
532     DWORD size,status;
533     capture_state_t state;
534     int i;
535
536     /* Private dsound.dll: Error: Invalid caps pointer */
537     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0);
538     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
539
540     /* Private dsound.dll: Error: Invalid caps pointer */
541     dscbcaps.dwSize=0;
542     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
543     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
544
545     dscbcaps.dwSize=sizeof(dscbcaps);
546     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
547     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
548     if (rc==DS_OK) {
549         trace("    Caps: size = %ld flags=0x%08lx buffer size=%ld\n",
550             dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes);
551     }
552
553     /* Query the format size. Note that it may not match sizeof(wfx) */
554     /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must be non-NULL */
555     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL);
556     ok(rc==DSERR_INVALIDPARAM,
557        "GetFormat should have returned an error: rc=0x%lx\n",rc);
558
559     size=0;
560     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size);
561     ok(rc==DS_OK && size!=0,
562        "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
563        rc,size);
564
565     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL);
566     ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
567     if (rc==DS_OK) {
568         trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
569               wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
570               wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
571     }
572
573     /* Private dsound.dll: Error: Invalid status pointer */
574     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0);
575     ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc);
576
577     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
578     ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
579     if (rc==DS_OK) {
580         trace("    status=0x%04lx\n",status);
581     }
582
583     ZeroMemory(&state, sizeof(state));
584     state.dscbo=dscbo;
585     state.wfx=&wfx;
586     state.buffer_size = dscbcaps.dwBufferBytes;
587     state.event = CreateEvent( NULL, FALSE, FALSE, NULL );
588     state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS;
589
590     rc=IDirectSoundCapture_QueryInterface(dscbo,&IID_IDirectSoundNotify,(void **)&(state.notify));
591     ok(rc==DS_OK,"QueryInterface failed: 0x%lx\n",rc);
592     if (rc!=DS_OK)
593         return;
594
595     for (i = 0; i < NOTIFICATIONS; i++) {
596         state.posnotify[i].dwOffset = (i * state.size) + state.size - 1;
597         state.posnotify[i].hEventNotify = state.event;
598     }
599
600     rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS,state.posnotify);
601     ok(rc==DS_OK,"SetNotificationPositions failed: 0x%lx\n",rc);
602     if (rc!=DS_OK)
603         return;
604
605     rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING);
606     ok(rc==DS_OK,"Start: 0x%lx\n",rc);
607     if (rc!=DS_OK)
608         return;
609
610     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
611     ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
612     ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING),
613        "GetStatus: bad status: %lx",status);
614     if (rc!=DS_OK)
615         return;
616
617     /* wait for the notifications */
618     for (i = 0; i < (NOTIFICATIONS * 2); i++) {
619         rc=MsgWaitForMultipleObjects( 1, &(state.event), FALSE, 1000, QS_ALLEVENTS );
620         ok(rc==WAIT_OBJECT_0,"MsgWaitForMultipleObjects failed: 0x%lx\n",rc);
621         if (rc!=WAIT_OBJECT_0)
622             break;
623         if (!capture_buffer_service(&state))
624             break;
625     }
626
627     rc=IDirectSoundCaptureBuffer_Stop(dscbo);
628     ok(rc==DS_OK,"Stop: 0x%lx\n",rc);
629     if (rc!=DS_OK)
630         return;
631
632     rc=IDirectSoundNotify_Release(state.notify);
633     ok(rc==0,"Release: 0x%lx\n",rc);
634     if (rc!=0)
635         return;
636 }
637
638 static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
639                                     LPCSTR lpcstrModule, LPVOID lpContext)
640 {
641     HRESULT rc;
642     LPDIRECTSOUNDCAPTURE dsco=NULL;
643     LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL;
644     DSCBUFFERDESC bufdesc;
645     WAVEFORMATEX wfx;
646     DSCCAPS dsccaps;
647     int f;
648
649     /* Private dsound.dll: Error: Invalid interface buffer */
650     trace("Testing %s - %s : %s\n",lpcstrDescription,lpcstrModule,wine_dbgstr_guid(lpGuid));
651     rc=DirectSoundCaptureCreate(lpGuid,NULL,NULL);
652     ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate didn't fail: 0x%lx\n",rc);
653     if (rc==DS_OK)
654         IDirectSoundCapture_Release(dsco);
655
656     rc=DirectSoundCaptureCreate(lpGuid,&dsco,NULL);
657     ok((rc==DS_OK)||(rc==DSERR_NODRIVER),"DirectSoundCaptureCreate failed: 0x%lx\n",rc);
658     if (rc!=DS_OK)
659         goto EXIT;
660
661     /* Private dsound.dll: Error: Invalid caps buffer */
662     rc=IDirectSoundCapture_GetCaps(dsco,NULL);
663     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
664
665     /* Private dsound.dll: Error: Invalid caps buffer */
666     dsccaps.dwSize=0;
667     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
668     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
669
670     dsccaps.dwSize=sizeof(dsccaps);
671     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
672     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
673     if (rc==DS_OK) {
674         trace("  DirectSoundCapture Caps: size=%ld flags=0x%08lx formats=%ld channels=%ld\n",
675               dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats,dsccaps.dwChannels);
676     }
677
678     /* Private dsound.dll: Error: Invalid size */
679     /* Private dsound.dll: Error: Invalid capture buffer description */
680     ZeroMemory(&bufdesc, sizeof(bufdesc));
681     bufdesc.dwSize=0;
682     bufdesc.dwFlags=0;
683     bufdesc.dwBufferBytes=0;
684     bufdesc.dwReserved=0;
685     bufdesc.lpwfxFormat=NULL;
686     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
687     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
688     if (rc==DS_OK) {
689         IDirectSoundCaptureBuffer_Release(dscbo);
690     }
691
692     /* Private dsound.dll: Error: Invalid buffer size */
693     /* Private dsound.dll: Error: Invalid capture buffer description */
694     ZeroMemory(&bufdesc, sizeof(bufdesc));
695     bufdesc.dwSize=sizeof(bufdesc);
696     bufdesc.dwFlags=0;
697     bufdesc.dwBufferBytes=0;
698     bufdesc.dwReserved=0;
699     bufdesc.lpwfxFormat=NULL;
700     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
701     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
702     if (rc==DS_OK) {
703         IDirectSoundCaptureBuffer_Release(dscbo);
704     }
705
706     /* Private dsound.dll: Error: Invalid buffer size */
707     /* Private dsound.dll: Error: Invalid capture buffer description */
708     ZeroMemory(&bufdesc, sizeof(bufdesc));
709     ZeroMemory(&wfx, sizeof(wfx));
710     bufdesc.dwSize=sizeof(bufdesc);
711     bufdesc.dwFlags=0;
712     bufdesc.dwBufferBytes=0;
713     bufdesc.dwReserved=0;
714     bufdesc.lpwfxFormat=&wfx;
715     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
716     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
717     if (rc==DS_OK) {
718         IDirectSoundCaptureBuffer_Release(dscbo);
719     }
720
721     /* Private dsound.dll: Error: Invalid buffer size */
722     /* Private dsound.dll: Error: Invalid capture buffer description */
723     init_format(&wfx,11025,8,1);
724     ZeroMemory(&bufdesc, sizeof(bufdesc));
725     bufdesc.dwSize=sizeof(bufdesc);
726     bufdesc.dwFlags=0;
727     bufdesc.dwBufferBytes=0;
728     bufdesc.dwReserved=0;
729     bufdesc.lpwfxFormat=&wfx;
730     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
731     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
732     if (rc==DS_OK) {
733         IDirectSoundCaptureBuffer_Release(dscbo);
734     }
735
736     for (f=0;f<NB_FORMATS;f++) {
737         init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
738         ZeroMemory(&bufdesc, sizeof(bufdesc));
739         bufdesc.dwSize=sizeof(bufdesc);
740         bufdesc.dwFlags=0;
741         bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
742         bufdesc.dwReserved=0;
743         bufdesc.lpwfxFormat=&wfx;
744         trace("  Testing the capture buffer at %ldx%dx%d\n",
745             wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
746         rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
747         ok(rc==DS_OK,"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
748         if (rc==DS_OK) {
749             test_capture_buffer(dsco, dscbo);
750             IDirectSoundCaptureBuffer_Release(dscbo);
751         }
752     }
753
754     /* Try an invalid format to test error handling */
755 #if 0
756     init_format(&wfx,2000000,16,2);
757     ZeroMemory(&bufdesc, sizeof(bufdesc));
758     bufdesc.dwSize=sizeof(bufdesc);
759     bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
760     bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
761     bufdesc.dwReserved=0;
762     bufdesc.lpwfxFormat=&wfx;
763     trace("  Testing the capture buffer at %ldx%dx%d\n",
764         wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
765     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
766     ok(rc!=DS_OK,"CreateCaptureBuffer should have failed at 2 MHz 0x%lx\n",rc);
767 #endif
768
769 EXIT:
770     if (dsco!=NULL)
771         IDirectSoundCapture_Release(dsco);
772
773     return TRUE;
774 }
775
776 static void dsound_in_tests()
777 {
778     HRESULT rc;
779     rc=DirectSoundCaptureEnumerateA(&dscenum_callback,NULL);
780     ok(rc==DS_OK,"DirectSoundCaptureEnumerate failed: %ld\n",rc);
781 }
782
783 START_TEST(dsound)
784 {
785     dsound_out_tests();
786     dsound_in_tests();
787 }