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