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