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