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