Release 20030408.
[wine/gsoc-2012-control.git] / dlls / dsound / tests / dsound.c
blobfd51d86290ef04e3010f51f77cf952c73d694c97
1 /*
2 * Unit tests for dsound functions
4 * Copyright (c) 2002 Francois Gouget
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.
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.
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
21 #include <math.h>
22 #include <stdlib.h>
24 #include "wine/test.h"
25 #include "wine/debug.h"
27 #include "objbase.h"
28 #include "initguid.h"
29 #include "dsound.h"
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}
57 #define NB_FORMATS (sizeof(formats)/sizeof(*formats))
59 /* The time slice determines how often we will service the buffer and the
60 * buffer will be four time slices long
62 #define TIME_SLICE 100
63 #define BUFFER_LEN (4*TIME_SLICE)
64 #define TONE_DURATION (6*TIME_SLICE)
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.
71 #define PI 3.14159265358979323846
72 static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
74 int i;
75 int nb_samples;
76 char* buf;
77 char* b;
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;
101 return buf;
104 static HWND get_hwnd()
106 HWND hwnd=GetForegroundWindow();
107 if (!hwnd)
108 hwnd=GetDesktopWindow();
109 return hwnd;
112 static void init_format(WAVEFORMATEX* wfx, int rate, int depth, int channels)
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;
123 typedef struct {
124 char* wave;
125 DWORD wave_len;
127 LPDIRECTSOUNDBUFFER dsbo;
128 LPWAVEFORMATEX wfx;
129 DWORD buffer_size;
130 DWORD written;
131 DWORD offset;
133 DWORD last_pos;
134 } play_state_t;
136 static int buffer_refill(play_state_t* state, DWORD size)
138 LPVOID ptr1,ptr2;
139 DWORD len1,len2;
140 HRESULT rc;
142 if (size>state->wave_len-state->written)
143 size=state->wave_len-state->written;
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;
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;
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;
165 static int buffer_silence(play_state_t* state, DWORD size)
167 LPVOID ptr1,ptr2;
168 DWORD len1,len2;
169 HRESULT rc;
170 BYTE s;
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;
178 s=(state->wfx->wBitsPerSample==8?0x80:0);
179 memset(ptr1,s,len1);
180 if (ptr2!=NULL) {
181 memset(ptr2,s,len2);
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;
191 static int buffer_service(play_state_t* state)
193 DWORD play_pos,write_pos,buf_free;
194 HRESULT rc;
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;
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;
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;
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));
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;
230 if (state->last_pos==0 &&
231 play_pos>(state->written % state->buffer_size)) {
232 /* Now everything has been played */
233 goto STOP;
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;
244 return 1;
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;
254 static void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo,
255 int primary, int play)
257 HRESULT rc;
258 DSBCAPS dsbcaps;
259 WAVEFORMATEX wfx,wfx2;
260 DWORD size,status,freq;
262 dsbcaps.dwSize=0;
263 rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
264 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
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);
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);
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);
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);
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);
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;
310 init_format(&wfx2,11025,16,2);
311 rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2);
312 ok(rc==DS_OK,"SetFormat failed: 0x%lx\n",rc);
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.
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);
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);
331 if (play) {
332 play_state_t state;
333 LONG volume;
335 trace(" Playing 440Hz LA at %ldx%2dx%d\n",
336 wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels);
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;
346 if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
347 rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
348 ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc);
350 rc=IDirectSoundBuffer_SetVolume(dsbo,-300);
351 ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
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);
359 state.wave=wave_generate_la(&wfx,((double)TONE_DURATION)/1000,&state.wave_len);
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);
367 rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING);
368 ok(rc==DS_OK,"Play: 0x%lx\n",rc);
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);
375 while (buffer_service(&state)) {
376 WaitForSingleObject(GetCurrentProcess(),TIME_SLICE/2);
379 if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
380 rc=IDirectSoundBuffer_SetVolume(dsbo,volume);
381 ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
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);
393 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
394 LPCSTR lpcstrModule, LPVOID lpContext)
396 HRESULT rc;
397 LPDIRECTSOUND dso=NULL;
398 LPDIRECTSOUNDBUFFER dsbo=NULL;
399 DSBUFFERDESC bufdesc;
400 WAVEFORMATEX wfx;
401 DSCAPS dscaps;
402 int f;
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;
410 dscaps.dwSize=0;
411 rc=IDirectSound_GetCaps(dso,&dscaps);
412 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
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);
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;
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);
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;
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);
467 EXIT:
468 if (dso!=NULL)
469 IDirectSound_Release(dso);
470 return 1;
473 static void dsound_out_tests()
475 HRESULT rc;
476 rc=DirectSoundEnumerateA(&dsenum_callback,NULL);
477 ok(rc==DS_OK,"DirectSoundEnumerate failed: %ld\n",rc);
480 #define NOTIFICATIONS 5
482 typedef struct {
483 char* wave;
484 DWORD wave_len;
486 LPDIRECTSOUNDCAPTUREBUFFER dscbo;
487 LPWAVEFORMATEX wfx;
488 DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS];
489 HANDLE event;
490 LPDIRECTSOUNDNOTIFY notify;
492 DWORD buffer_size;
493 DWORD read;
494 DWORD offset;
495 DWORD size;
497 DWORD last_pos;
498 } capture_state_t;
500 static int capture_buffer_service(capture_state_t* state)
502 HRESULT rc;
503 LPVOID ptr1,ptr2;
504 DWORD len1,len2;
505 DWORD capture_pos,read_pos;
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;
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;
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;
522 state->offset = (state->offset + state->size) % state->buffer_size;
524 return 1;
527 static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, LPDIRECTSOUNDCAPTUREBUFFER dscbo)
529 HRESULT rc;
530 DSCBCAPS dscbcaps;
531 WAVEFORMATEX wfx;
532 DWORD size,status;
533 capture_state_t state;
534 int i;
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);
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);
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);
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);
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);
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);
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);
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);
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;
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;
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;
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;
605 rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING);
606 ok(rc==DS_OK,"Start: 0x%lx\n",rc);
607 if (rc!=DS_OK)
608 return;
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;
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;
627 rc=IDirectSoundCaptureBuffer_Stop(dscbo);
628 ok(rc==DS_OK,"Stop: 0x%lx\n",rc);
629 if (rc!=DS_OK)
630 return;
632 rc=IDirectSoundNotify_Release(state.notify);
633 ok(rc==0,"Release: 0x%lx\n",rc);
634 if (rc!=0)
635 return;
638 static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
639 LPCSTR lpcstrModule, LPVOID lpContext)
641 HRESULT rc;
642 LPDIRECTSOUNDCAPTURE dsco=NULL;
643 LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL;
644 DSCBUFFERDESC bufdesc;
645 WAVEFORMATEX wfx;
646 DSCCAPS dsccaps;
647 int f;
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);
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;
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);
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);
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);
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);
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);
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);
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);
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);
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
769 EXIT:
770 if (dsco!=NULL)
771 IDirectSoundCapture_Release(dsco);
773 return TRUE;
776 static void dsound_in_tests()
778 HRESULT rc;
779 rc=DirectSoundCaptureEnumerateA(&dscenum_callback,NULL);
780 ok(rc==DS_OK,"DirectSoundCaptureEnumerate failed: %ld\n",rc);
783 START_TEST(dsound)
785 dsound_out_tests();
786 dsound_in_tests();