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