3D buffer and listener reference counts should be fixed.
[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 #define NONAMELESSSTRUCT
22 #define NONAMELESSUNION
23 #include <windows.h>
24
25 #include <math.h>
26 #include <stdlib.h>
27
28 #include "wine/test.h"
29 #include "objbase.h"
30 #include "initguid.h"
31 #include "dsound.h"
32
33 #ifndef DSBCAPS_CTRLDEFAULT
34 #define DSBCAPS_CTRLDEFAULT      0x000000E0
35 #endif
36
37 static const unsigned int formats[][3]={
38     { 8000,  8, 1},
39     { 8000,  8, 2},
40     { 8000, 16, 1},
41     { 8000, 16, 2},
42     {11025,  8, 1},
43     {11025,  8, 2},
44     {11025, 16, 1},
45     {11025, 16, 2},
46     {22050,  8, 1},
47     {22050,  8, 2},
48     {22050, 16, 1},
49     {22050, 16, 2},
50     {44100,  8, 1},
51     {44100,  8, 2},
52     {44100, 16, 1},
53     {44100, 16, 2},
54     {48000,  8, 1},
55     {48000,  8, 2},
56     {48000, 16, 1},
57     {48000, 16, 2},
58     {96000,  8, 1},
59     {96000,  8, 2},
60     {96000, 16, 1},
61     {96000, 16, 2}
62 };
63 #define NB_FORMATS (sizeof(formats)/sizeof(*formats))
64
65 /* The time slice determines how often we will service the buffer and the
66  * buffer will be four time slices long
67  */
68 #define TIME_SLICE    100
69 #define BUFFER_LEN    (4*TIME_SLICE)
70 #define TONE_DURATION (6*TIME_SLICE)
71
72 /* This test can play a test tone. But this only makes sense if someone
73  * is going to carefully listen to it, and would only bother everyone else.
74  * So this is only done if the test is being run in interactive mode.
75  */
76
77 #define PI 3.14159265358979323846
78 static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
79 {
80     int i;
81     int nb_samples;
82     char* buf;
83     char* b;
84
85     nb_samples=(int)(duration*wfx->nSamplesPerSec);
86     *size=nb_samples*wfx->nBlockAlign;
87     b=buf=malloc(*size);
88     for (i=0;i<nb_samples;i++) {
89         double y=sin(440.0*2*PI*i/wfx->nSamplesPerSec);
90         if (wfx->wBitsPerSample==8) {
91             unsigned char sample=(unsigned char)((double)127.5*(y+1.0));
92             *b++=sample;
93             if (wfx->nChannels==2)
94                *b++=sample;
95         } else {
96             signed short sample=(signed short)((double)32767.5*y-0.5);
97             b[0]=sample & 0xff;
98             b[1]=sample >> 8;
99             b+=2;
100             if (wfx->nChannels==2) {
101                 b[0]=sample & 0xff;
102                 b[1]=sample >> 8;
103                 b+=2;
104             }
105         }
106     }
107     return buf;
108 }
109
110 static HWND get_hwnd()
111 {
112     HWND hwnd=GetForegroundWindow();
113     if (!hwnd)
114         hwnd=GetDesktopWindow();
115     return hwnd;
116 }
117
118 static void init_format(WAVEFORMATEX* wfx, int rate, int depth, int channels)
119 {
120     wfx->wFormatTag=WAVE_FORMAT_PCM;
121     wfx->nChannels=channels;
122     wfx->wBitsPerSample=depth;
123     wfx->nSamplesPerSec=rate;
124     wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
125     wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
126     wfx->cbSize=0;
127 }
128
129 typedef struct {
130     char* wave;
131     DWORD wave_len;
132
133     LPDIRECTSOUNDBUFFER dsbo;
134     LPWAVEFORMATEX wfx;
135     DWORD buffer_size;
136     DWORD written;
137     DWORD offset;
138
139     DWORD last_pos;
140 } play_state_t;
141
142 static int buffer_refill(play_state_t* state, DWORD size)
143 {
144     LPVOID ptr1,ptr2;
145     DWORD len1,len2;
146     HRESULT rc;
147
148     if (size>state->wave_len-state->written)
149         size=state->wave_len-state->written;
150
151     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
152                                &ptr1,&len1,&ptr2,&len2,0);
153     ok(rc==DS_OK,"Lock: 0x%lx",rc);
154     if (rc!=DS_OK)
155         return -1;
156
157     memcpy(ptr1,state->wave+state->written,len1);
158     state->written+=len1;
159     if (ptr2!=NULL) {
160         memcpy(ptr2,state->wave+state->written,len2);
161         state->written+=len2;
162     }
163     state->offset=state->written % state->buffer_size;
164     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
165     ok(rc==DS_OK,"Unlock: 0x%lx",rc);
166     if (rc!=DS_OK)
167         return -1;
168     return size;
169 }
170
171 static int buffer_silence(play_state_t* state, DWORD size)
172 {
173     LPVOID ptr1,ptr2;
174     DWORD len1,len2;
175     HRESULT rc;
176     BYTE s;
177
178     rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
179                                &ptr1,&len1,&ptr2,&len2,0);
180     ok(rc==DS_OK,"Lock: 0x%lx",rc);
181     if (rc!=DS_OK)
182         return -1;
183
184     s=(state->wfx->wBitsPerSample==8?0x80:0);
185     memset(ptr1,s,len1);
186     if (ptr2!=NULL) {
187         memset(ptr2,s,len2);
188     }
189     state->offset=(state->offset+size) % state->buffer_size;
190     rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
191     ok(rc==DS_OK,"Unlock: 0x%lx",rc);
192     if (rc!=DS_OK)
193         return -1;
194     return size;
195 }
196
197 static int buffer_service(play_state_t* state)
198 {
199     DWORD play_pos,write_pos,buf_free;
200     HRESULT rc;
201
202     rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,&write_pos);
203     ok(rc==DS_OK,"GetCurrentPosition: %lx",rc);
204     if (rc!=DS_OK) {
205         goto STOP;
206     }
207
208     /* Refill the buffer */
209     if (state->offset<=play_pos) {
210         buf_free=play_pos-state->offset;
211     } else {
212         buf_free=state->buffer_size-state->offset+play_pos;
213     }
214     if (winetest_debug > 1)
215         trace("buf pos=%ld free=%ld written=%ld / %ld\n",
216               play_pos,buf_free,state->written,state->wave_len);
217     if (buf_free==0)
218         return 1;
219
220     if (state->written<state->wave_len) {
221         int w=buffer_refill(state,buf_free);
222         if (w==-1)
223             goto STOP;
224         buf_free-=w;
225         if (state->written==state->wave_len) {
226             state->last_pos=(state->offset<play_pos)?play_pos:0;
227             if (winetest_debug > 1)
228                 trace("last sound byte at %ld\n",
229                       (state->written % state->buffer_size));
230         }
231     } else {
232         if (state->last_pos!=0 && play_pos<state->last_pos) {
233             /* We wrapped around the end of the buffer */
234             state->last_pos=0;
235         }
236         if (state->last_pos==0 &&
237             play_pos>(state->written % state->buffer_size)) {
238             /* Now everything has been played */
239             goto STOP;
240         }
241     }
242
243     if (buf_free>0) {
244         /* Fill with silence */
245         if (winetest_debug > 1)
246             trace("writing %ld bytes of silence\n",buf_free);
247         if (buffer_silence(state,buf_free)==-1)
248             goto STOP;
249     }
250     return 1;
251
252 STOP:
253     if (winetest_debug > 1)
254         trace("stopping playback\n");
255     rc=IDirectSoundBuffer_Stop(state->dsbo);
256     ok(rc==DS_OK,"Stop failed: rc=%ld",rc);
257     return 0;
258 }
259
260 static void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo,
261                         int is_primary, int play, int buffer3d, 
262                         LPDIRECTSOUND3DLISTENER listener, 
263                         int move_listener, int move_sound)
264 {
265     HRESULT rc;
266     DSBCAPS dsbcaps;
267     WAVEFORMATEX wfx,wfx2;
268     DWORD size,status,freq;
269     int ref;
270
271     /* DSOUND: Error: Invalid caps pointer */
272     rc=IDirectSoundBuffer_GetCaps(dsbo,0);
273     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
274
275     ZeroMemory(&dsbcaps, sizeof(dsbcaps));
276
277     /* DSOUND: Error: Invalid caps pointer */
278     rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
279     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
280
281     dsbcaps.dwSize=sizeof(dsbcaps);
282     rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
283     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
284     if (rc==DS_OK) {
285         trace("    Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags,
286               dsbcaps.dwBufferBytes);
287     }
288
289     /* Query the format size. Note that it may not match sizeof(wfx) */
290     size=0;
291     rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size);
292     ok(rc==DS_OK && size!=0,
293        "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
294        rc,size);
295
296     rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
297     ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
298     if (rc==DS_OK) {
299         trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
300               wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
301               wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
302     }
303
304     /* DSOUND: Error: Invalid frequency buffer */
305     rc=IDirectSoundBuffer_GetFrequency(dsbo,0);
306     ok(rc==DSERR_INVALIDPARAM,"GetFrequency should have failed: 0x%lx\n",rc);
307
308     /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */
309     rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq);
310     ok((rc==DS_OK&&!is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary),
311         "GetFrequency failed: 0x%lx\n",rc);
312     if (rc==DS_OK) {
313         ok(freq==wfx.nSamplesPerSec,
314            "The frequency returned by GetFrequency %ld does not match the format %ld\n",
315            freq,wfx.nSamplesPerSec);
316     }
317
318     /* DSOUND: Error: Invalid status pointer */
319     rc=IDirectSoundBuffer_GetStatus(dsbo,0);
320     ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc);
321
322     rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
323     ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
324     if (rc==DS_OK) {
325         trace("    status=0x%04lx\n",status);
326     }
327
328     if (is_primary) {
329         /* We must call SetCooperativeLevel to be allowed to call SetFormat */
330         /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
331         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
332         ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
333         if(rc!=DS_OK)
334             return;
335
336         /* DSOUND: Error: Invalid format pointer */
337         rc=IDirectSoundBuffer_SetFormat(dsbo,0);
338         ok(rc==DSERR_INVALIDPARAM,"SetFormat should have failed: 0x%lx\n",rc);
339
340         init_format(&wfx2,11025,16,2);
341         rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2);
342         ok(rc==DS_OK,"SetFormat failed: 0x%lx\n",rc);
343
344         /* There is no garantee that SetFormat will actually change the
345          * format to what we asked for. It depends on what the soundcard
346          * supports. So we must re-query the format.
347          */
348         rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
349         ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
350         if (rc==DS_OK) {
351             trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
352                   wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
353                   wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
354         }
355
356         /* Set the CooperativeLevel back to normal */
357         /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
358         rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
359         ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
360     }
361
362     if (play) {
363         play_state_t state;
364         LONG volume;
365         LPDIRECTSOUND3DBUFFER buffer=NULL;
366         DS3DBUFFER buffer_param;
367         DS3DLISTENER listener_param;
368         trace("    Playing 440Hz LA at %ldx%dx%d\n",
369               wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels);
370
371         if (is_primary) {
372             /* We must call SetCooperativeLevel to be allowed to call Lock */
373             /* DSOUND: Setting DirectSound cooperative level to DSSCL_WRITEPRIMARY */
374             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_WRITEPRIMARY);
375             ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
376             if (rc!=DS_OK)
377                 return;
378         }
379         if (buffer3d) {
380             LPDIRECTSOUNDBUFFER temp_buffer;
381
382             rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer,(LPVOID *)&buffer);
383             ok(rc==DS_OK,"QueryInterface failed: 0x%lx\n",rc);
384             if(rc!=DS_OK)
385                 return;
386
387             /* check the COM interface */
388             rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
389             ok(rc==DS_OK&&temp_buffer!=NULL,"QueryInterface failed: 0x%lx\n",rc);
390             ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo);
391             ref=IDirectSoundBuffer_Release(temp_buffer);
392             ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
393
394             temp_buffer=NULL;
395             rc=IDirectSound3DBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
396             ok(rc==DS_OK&&temp_buffer!=NULL,"IDirectSound3DBuffer_QueryInterface failed: 0x%lx\n",rc);
397             ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)dsbo);
398             ref=IDirectSoundBuffer_Release(temp_buffer);
399             ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
400
401             /* DSOUND: Error: Invalid buffer */
402             rc=IDirectSound3DBuffer_GetAllParameters(buffer,0);
403             ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc);
404
405             ZeroMemory(&buffer_param, sizeof(buffer_param));
406
407             /* DSOUND: Error: Invalid buffer */
408             rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
409             ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc);
410
411             buffer_param.dwSize=sizeof(buffer_param);
412             rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param);
413             ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters failed: 0x%lx\n",rc);
414         }
415         if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
416             rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
417             ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc);
418
419             rc=IDirectSoundBuffer_SetVolume(dsbo,-300);
420             ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
421         }
422
423         /* DSOUND: Error: Buffer does not have CTRLVOLUME */
424         rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
425         ok((rc==DS_OK&&!is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary),"GetVolume failed: 0x%lx\n",rc);
426         if (rc==DS_OK) {
427             trace("    volume=%ld\n",volume);
428         }
429
430         state.wave=wave_generate_la(&wfx,((double)TONE_DURATION)/1000,&state.wave_len);
431
432         state.dsbo=dsbo;
433         state.wfx=&wfx;
434         state.buffer_size=dsbcaps.dwBufferBytes;
435         state.written=state.offset=0;
436         buffer_refill(&state,state.buffer_size);
437
438         rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING);
439         ok(rc==DS_OK,"Play: 0x%lx\n",rc);
440
441         rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
442         ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
443         ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
444            "GetStatus: bad status: %lx",status);
445
446         /* FIXME: set position here someday */
447         if (listener) {
448             ZeroMemory(&listener_param,sizeof(listener_param));
449             listener_param.dwSize=sizeof(listener_param);
450             rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param);
451             ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
452             if (move_listener)
453                 listener_param.vPosition.u1.x = -5.0;
454             else
455                 listener_param.vPosition.u1.x = 0.0;
456             listener_param.vPosition.u2.y = 0.0;
457             listener_param.vPosition.u3.z = 0.0;
458             rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.u1.x,listener_param.vPosition.u2.y,listener_param.vPosition.u3.z,DS3D_IMMEDIATE);
459             ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc);
460         }
461         if (buffer3d) {
462             if (move_sound)
463                 buffer_param.vPosition.u1.x = 5.0;
464             else
465                 buffer_param.vPosition.u1.x = 0.0;
466             buffer_param.vPosition.u2.y = 0.0;
467             buffer_param.vPosition.u3.z = 0.0;
468             rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.u1.x,buffer_param.vPosition.u2.y,buffer_param.vPosition.u3.z,DS3D_IMMEDIATE);
469             ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc);
470         }
471
472         while (buffer_service(&state)) {
473             WaitForSingleObject(GetCurrentProcess(),TIME_SLICE/2);
474             /* FIXME: move positions here someday */
475             if (listener&&move_listener) {
476                 listener_param.vPosition.u1.x += 0.5;
477                 rc=IDirectSound3DListener_SetPosition(listener,listener_param.vPosition.u1.x,listener_param.vPosition.u2.y,listener_param.vPosition.u3.z,DS3D_IMMEDIATE);
478                 ok(rc==DS_OK,"IDirectSound3dListener_SetPosition failed 0x%lx\n",rc);
479             }
480             if (buffer3d&&move_sound) {
481                 buffer_param.vPosition.u1.x -= 0.5;
482                 rc=IDirectSound3DBuffer_SetPosition(buffer,buffer_param.vPosition.u1.x,buffer_param.vPosition.u2.y,buffer_param.vPosition.u3.z,DS3D_IMMEDIATE);
483                 ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition failed 0x%lx\n",rc);
484             }
485         }
486
487         if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
488             rc=IDirectSoundBuffer_SetVolume(dsbo,volume);
489             ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
490         }
491
492         free(state.wave);
493         if (is_primary) {
494             /* Set the CooperativeLevel back to normal */
495             /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
496             rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
497             ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%0lx\n",rc);
498         }
499         if (buffer3d) {
500             ref=IDirectSound3DBuffer_Release(buffer);
501             ok(ref==0,"IDirectSound3DBuffer_Release has %d references, should have 0\n",ref); 
502         }
503     }
504 }
505
506 static void test_secondary(LPDIRECTSOUND dso, 
507                            int play, int has_3dbuffer, 
508                            int has_listener, int has_duplicate, 
509                            int move_listener, int move_sound)
510 {
511     HRESULT rc;
512     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL;
513     LPDIRECTSOUND3DLISTENER listener=NULL;
514     DSBUFFERDESC bufdesc;
515     WAVEFORMATEX wfx;
516     int f,ref;
517
518     ZeroMemory(&bufdesc, sizeof(bufdesc));
519     bufdesc.dwSize=sizeof(bufdesc);
520     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
521     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
522     ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer 0x%lx\n",rc);
523     if (rc==DS_OK&&primary!=NULL) {
524         if (has_listener) {
525             rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener);
526             ok(rc==DS_OK&&listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc);
527             ref=IDirectSoundBuffer_Release(primary);
528             ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
529             if(rc==DS_OK&&listener!=NULL) {
530                 DS3DLISTENER listener_param;
531                 ZeroMemory(&listener_param,sizeof(listener_param));
532                 /* DSOUND: Error: Invalid buffer */
533                 rc=IDirectSound3DListener_GetAllParameters(listener,0);
534                 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
535
536                 /* DSOUND: Error: Invalid buffer */
537                 rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param);
538                 ok(rc==DSERR_INVALIDPARAM,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
539
540                 listener_param.dwSize=sizeof(listener_param);
541                 rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param);
542                 ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters failed 0x%lx\n",rc);
543             } else
544                 return;
545         } 
546
547         for (f=0;f<NB_FORMATS;f++) {
548             init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
549             secondary=NULL;
550             ZeroMemory(&bufdesc, sizeof(bufdesc));
551             bufdesc.dwSize=sizeof(bufdesc);
552             bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRL3D;
553             bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
554             bufdesc.lpwfxFormat=&wfx;
555             trace("  Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d\n",
556                 has_3dbuffer?"3D ":"",
557                 has_duplicate?"duplicated ":"",
558                 listener!=NULL||move_sound?"with ":"",
559                 move_listener?"moving ":"",
560                 listener!=NULL?"listener ":"",
561                 listener&&move_sound?"and moving sound ":move_sound?"moving sound ":"",
562             wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
563             rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
564             ok(rc==DS_OK&&secondary!=NULL,"CreateSoundBuffer failed to create a 3D secondary buffer 0x%lx\n",rc);
565             if (rc==DS_OK&&secondary!=NULL) {
566                 if (has_duplicate) {
567                     LPDIRECTSOUNDBUFFER duplicated=NULL;
568
569                     /* DSOUND: Error: Invalid source buffer */
570                     rc=IDirectSound_DuplicateSoundBuffer(dso,0,0);
571                     ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
572
573                     /* DSOUND: Error: Invalid dest buffer */
574                     rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0);
575                     ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
576
577                     /* DSOUND: Error: Invalid source buffer */
578                     rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated);
579                     ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
580
581                     duplicated=NULL;
582                     rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,&duplicated);
583                     ok(rc==DS_OK&&duplicated!=NULL,"IDirectSound_DuplicateSoundBuffer failed to duplicate a secondary buffer 0x%lx\n",rc);
584
585                     if (rc==DS_OK&&duplicated!=NULL) {
586                         ref=IDirectSoundBuffer_Release(secondary);
587                         ok(ref==0,"IDirectSoundBuffer_Release secondary has %d references, should have 0\n",ref); 
588                         secondary=duplicated;
589                     } 
590                 }
591
592                 if (rc==DS_OK&&secondary!=NULL) {
593                     test_buffer(dso,secondary,0,winetest_interactive,has_3dbuffer,listener,move_listener,move_sound);
594                     ref=IDirectSoundBuffer_Release(secondary);
595                     ok(ref==0,"IDirectSoundBuffer_Release %s has %d references, should have 0\n",has_duplicate?"duplicated":"secondary",ref);
596                 }
597             }
598         }
599         if (has_listener) {
600             ref=IDirectSound3DListener_Release(listener);
601             ok(ref==0,"IDirectSound3dListener_Release listener has %d references, should have 0\n",ref);
602         } else {
603             ref=IDirectSoundBuffer_Release(primary);
604             ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref);
605         }
606     }
607 }
608
609 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
610                                    LPCSTR lpcstrModule, LPVOID lpContext)
611 {
612     HRESULT rc;
613     LPDIRECTSOUND dso=NULL;
614     LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL,duplicated=NULL;
615     DSBUFFERDESC bufdesc;
616     WAVEFORMATEX wfx;
617     DSCAPS dscaps;
618     int f,ref;
619
620     trace("Testing %s - %s\n",lpcstrDescription,lpcstrModule);
621
622     /* DSOUND: Error: Invalid interface buffer */
623     rc=DirectSoundCreate(lpGuid,0,NULL);
624     ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate should have failed: 0x%lx\n",rc);
625
626     rc=DirectSoundCreate(lpGuid,&dso,NULL);
627     ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
628     if (rc!=DS_OK)
629         goto EXIT;
630
631     /* DSOUND: Error: Invalid caps buffer */
632     rc=IDirectSound_GetCaps(dso,0);
633     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
634
635     ZeroMemory(&dscaps, sizeof(dscaps));
636
637     /* DSOUND: Error: Invalid caps buffer */
638     rc=IDirectSound_GetCaps(dso,&dscaps);
639     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
640
641     dscaps.dwSize=sizeof(dscaps);
642
643     /* DSOUND: Running on a certified driver */
644     rc=IDirectSound_GetCaps(dso,&dscaps);
645     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
646     if (rc==DS_OK) {
647         trace("  DirectSound Caps: flags=0x%08lx secondary min=%ld max=%ld\n",
648               dscaps.dwFlags,dscaps.dwMinSecondarySampleRate,
649               dscaps.dwMaxSecondarySampleRate);
650     }
651
652     /* DSOUND: Error: Invalid buffer description pointer */
653     rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL);
654     ok(rc==DSERR_INVALIDPARAM,"CreateSoundBuffer should have failed: 0x%lx\n",rc);
655
656     /* DSOUND: Error: Invalid buffer description pointer */
657     rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL);
658     ok(rc==DSERR_INVALIDPARAM && primary==0,"CreateSoundBuffer should have failed: rc=0x%lx,dsbo=0x%lx\n",rc,(DWORD)primary);
659
660     /* DSOUND: Error: Invalid buffer description pointer */
661     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,0,NULL);
662     ok(rc==DSERR_INVALIDPARAM && primary==0,"CreateSoundBuffer should have failed: rc=0x%lx,dsbo=0x%lx\n",rc,(DWORD)primary);
663
664     ZeroMemory(&bufdesc, sizeof(bufdesc));
665
666     /* DSOUND: Error: Invalid size */
667     /* DSOUND: Error: Invalid buffer description */
668     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
669     ok(rc==DSERR_INVALIDPARAM && primary==0,"CreateSoundBuffer should have failed: rc=0x%lx,primary=0x%lx\n",rc,(DWORD)primary);
670
671     /* We must call SetCooperativeLevel before calling CreateSoundBuffer */
672     /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */
673     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
674     ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
675     if (rc!=DS_OK)
676         goto EXIT;
677
678     /* Testing the primary buffer */
679     primary=NULL;
680     ZeroMemory(&bufdesc, sizeof(bufdesc));
681     bufdesc.dwSize=sizeof(bufdesc);
682     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
683     trace("  Testing the primary buffer\n");
684     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
685     ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a primary buffer: 0x%lx\n",rc);
686     if (rc==DS_OK&&primary!=NULL) {
687         test_buffer(dso,primary,1,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,0,0,0);
688         ref=IDirectSoundBuffer_Release(primary);
689         ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); 
690     }
691
692     /* Testing 3D primary buffer */
693     primary=NULL;
694     ZeroMemory(&bufdesc, sizeof(bufdesc));
695     bufdesc.dwSize=sizeof(bufdesc);
696     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
697     trace("  Testing 3D primary buffer\n");
698     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
699     ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer: 0x%lx\n",rc);
700     if (rc==DS_OK&&primary!=NULL) {
701         ref=IDirectSoundBuffer_Release(primary);
702         ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); 
703         primary=NULL;
704         ZeroMemory(&bufdesc, sizeof(bufdesc));
705         bufdesc.dwSize=sizeof(bufdesc);
706         bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
707         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
708         ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer: 0x%lx\n",rc);
709         if (rc==DS_OK&&primary!=NULL) {
710             test_buffer(dso,primary,1,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,0,0,0);
711             ref=IDirectSoundBuffer_Release(primary);
712             ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); 
713         }
714     }
715
716     /* Testing the primary buffer with listener */
717     primary=NULL;
718     ZeroMemory(&bufdesc, sizeof(bufdesc));
719     bufdesc.dwSize=sizeof(bufdesc);
720     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
721     trace("  Testing 3D primary buffer\n");
722     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
723     ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer: 0x%lx\n",rc);
724     if (rc==DS_OK&&primary!=NULL) {
725         ref=IDirectSoundBuffer_Release(primary);
726         ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); 
727         primary=NULL;
728         ZeroMemory(&bufdesc, sizeof(bufdesc));
729         bufdesc.dwSize=sizeof(bufdesc);
730         bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
731         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
732         ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer: 0x%lx\n",rc);
733         if (rc==DS_OK&&primary!=NULL) {
734             LPDIRECTSOUND3DLISTENER listener=NULL;
735             rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener);
736             ok(rc==DS_OK&&listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc);
737             if (rc==DS_OK&&listener) {
738                 test_buffer(dso,primary,1,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,listener,0,0);
739                 ref=IDirectSound3DListener_Release(listener);
740                 ok(ref==0,"IDirectSound3DListener_Release listener has %d references, should have 0\n",ref);
741             }
742             ref=IDirectSoundBuffer_Release(primary);
743             ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); 
744         }
745     }
746
747     /* Testing 3D primary buffer with listener */
748     primary=NULL;
749     ZeroMemory(&bufdesc, sizeof(bufdesc));
750     bufdesc.dwSize=sizeof(bufdesc);
751     bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
752     trace("  Testing 3D primary buffer with listener\n");
753     rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL);
754     ok(rc==DS_OK&&primary!=NULL,"CreateSoundBuffer failed to create a 3D primary buffer 0x%lx\n",rc);
755     if (rc==DS_OK&&primary!=NULL) {
756         LPDIRECTSOUND3DLISTENER listener=NULL;
757         rc=IDirectSoundBuffer_QueryInterface(primary,&IID_IDirectSound3DListener,(void **)&listener);
758         ok(rc==DS_OK&&listener!=NULL,"IDirectSoundBuffer_QueryInterface failed to get a 3D listener 0x%lx\n",rc);
759         if (rc==DS_OK&&listener!=NULL) {
760             LPDIRECTSOUNDBUFFER temp_buffer=NULL;
761
762             /* Checking the COM interface */
763             rc=IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
764             ok(rc==DS_OK&&temp_buffer!=NULL,"IDirectSoundBuffer_QueryInterface failed: 0x%lx\n",rc);
765             ok(temp_buffer==primary,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary);
766             if(rc==DS_OK&&temp_buffer!=NULL) {
767                 ref=IDirectSoundBuffer_Release(temp_buffer);
768                 ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
769
770                 temp_buffer=NULL;
771                 rc=IDirectSound3DListener_QueryInterface(listener, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer);
772                 ok(rc==DS_OK&&temp_buffer!=NULL,"IDirectSoundBuffer_QueryInterface failed: 0x%lx\n",rc);
773                 ok(temp_buffer==primary,"COM interface broken: 0x%08lx != 0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary);
774                 ref=IDirectSoundBuffer_Release(temp_buffer);
775                 ok(ref==1,"IDirectSoundBuffer_Release has %d references, should have 1\n",ref);
776
777                 /* Testing the buffer */
778                 test_buffer(dso,primary,1,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),0,listener,0,0);
779             }
780
781             /* Testing the reference counting */
782             ref=IDirectSound3DListener_Release(listener);
783             ok(ref==0,"IDirectSound3DListener_Release listener has %d references, should have 0\n",ref);
784         }
785
786         /* Testing the reference counting */
787         ref=IDirectSoundBuffer_Release(primary);
788         ok(ref==0,"IDirectSoundBuffer_Release primary has %d references, should have 0\n",ref); 
789     }
790
791     /* Set the CooperativeLevel back to normal */
792     /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */
793     rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
794     ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
795     if (rc!=DS_OK)
796         goto EXIT;
797
798     /* Testing secondary buffers */
799     for (f=0;f<NB_FORMATS;f++) {
800         init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
801         secondary=NULL;
802         ZeroMemory(&bufdesc, sizeof(bufdesc));
803         bufdesc.dwSize=sizeof(bufdesc);
804         bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2;
805         bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
806         bufdesc.lpwfxFormat=&wfx;
807         trace("  Testing a secondary buffer at %ldx%dx%d\n",
808             wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
809         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
810         ok(rc==DS_OK&&secondary!=NULL,"CreateSoundBuffer failed to create a secondary buffer 0x%lx\n",rc);
811         if (rc==DS_OK&&secondary!=NULL) {
812             test_buffer(dso,secondary,0,winetest_interactive,0,0,0,0);
813             ref=IDirectSoundBuffer_Release(secondary);
814             ok(ref==0,"IDirectSoundBuffer_Release secondary has %d references, should have 0\n",ref); 
815         }
816     }
817
818     /* Testing duplicated secondary buffers */
819     for (f=0;f<NB_FORMATS;f++) {
820         init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
821         secondary=NULL;
822         ZeroMemory(&bufdesc, sizeof(bufdesc));
823         bufdesc.dwSize=sizeof(bufdesc);
824         bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2;
825         bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
826         bufdesc.lpwfxFormat=&wfx;
827         trace("  Testing a duplicated secondary buffer at %ldx%dx%d\n",
828             wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
829         rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL);
830         ok(rc==DS_OK&&secondary!=NULL,"CreateSoundBuffer failed to create a secondary buffer 0x%lx\n",rc);
831         if(rc==DS_OK&&secondary!=NULL) {
832             /* DSOUND: Error: Invalid source buffer */
833             rc=IDirectSound_DuplicateSoundBuffer(dso,0,0);
834             ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
835
836             /* DSOUND: Error: Invalid dest buffer */
837             rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0);
838             ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
839
840             /* DSOUND: Error: Invalid source buffer */
841             rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated);
842             ok(rc==DSERR_INVALIDPARAM,"IDirectSound_DuplicateSoundBuffer should have failed 0x%lx\n",rc);
843
844             duplicated=NULL;
845             rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,&duplicated);
846             ok(rc==DS_OK&&duplicated!=NULL,"IDirectSound_DuplicateSoundBuffer failed to duplicate a secondary buffer 0x%lx\n",rc);
847
848             ref=IDirectSoundBuffer_Release(secondary);
849             ok(ref==0,"IDirectSoundBuffer_Release secondary has %d references, should have 0\n",ref); 
850
851             if (rc==DS_OK&&duplicated!=NULL) {
852                 test_buffer(dso,duplicated,0,winetest_interactive,0,0,0,0);
853
854                 ref=IDirectSoundBuffer_Release(duplicated);
855                 ok(ref==0,"IDirectSoundBuffer_Release duplicated has %d references, should have 0\n",ref); 
856             }
857         }
858     }
859
860     /* Testing 3D secondary buffers */
861     test_secondary(dso,winetest_interactive,0,0,0,0,0);
862     test_secondary(dso,winetest_interactive,1,0,0,0,0);
863     test_secondary(dso,winetest_interactive,1,0,1,0,0);
864     test_secondary(dso,winetest_interactive,0,1,0,0,0);
865     test_secondary(dso,winetest_interactive,0,1,1,0,0);
866     test_secondary(dso,winetest_interactive,1,1,0,0,0);
867     test_secondary(dso,winetest_interactive,1,1,1,0,0);
868     test_secondary(dso,winetest_interactive,1,1,0,1,0);
869     test_secondary(dso,winetest_interactive,1,1,0,0,1);
870     test_secondary(dso,winetest_interactive,1,1,0,1,1);
871
872 EXIT:
873     if (dso!=NULL) {
874         ref=IDirectSound_Release(dso);
875         ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
876     }
877     return 1;
878 }
879
880 static void dsound_out_tests()
881 {
882     HRESULT rc;
883     rc=DirectSoundEnumerateA(&dsenum_callback,NULL);
884     ok(rc==DS_OK,"DirectSoundEnumerate failed: %ld\n",rc);
885 }
886
887 #define NOTIFICATIONS    5
888
889 typedef struct {
890     char* wave;
891     DWORD wave_len;
892
893     LPDIRECTSOUNDCAPTUREBUFFER dscbo;
894     LPWAVEFORMATEX wfx;
895     DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS];
896     HANDLE event;
897     LPDIRECTSOUNDNOTIFY notify;
898
899     DWORD buffer_size;
900     DWORD read;
901     DWORD offset;
902     DWORD size;
903
904     DWORD last_pos;
905 } capture_state_t;
906
907 static int capture_buffer_service(capture_state_t* state)
908 {
909     HRESULT rc;
910     LPVOID ptr1,ptr2;
911     DWORD len1,len2;
912     DWORD capture_pos,read_pos;
913
914     rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos,&read_pos);
915     ok(rc==DS_OK,"GetCurrentPosition failed: 0x%lx\n",rc);
916     if (rc!=DS_OK)
917         return 0;
918
919     rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size,&ptr1,&len1,&ptr2,&len2,0);
920     ok(rc==DS_OK,"Lock failed: 0x%lx\n",rc);
921     if (rc!=DS_OK)
922         return 0;
923
924     rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2);
925     ok(rc==DS_OK,"Unlock failed: 0x%lx\n",rc);
926     if (rc!=DS_OK)
927         return 0;
928
929     state->offset = (state->offset + state->size) % state->buffer_size;
930
931     return 1;
932 }
933
934 static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, 
935                                 LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record)
936 {
937     HRESULT rc;
938     DSCBCAPS dscbcaps;
939     WAVEFORMATEX wfx;
940     DWORD size,status;
941     capture_state_t state;
942     int i;
943
944     /* Private dsound.dll: Error: Invalid caps pointer */
945     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0);
946     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
947
948     /* Private dsound.dll: Error: Invalid caps pointer */
949     dscbcaps.dwSize=0;
950     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
951     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
952
953     dscbcaps.dwSize=sizeof(dscbcaps);
954     rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps);
955     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
956     if (rc==DS_OK) {
957         trace("    Caps: size = %ld flags=0x%08lx buffer size=%ld\n",
958             dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes);
959     }
960
961     /* Query the format size. Note that it may not match sizeof(wfx) */
962     /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must be non-NULL */
963     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL);
964     ok(rc==DSERR_INVALIDPARAM,
965        "GetFormat should have returned an error: rc=0x%lx\n",rc);
966
967     size=0;
968     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size);
969     ok(rc==DS_OK && size!=0,
970        "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
971        rc,size);
972
973     rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL);
974     ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
975     if (rc==DS_OK) {
976         trace("    tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
977               wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,
978               wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign);
979     }
980
981     /* Private dsound.dll: Error: Invalid status pointer */
982     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0);
983     ok(rc==DSERR_INVALIDPARAM,"GetStatus should have failed: 0x%lx\n",rc);
984
985     rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
986     ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
987     if (rc==DS_OK) {
988         trace("    status=0x%04lx\n",status);
989     }
990
991     ZeroMemory(&state, sizeof(state));
992     state.dscbo=dscbo;
993     state.wfx=&wfx;
994     state.buffer_size = dscbcaps.dwBufferBytes;
995     state.event = CreateEvent( NULL, FALSE, FALSE, NULL );
996     state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS;
997
998     rc=IDirectSoundCapture_QueryInterface(dscbo,&IID_IDirectSoundNotify,(void **)&(state.notify));
999     ok(rc==DS_OK,"QueryInterface failed: 0x%lx\n",rc);
1000     if (rc!=DS_OK)
1001         return;
1002
1003     for (i = 0; i < NOTIFICATIONS; i++) {
1004         state.posnotify[i].dwOffset = (i * state.size) + state.size - 1;
1005         state.posnotify[i].hEventNotify = state.event;
1006     }
1007
1008     rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS,state.posnotify);
1009     ok(rc==DS_OK,"SetNotificationPositions failed: 0x%lx\n",rc);
1010     if (rc!=DS_OK)
1011         return;
1012
1013     if (record) {
1014         rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING);
1015         ok(rc==DS_OK,"Start: 0x%lx\n",rc);
1016         if (rc!=DS_OK)
1017             return;
1018
1019         rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status);
1020         ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
1021         ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING),
1022            "GetStatus: bad status: %lx",status);
1023         if (rc!=DS_OK)
1024             return;
1025
1026         /* wait for the notifications */
1027         for (i = 0; i < (NOTIFICATIONS * 2); i++) {
1028             rc=MsgWaitForMultipleObjects( 1, &(state.event), FALSE, 3000, QS_ALLEVENTS );
1029             ok(rc==WAIT_OBJECT_0,"MsgWaitForMultipleObjects failed: 0x%lx\n",rc);
1030             if (rc!=WAIT_OBJECT_0)
1031                 break;
1032             if (!capture_buffer_service(&state))
1033                 break;
1034         }
1035
1036         rc=IDirectSoundCaptureBuffer_Stop(dscbo);
1037         ok(rc==DS_OK,"Stop: 0x%lx\n",rc);
1038         if (rc!=DS_OK)
1039             return;
1040     }
1041
1042     rc=IDirectSoundNotify_Release(state.notify);
1043     ok(rc==0,"Release: 0x%lx\n",rc);
1044     if (rc!=0)
1045         return;
1046 }
1047
1048 static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
1049                                     LPCSTR lpcstrModule, LPVOID lpContext)
1050 {
1051     HRESULT rc;
1052     LPDIRECTSOUNDCAPTURE dsco=NULL;
1053     LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL;
1054     DSCBUFFERDESC bufdesc;
1055     WAVEFORMATEX wfx;
1056     DSCCAPS dsccaps;
1057     int f, ref;
1058
1059     /* Private dsound.dll: Error: Invalid interface buffer */
1060     trace("Testing %s - %s\n",lpcstrDescription,lpcstrModule);
1061     rc=DirectSoundCaptureCreate(lpGuid,NULL,NULL);
1062     ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate didn't fail: 0x%lx\n",rc);
1063     if (rc==DS_OK) {
1064         ref=IDirectSoundCapture_Release(dsco);
1065         ok(ref==0,"IDirectSoundCapture_Release has %d references, should have 0\n",ref);
1066     }
1067
1068     rc=DirectSoundCaptureCreate(lpGuid,&dsco,NULL);
1069     ok((rc==DS_OK)||(rc==DSERR_NODRIVER),"DirectSoundCaptureCreate failed: 0x%lx\n",rc);
1070     if (rc!=DS_OK)
1071         goto EXIT;
1072
1073     /* Private dsound.dll: Error: Invalid caps buffer */
1074     rc=IDirectSoundCapture_GetCaps(dsco,NULL);
1075     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
1076
1077     /* Private dsound.dll: Error: Invalid caps buffer */
1078     dsccaps.dwSize=0;
1079     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
1080     ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
1081
1082     dsccaps.dwSize=sizeof(dsccaps);
1083     rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps);
1084     ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
1085     if (rc==DS_OK) {
1086         trace("  DirectSoundCapture Caps: size=%ld flags=0x%08lx formats=%05lx channels=%ld\n",
1087               dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats,dsccaps.dwChannels);
1088     }
1089
1090     /* Private dsound.dll: Error: Invalid size */
1091     /* Private dsound.dll: Error: Invalid capture buffer description */
1092     ZeroMemory(&bufdesc, sizeof(bufdesc));
1093     bufdesc.dwSize=0;
1094     bufdesc.dwFlags=0;
1095     bufdesc.dwBufferBytes=0;
1096     bufdesc.dwReserved=0;
1097     bufdesc.lpwfxFormat=NULL;
1098     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
1099     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
1100     if (rc==DS_OK) {
1101         ref=IDirectSoundCaptureBuffer_Release(dscbo);
1102         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
1103     }
1104
1105     /* Private dsound.dll: Error: Invalid buffer size */
1106     /* Private dsound.dll: Error: Invalid capture buffer description */
1107     ZeroMemory(&bufdesc, sizeof(bufdesc));
1108     bufdesc.dwSize=sizeof(bufdesc);
1109     bufdesc.dwFlags=0;
1110     bufdesc.dwBufferBytes=0;
1111     bufdesc.dwReserved=0;
1112     bufdesc.lpwfxFormat=NULL;
1113     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
1114     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
1115     if (rc==DS_OK) {
1116         ref=IDirectSoundCaptureBuffer_Release(dscbo);
1117         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
1118     }
1119
1120     /* Private dsound.dll: Error: Invalid buffer size */
1121     /* Private dsound.dll: Error: Invalid capture buffer description */
1122     ZeroMemory(&bufdesc, sizeof(bufdesc));
1123     ZeroMemory(&wfx, sizeof(wfx));
1124     bufdesc.dwSize=sizeof(bufdesc);
1125     bufdesc.dwFlags=0;
1126     bufdesc.dwBufferBytes=0;
1127     bufdesc.dwReserved=0;
1128     bufdesc.lpwfxFormat=&wfx;
1129     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
1130     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
1131     if (rc==DS_OK) {
1132         ref=IDirectSoundCaptureBuffer_Release(dscbo);
1133         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
1134     }
1135
1136     /* Private dsound.dll: Error: Invalid buffer size */
1137     /* Private dsound.dll: Error: Invalid capture buffer description */
1138     init_format(&wfx,11025,8,1);
1139     ZeroMemory(&bufdesc, sizeof(bufdesc));
1140     bufdesc.dwSize=sizeof(bufdesc);
1141     bufdesc.dwFlags=0;
1142     bufdesc.dwBufferBytes=0;
1143     bufdesc.dwReserved=0;
1144     bufdesc.lpwfxFormat=&wfx;
1145     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
1146     ok(rc==DSERR_INVALIDPARAM,"CreateCaptureBuffer should have failed to create a capture buffer 0x%lx\n",rc);
1147     if (rc==DS_OK) {
1148         ref=IDirectSoundCaptureBuffer_Release(dscbo);
1149         ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
1150     }
1151
1152     for (f=0;f<NB_FORMATS;f++) {
1153         init_format(&wfx,formats[f][0],formats[f][1],formats[f][2]);
1154         ZeroMemory(&bufdesc, sizeof(bufdesc));
1155         bufdesc.dwSize=sizeof(bufdesc);
1156         bufdesc.dwFlags=0;
1157         bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
1158         bufdesc.dwReserved=0;
1159         bufdesc.lpwfxFormat=&wfx;
1160         trace("  Testing the capture buffer at %ldx%dx%d\n",
1161             wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
1162         rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
1163         ok(rc==DS_OK,"CreateCaptureBuffer failed to create a capture buffer 0x%lx\n",rc);
1164         if (rc==DS_OK) {
1165             test_capture_buffer(dsco, dscbo, winetest_interactive);
1166             ref=IDirectSoundCaptureBuffer_Release(dscbo);
1167             ok(ref==0,"IDirectSoundCaptureBuffer_Release has %d references, should have 0\n",ref);
1168         }
1169     }
1170
1171     /* Try an invalid format to test error handling */
1172 #if 0
1173     init_format(&wfx,2000000,16,2);
1174     ZeroMemory(&bufdesc, sizeof(bufdesc));
1175     bufdesc.dwSize=sizeof(bufdesc);
1176     bufdesc.dwFlags=DSCBCAPS_WAVEMAPPED;
1177     bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec;
1178     bufdesc.dwReserved=0;
1179     bufdesc.lpwfxFormat=&wfx;
1180     trace("  Testing the capture buffer at %ldx%dx%d\n",
1181         wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
1182     rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL);
1183     ok(rc!=DS_OK,"CreateCaptureBuffer should have failed at 2 MHz 0x%lx\n",rc);
1184 #endif
1185
1186 EXIT:
1187     if (dsco!=NULL) {
1188         ref=IDirectSoundCapture_Release(dsco);
1189         ok(ref==0,"IDirectSoundCapture_Release has %d references, should have 0\n",ref);
1190     }
1191
1192     return TRUE;
1193 }
1194
1195 static void dsound_in_tests()
1196 {
1197     HRESULT rc;
1198     rc=DirectSoundCaptureEnumerateA(&dscenum_callback,NULL);
1199     ok(rc==DS_OK,"DirectSoundCaptureEnumerate failed: %ld\n",rc);
1200 }
1201
1202 START_TEST(dsound)
1203 {
1204     dsound_out_tests();
1205     dsound_in_tests();
1206 }