2 * Unit tests for dsound functions
4 * Copyright (c) 2002 Francois Gouget
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/test.h"
27 /* http://www.gamedev.net/reference/articles/article710.asp */
29 /* The time slice determines how often we will service the buffer and the
30 * buffer will be four time slices long
32 #define TIME_SLICE 100
33 #define BUFFER_LEN (4*TIME_SLICE)
34 #define TONE_DURATION (6*TIME_SLICE)
36 /* This test can play a test tone. But this only makes sense if someone
37 * is going to carefully listen to it, and would only bother everyone else.
38 * So this is only done if the test is being run in interactive mode.
41 #define PI 3.14159265358979323846
42 static char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size)
49 nb_samples=(int)(duration*wfx->nSamplesPerSec);
50 *size=nb_samples*wfx->nBlockAlign;
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));
57 if (wfx->nChannels==2)
60 signed short sample=(signed short)((double)32767.5*y-0.5);
64 if (wfx->nChannels==2) {
74 static HWND get_hwnd()
76 HWND hwnd=GetForegroundWindow();
78 hwnd=GetDesktopWindow();
82 static void init_format(WAVEFORMATEX* wfx, int rate, int depth, int channels)
84 wfx->wFormatTag=WAVE_FORMAT_PCM;
85 wfx->nChannels=channels;
86 wfx->wBitsPerSample=depth;
87 wfx->nSamplesPerSec=rate;
88 wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8;
89 wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign;
97 LPDIRECTSOUNDBUFFER dsbo;
106 static int buffer_refill(play_state_t* state, DWORD size)
112 if (size>state->wave_len-state->written)
113 size=state->wave_len-state->written;
115 rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
116 &ptr1,&len1,&ptr2,&len2,0);
117 ok(rc==DS_OK,"Lock: 0x%lx",rc);
121 memcpy(ptr1,state->wave+state->written,len1);
122 state->written+=len1;
124 memcpy(ptr2,state->wave+state->written,len2);
125 state->written+=len2;
127 state->offset=state->written % state->buffer_size;
128 rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
129 ok(rc==DS_OK,"Unlock: 0x%lx",rc);
135 static int buffer_silence(play_state_t* state, DWORD size)
142 rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size,
143 &ptr1,&len1,&ptr2,&len2,0);
144 ok(rc==DS_OK,"Lock: 0x%lx",rc);
148 s=(state->wfx->wBitsPerSample==8?0x80:0);
153 state->offset=(state->offset+size) % state->buffer_size;
154 rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2);
155 ok(rc==DS_OK,"Unlock: 0x%lx",rc);
161 static int buffer_service(play_state_t* state)
163 DWORD play_pos,write_pos,buf_free;
166 rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,&write_pos);
167 ok(rc==DS_OK,"GetCurrentPosition: %lx",rc);
172 /* Refill the buffer */
173 if (state->offset<=play_pos) {
174 buf_free=play_pos-state->offset;
176 buf_free=state->buffer_size-state->offset+play_pos;
178 if (winetest_debug > 1)
179 trace("buf pos=%ld free=%ld written=%ld / %ld\n",
180 play_pos,buf_free,state->written,state->wave_len);
184 if (state->written<state->wave_len) {
185 int w=buffer_refill(state,buf_free);
189 if (state->written==state->wave_len) {
190 state->last_pos=(state->offset<play_pos)?play_pos:0;
191 if (winetest_debug > 1)
192 trace("last sound byte at %ld\n",
193 (state->written % state->buffer_size));
196 if (state->last_pos!=0 && play_pos<state->last_pos) {
197 /* We wrapped around the end of the buffer */
200 if (state->last_pos==0 &&
201 play_pos>(state->written % state->buffer_size)) {
202 /* Now everything has been played */
208 /* Fill with silence */
209 if (winetest_debug > 1)
210 trace("writing %ld bytes of silence\n",buf_free);
211 if (buffer_silence(state,buf_free)==-1)
217 if (winetest_debug > 1)
218 trace("stopping playback\n");
219 rc=IDirectSoundBuffer_Stop(state->dsbo);
220 ok(rc==DS_OK,"Stop failed: rc=%ld",rc);
224 static void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo,
225 int primary, int play)
229 WAVEFORMATEX wfx,wfx2;
230 DWORD size,status,freq;
233 rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
234 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
236 dsbcaps.dwSize=sizeof(dsbcaps);
237 rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps);
238 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
240 trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags,
241 dsbcaps.dwBufferBytes);
244 /* Query the format size. Note that it may not match sizeof(wfx) */
246 rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size);
247 ok(rc==DS_OK && size!=0,
248 "GetFormat should have returned the needed size: rc=0x%lx size=%ld\n",
251 rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
252 ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
254 trace(" tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
255 wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
256 wfx.nAvgBytesPerSec,wfx.nBlockAlign);
259 rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq);
260 ok(rc==DS_OK || rc==DSERR_CONTROLUNAVAIL,"GetFrequency failed: 0x%lx\n",rc);
262 ok(freq==wfx.nSamplesPerSec,
263 "The frequency returned by GetFrequency %ld does not match the format %ld\n",
264 freq,wfx.nSamplesPerSec);
267 rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
268 ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
270 trace(" status=0x%04lx\n",status);
274 /* We must call SetCooperativeLevel to be allowed to call SetFormat */
275 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY);
276 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
280 init_format(&wfx2,11025,16,2);
281 rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2);
282 ok(rc==DS_OK,"SetFormat failed: 0x%lx\n",rc);
284 rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL);
285 ok(rc==DS_OK,"GetFormat failed: 0x%lx\n",rc);
287 ok(wfx.wFormatTag==wfx2.wFormatTag &&
288 wfx.nChannels==wfx2.nChannels &&
289 wfx.wBitsPerSample==wfx2.wBitsPerSample &&
290 wfx.nSamplesPerSec==wfx2.nSamplesPerSec &&
291 wfx.nBlockAlign==wfx2.nBlockAlign &&
292 wfx.nAvgBytesPerSec==wfx2.nAvgBytesPerSec,
293 "SetFormat did not work right: tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n",
294 wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels,
295 wfx.nAvgBytesPerSec,wfx.nBlockAlign);
298 /* Set the CooperativeLevel back to normal */
299 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
300 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
307 trace(" Playing 440Hz LA at %ldx%2dx%d\n",
308 wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels);
311 /* We must call SetCooperativeLevel to be allowed to call Lock */
312 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_WRITEPRIMARY);
313 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
318 if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
319 rc=IDirectSoundBuffer_GetVolume(dsbo,&volume);
320 ok(rc==DS_OK,"GetVolume failed: 0x%lx\n",rc);
322 trace(" volume=%ld\n",volume);
325 rc=IDirectSoundBuffer_SetVolume(dsbo,-1200);
326 ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
329 state.wave=wave_generate_la(&wfx,((double)TONE_DURATION)/1000,&state.wave_len);
333 state.buffer_size=dsbcaps.dwBufferBytes;
334 state.written=state.offset=0;
335 buffer_refill(&state,state.buffer_size);
337 rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING);
338 ok(rc==DS_OK,"Play: 0x%lx\n",rc);
340 rc=IDirectSoundBuffer_GetStatus(dsbo,&status);
341 ok(rc==DS_OK,"GetStatus failed: 0x%lx\n",rc);
342 ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING),
343 "GetStatus: bad status: %lx",status);
345 while (buffer_service(&state)) {
346 WaitForSingleObject(GetCurrentProcess(),TIME_SLICE/2);
349 if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) {
350 rc=IDirectSoundBuffer_SetVolume(dsbo,volume);
351 ok(rc==DS_OK,"SetVolume failed: 0x%lx\n",rc);
356 /* Set the CooperativeLevel back to normal */
357 rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL);
358 ok(rc==DS_OK,"SetCooperativeLevel failed: 0x%lx\n",rc);
363 static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
364 LPCSTR lpcstrModule, LPVOID lpContext)
367 LPDIRECTSOUND dso=NULL;
368 LPDIRECTSOUNDBUFFER dsbo=NULL;
369 DSBUFFERDESC bufdesc;
373 trace("Testing %s - %s\n",lpcstrDescription,lpcstrModule);
374 rc=DirectSoundCreate(lpGuid,&dso,NULL);
375 ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
380 rc=IDirectSound_GetCaps(dso,&dscaps);
381 ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
383 dscaps.dwSize=sizeof(dscaps);
384 rc=IDirectSound_GetCaps(dso,&dscaps);
385 ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
387 trace(" DirectSound Caps: flags=0x%08lx secondary min=%ld max=%ld\n",
388 dscaps.dwFlags,dscaps.dwMinSecondarySampleRate,
389 dscaps.dwMaxSecondarySampleRate);
392 /* Testing the primary buffer */
393 bufdesc.dwSize=sizeof(bufdesc);
394 bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
395 bufdesc.dwBufferBytes=0;
396 bufdesc.dwReserved=0;
397 bufdesc.lpwfxFormat=NULL;
398 trace(" Testing the primary buffer\n");
399 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&dsbo,NULL);
400 ok(rc==DS_OK,"CreateSoundBuffer failed to create a primary buffer 0x%lx\n",rc);
402 test_buffer(dso,dsbo,1,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER));
403 IDirectSoundBuffer_Release(dsbo);
406 /* Testing secondary buffers */
407 init_format(&wfx,11025,8,1);
408 bufdesc.dwSize=sizeof(bufdesc);
409 bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2;
410 bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
411 bufdesc.dwReserved=0;
412 bufdesc.lpwfxFormat=&wfx;
413 trace(" Testing a secondary buffer at %ldx%dx%d\n",
414 wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
415 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&dsbo,NULL);
416 ok(rc==DS_OK,"CreateSoundBuffer failed to create a secondary buffer 0x%lx\n",rc);
418 test_buffer(dso,dsbo,0,winetest_interactive);
419 IDirectSoundBuffer_Release(dsbo);
422 init_format(&wfx,48000,16,2);
423 bufdesc.dwSize=sizeof(bufdesc);
424 bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2;
425 bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000;
426 bufdesc.dwReserved=0;
427 bufdesc.lpwfxFormat=&wfx;
428 trace(" Testing a secondary buffer at %ldx%dx%d\n",
429 wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels);
430 rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&dsbo,NULL);
431 ok(rc==DS_OK,"CreateSoundBuffer failed to create a secondary buffer 0x%lx\n",rc);
433 test_buffer(dso,dsbo,0,winetest_interactive);
434 IDirectSoundBuffer_Release(dsbo);
439 IDirectSound_Release(dso);
443 static void dsound_out_tests()
446 rc=DirectSoundEnumerateA(&dsenum_callback,NULL);
447 ok(rc==DS_OK,"DirectSoundEnumerate failed: %ld\n",rc);