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