/* * Tests the panning and 3D functions of DirectSound * * Part of this test involves playing test tones. But this only makes * sense if someone is going to carefully listen to it, and would only * bother everyone else. * So this is only done if the test is being run in interactive mode. * * Copyright (c) 2002-2004 Francois Gouget * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include "wine/test.h" #include "dsound.h" #include "mmreg.h" #include "ks.h" #include "ksmedia.h" #include "dsound_test.h" #define PI 3.14159265358979323846 static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*, LPUNKNOWN)=NULL; char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size, BOOL ieee) { int i; int nb_samples; char* buf; char* b; nb_samples=(int)(duration*wfx->nSamplesPerSec); *size=nb_samples*wfx->nBlockAlign; b=buf=HeapAlloc(GetProcessHeap(), 0, *size); for (i=0;inSamplesPerSec); if (wfx->wBitsPerSample==8) { unsigned char sample=127.5*(y+1.0); *b++=sample; if (wfx->nChannels==2) *b++=sample; } else if (wfx->wBitsPerSample == 16) { signed short sample=32767.5*y-0.5; b[0]=sample & 0xff; b[1]=sample >> 8; b+=2; if (wfx->nChannels==2) { b[0]=sample & 0xff; b[1]=sample >> 8; b+=2; } } else if (wfx->wBitsPerSample == 24) { signed int sample=8388607.5*y-0.5; b[0]=sample & 0xff; b[1]=(sample >> 8)&0xff; b[2]=sample >> 16; b+=3; if (wfx->nChannels==2) { b[0]=sample & 0xff; b[1]=(sample >> 8)&0xff; b[2]=sample >> 16; b+=3; } } else if (wfx->wBitsPerSample == 32) { if (ieee) { float *ptr = (float *) b; *ptr = y; ptr++; b+=4; if (wfx->nChannels==2) { *ptr = y; b+=4; } } else { signed int sample=2147483647.5*y-0.5; b[0]=sample & 0xff; b[1]=(sample >> 8)&0xff; b[2]=(sample >> 16)&0xff; b[3]=sample >> 24; b+=4; if (wfx->nChannels==2) { b[0]=sample & 0xff; b[1]=(sample >> 8)&0xff; b[2]=(sample >> 16)&0xff; b[3]=sample >> 24; b+=4; } } } } return buf; } const char * getDSBCAPS(DWORD xmask) { static struct { DWORD mask; const char *name; } flags[] = { #define FE(x) { x, #x }, FE(DSBCAPS_PRIMARYBUFFER) FE(DSBCAPS_STATIC) FE(DSBCAPS_LOCHARDWARE) FE(DSBCAPS_LOCSOFTWARE) FE(DSBCAPS_CTRL3D) FE(DSBCAPS_CTRLFREQUENCY) FE(DSBCAPS_CTRLPAN) FE(DSBCAPS_CTRLVOLUME) FE(DSBCAPS_CTRLPOSITIONNOTIFY) FE(DSBCAPS_STICKYFOCUS) FE(DSBCAPS_GLOBALFOCUS) FE(DSBCAPS_GETCURRENTPOSITION2) FE(DSBCAPS_MUTE3DATMAXDISTANCE) #undef FE }; static char buffer[512]; unsigned int i; BOOL first = TRUE; buffer[0] = 0; for (i=0;iwFormatTag=format; wfx->nChannels=channels; wfx->wBitsPerSample=depth; wfx->nSamplesPerSec=rate; wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */ if (wfx->nBlockAlign==0) { /* align compressed formats to byte boundary */ wfx->nBlockAlign=1; } wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign; wfx->cbSize=0; } typedef struct { char* wave; DWORD wave_len; LPDIRECTSOUNDBUFFER dsbo; LPWAVEFORMATEX wfx; DWORD buffer_size; DWORD written; DWORD played; DWORD offset; } play_state_t; static int buffer_refill(play_state_t* state, DWORD size) { LPVOID ptr1,ptr2; DWORD len1,len2; HRESULT rc; if (size>state->wave_len-state->written) size=state->wave_len-state->written; /* some broken apps like Navyfield mistakenly pass NULL for a ppValue */ rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, &ptr1,NULL,&ptr2,&len2,0); ok(rc==DSERR_INVALIDPARAM,"expected %08x got %08x\n",DSERR_INVALIDPARAM, rc); rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, &ptr1,&len1,&ptr2,&len2,0); ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc); if (rc!=DS_OK) return -1; memcpy(ptr1,state->wave+state->written,len1); state->written+=len1; if (ptr2!=NULL) { memcpy(ptr2,state->wave+state->written,len2); state->written+=len2; } state->offset=state->written % state->buffer_size; /* some apps blindly pass &ptr1 instead of ptr1 */ rc=IDirectSoundBuffer_Unlock(state->dsbo,&ptr1,len1,ptr2,len2); ok(rc==DSERR_INVALIDPARAM, "IDDirectSoundBuffer_Unlock(): expected %08x got %08x, %p %p\n",DSERR_INVALIDPARAM, rc, &ptr1, ptr1); rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc); if (rc!=DS_OK) return -1; return size; } static int buffer_silence(play_state_t* state, DWORD size) { LPVOID ptr1,ptr2; DWORD len1,len2; HRESULT rc; BYTE s; rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, &ptr1,&len1,&ptr2,&len2,0); ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %08x\n", rc); if (rc!=DS_OK) return -1; s=(state->wfx->wBitsPerSample==8?0x80:0); memset(ptr1,s,len1); if (ptr2!=NULL) { memset(ptr2,s,len2); } state->offset=(state->offset+size) % state->buffer_size; rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %08x\n", rc); if (rc!=DS_OK) return -1; return size; } static int buffer_service(play_state_t* state) { DWORD last_play_pos,play_pos,buf_free; HRESULT rc; rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL); ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %08x\n", rc); if (rc!=DS_OK) { goto STOP; } /* Update the amount played */ last_play_pos=state->played % state->buffer_size; if (play_posplayed+=state->buffer_size-last_play_pos+play_pos; else state->played+=play_pos-last_play_pos; if (winetest_debug > 1) trace("buf size=%d last_play_pos=%d play_pos=%d played=%d / %d\n", state->buffer_size,last_play_pos,play_pos,state->played, state->wave_len); if (state->played>state->wave_len) { /* Everything has been played */ goto STOP; } /* Refill the buffer */ if (state->offset<=play_pos) buf_free=play_pos-state->offset; else buf_free=state->buffer_size-state->offset+play_pos; if (winetest_debug > 1) trace("offset=%d free=%d written=%d / %d\n", state->offset,buf_free,state->written,state->wave_len); if (buf_free==0) return 1; if (state->writtenwave_len) { int w=buffer_refill(state,buf_free); if (w==-1) goto STOP; buf_free-=w; if (state->written==state->wave_len && winetest_debug > 1) trace("last sound byte at %d\n", (state->written % state->buffer_size)); } if (buf_free>0) { /* Fill with silence */ if (winetest_debug > 1) trace("writing %d bytes of silence\n",buf_free); if (buffer_silence(state,buf_free)==-1) goto STOP; } return 1; STOP: if (winetest_debug > 1) trace("stopping playback\n"); rc=IDirectSoundBuffer_Stop(state->dsbo); ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %08x\n", rc); return 0; } void 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) { HRESULT rc; DSBCAPS dsbcaps; WAVEFORMATEX wfx,wfx2; DWORD size,status,freq; BOOL ieee = FALSE; int ref; if (set_frequency) { rc=IDirectSoundBuffer_SetFrequency(*dsbo,frequency); ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL, "IDirectSoundBuffer_SetFrequency() failed to set frequency %08x\n",rc); if (rc!=DS_OK) return; } /* DSOUND: Error: Invalid caps pointer */ rc=IDirectSoundBuffer_GetCaps(*dsbo,0); ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); ZeroMemory(&dsbcaps, sizeof(dsbcaps)); /* DSOUND: Error: Invalid caps pointer */ rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps); ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); dsbcaps.dwSize=sizeof(dsbcaps); rc=IDirectSoundBuffer_GetCaps(*dsbo,&dsbcaps); ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc); if (rc==DS_OK && winetest_debug > 1) { trace(" Caps: flags=0x%08x size=%d\n",dsbcaps.dwFlags, dsbcaps.dwBufferBytes); } /* Query the format size. */ size=0; rc=IDirectSoundBuffer_GetFormat(*dsbo,NULL,0,&size); ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have " "returned the needed size: rc=%08x size=%d\n",rc,size); ok(size == sizeof(WAVEFORMATEX) || size == sizeof(WAVEFORMATEXTENSIBLE), "Expected a correct structure size, got %d\n", size); if (size == sizeof(WAVEFORMATEX)) { rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,size,NULL); ieee = (wfx.wFormatTag == WAVE_FORMAT_IEEE_FLOAT); } else if (size == sizeof(WAVEFORMATEXTENSIBLE)) { WAVEFORMATEXTENSIBLE wfxe; rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL); wfx = wfxe.Format; ieee = IsEqualGUID(&wfxe.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); } else return; ok(rc==DS_OK, "IDirectSoundBuffer_GetFormat() failed: %08x\n", rc); if (rc==DS_OK && winetest_debug > 1) { trace(" Format: %s tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", is_primary ? "Primary" : "Secondary", wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); } /* DSOUND: Error: Invalid frequency buffer */ rc=IDirectSoundBuffer_GetFrequency(*dsbo,0); ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have " "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ rc=IDirectSoundBuffer_GetFrequency(*dsbo,&freq); ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), "IDirectSoundBuffer_GetFrequency() failed: %08x\n",rc); if (rc==DS_OK) { DWORD f = set_frequency?frequency:wfx.nSamplesPerSec; ok(freq==f,"The frequency returned by GetFrequency " "%d does not match the format %d\n",freq,f); } /* DSOUND: Error: Invalid status pointer */ rc=IDirectSoundBuffer_GetStatus(*dsbo,0); ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have " "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); rc=IDirectSoundBuffer_GetStatus(*dsbo,&status); ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc); ok(status==0,"status=0x%x instead of 0\n",status); if (is_primary) { DSBCAPS new_dsbcaps; /* We must call SetCooperativeLevel to be allowed to call SetFormat */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); if (rc!=DS_OK) return; /* DSOUND: Error: Invalid format pointer */ rc=IDirectSoundBuffer_SetFormat(*dsbo,0); ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have " "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); rc=IDirectSoundBuffer_SetFormat(*dsbo,&wfx2); ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat(%s) failed: %08x\n", format_string(&wfx2), rc); /* There is no guarantee that SetFormat will actually change the * format to what we asked for. It depends on what the soundcard * supports. So we must re-query the format. */ rc=IDirectSoundBuffer_GetFormat(*dsbo,&wfx,sizeof(wfx),NULL); ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %08x\n", rc); if (rc==DS_OK && (wfx.wFormatTag!=wfx2.wFormatTag || wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || wfx.wBitsPerSample!=wfx2.wBitsPerSample || wfx.nChannels!=wfx2.nChannels)) { trace("Requested format tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); trace("Got tag=0x%04x %dx%dx%d avg.B/s=%d align=%d\n", wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); } ZeroMemory(&new_dsbcaps, sizeof(new_dsbcaps)); new_dsbcaps.dwSize = sizeof(new_dsbcaps); rc=IDirectSoundBuffer_GetCaps(*dsbo,&new_dsbcaps); ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %08x\n", rc); if (rc==DS_OK && winetest_debug > 1) { trace(" new Caps: flags=0x%08x size=%d\n",new_dsbcaps.dwFlags, new_dsbcaps.dwBufferBytes); } /* Check for primary buffer size change */ ok(new_dsbcaps.dwBufferBytes == dsbcaps.dwBufferBytes, " buffer size changed after SetFormat() - " "previous size was %u, current size is %u\n", dsbcaps.dwBufferBytes, new_dsbcaps.dwBufferBytes); dsbcaps.dwBufferBytes = new_dsbcaps.dwBufferBytes; /* Check for primary buffer flags change */ ok(new_dsbcaps.dwFlags == dsbcaps.dwFlags, " flags changed after SetFormat() - " "previous flags were %08x, current flags are %08x\n", dsbcaps.dwFlags, new_dsbcaps.dwFlags); /* Set the CooperativeLevel back to normal */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); } if (play) { play_state_t state; DS3DLISTENER listener_param; LPDIRECTSOUND3DBUFFER buffer=NULL; DS3DBUFFER buffer_param; DWORD start_time,now; LPVOID buffer1; DWORD length1; if (winetest_interactive) { if (set_frequency) trace(" Playing %g second 440Hz tone at %dx%dx%d with a " "frequency of %d (%dHz)\n", duration, wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels, frequency, (440 * frequency) / wfx.nSamplesPerSec); else trace(" Playing %g second 440Hz tone at %dx%dx%d\n", duration, wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels); } if (is_primary) { /* We must call SetCooperativeLevel to be allowed to call Lock */ /* DSOUND: Setting DirectSound cooperative level to * DSSCL_WRITEPRIMARY */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(), DSSCL_WRITEPRIMARY); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) " "failed: %08x\n",rc); if (rc!=DS_OK) return; } if (buffer3d) { LPDIRECTSOUNDBUFFER temp_buffer; rc=IDirectSoundBuffer_QueryInterface(*dsbo,&IID_IDirectSound3DBuffer, (LPVOID *)&buffer); ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); if (rc!=DS_OK) return; /* check the COM interface */ rc=IDirectSoundBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer, (LPVOID *)&temp_buffer); ok(rc==DS_OK && temp_buffer!=NULL, "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n", temp_buffer,*dsbo); ref=IDirectSoundBuffer_Release(temp_buffer); ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " "should have 1\n",ref); temp_buffer=NULL; rc=IDirectSound3DBuffer_QueryInterface(*dsbo, &IID_IDirectSoundBuffer, (LPVOID *)&temp_buffer); ok(rc==DS_OK && temp_buffer!=NULL, "IDirectSound3DBuffer_QueryInterface() failed: %08x\n", rc); ok(temp_buffer==*dsbo,"COM interface broken: %p != %p\n", temp_buffer,*dsbo); ref=IDirectSoundBuffer_Release(temp_buffer); ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " "should have 1\n",ref); ref=IDirectSoundBuffer_Release(*dsbo); ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " "should have 0\n",ref); rc=IDirectSound3DBuffer_QueryInterface(buffer, &IID_IDirectSoundBuffer, (LPVOID *)dsbo); ok(rc==DS_OK && *dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() " "failed: %08x\n",rc); /* DSOUND: Error: Invalid buffer */ rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " "failed: %08x\n",rc); ZeroMemory(&buffer_param, sizeof(buffer_param)); /* DSOUND: Error: Invalid buffer */ rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " "failed: %08x\n",rc); buffer_param.dwSize=sizeof(buffer_param); rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %08x\n", rc); } if (set_volume) { if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { LONG val; rc=IDirectSoundBuffer_GetVolume(*dsbo,&val); ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc); rc=IDirectSoundBuffer_SetVolume(*dsbo,volume); ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %08x\n", rc); } else { /* DSOUND: Error: Buffer does not have CTRLVOLUME */ rc=IDirectSoundBuffer_GetVolume(*dsbo,&volume); ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() " "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc); } } if (set_pan) { if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { LONG val; rc=IDirectSoundBuffer_GetPan(*dsbo,&val); ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %08x\n", rc); rc=IDirectSoundBuffer_SetPan(*dsbo,pan); ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %08x\n", rc); } else { /* DSOUND: Error: Buffer does not have CTRLPAN */ rc=IDirectSoundBuffer_GetPan(*dsbo,&pan); ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() " "should have returned DSERR_CONTROLUNAVAIL, returned: %08x\n", rc); } } /* try an offset past the end of the buffer */ rc = IDirectSoundBuffer_Lock(*dsbo, dsbcaps.dwBufferBytes, 0, &buffer1, &length1, NULL, NULL, DSBLOCK_ENTIREBUFFER); ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have " "returned DSERR_INVALIDPARAM, returned %08x\n", rc); /* try a size larger than the buffer */ rc = IDirectSoundBuffer_Lock(*dsbo, 0, dsbcaps.dwBufferBytes + 1, &buffer1, &length1, NULL, NULL, DSBLOCK_FROMWRITECURSOR); ok(rc==DSERR_INVALIDPARAM, "IDirectSoundBuffer_Lock() should have " "returned DSERR_INVALIDPARAM, returned %08x\n", rc); if (set_frequency) state.wave=wave_generate_la(&wfx,(duration*frequency)/wfx.nSamplesPerSec,&state.wave_len,ieee); else state.wave=wave_generate_la(&wfx,duration,&state.wave_len,ieee); state.dsbo=*dsbo; state.wfx=&wfx; state.buffer_size=dsbcaps.dwBufferBytes; state.played=state.written=state.offset=0; buffer_refill(&state,state.buffer_size); rc=IDirectSoundBuffer_Play(*dsbo,0,0,DSBPLAY_LOOPING); ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %08x\n", rc); rc=IDirectSoundBuffer_GetStatus(*dsbo,&status); ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %08x\n", rc); ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), "GetStatus: bad status: %x\n",status); if (listener) { ZeroMemory(&listener_param,sizeof(listener_param)); listener_param.dwSize=sizeof(listener_param); rc=IDirectSound3DListener_GetAllParameters(listener, &listener_param); ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " "failed: %08x\n",rc); if (move_listener) { listener_param.vPosition.x = -5.0f; listener_param.vVelocity.x = (float)(10.0/duration); } rc=IDirectSound3DListener_SetAllParameters(listener, &listener_param, DS3D_IMMEDIATE); ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n", rc); } if (buffer3d) { if (move_sound) { buffer_param.vPosition.x = 100.0f; buffer_param.vVelocity.x = (float)(-200.0/duration); } buffer_param.flMinDistance = 10; rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param, DS3D_IMMEDIATE); ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc); } start_time=GetTickCount(); while (buffer_service(&state)) { WaitForSingleObject(GetCurrentProcess(),TIME_SLICE); now=GetTickCount(); if (listener && move_listener) { listener_param.vPosition.x = (float)(-5.0+10.0*(now-start_time)/1000/duration); if (winetest_debug>2) trace("listener position=%g\n",listener_param.vPosition.x); rc=IDirectSound3DListener_SetPosition(listener, listener_param.vPosition.x,listener_param.vPosition.y, listener_param.vPosition.z,DS3D_IMMEDIATE); ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %08x\n",rc); } if (buffer3d && move_sound) { buffer_param.vPosition.x = (float)(100-200.0*(now-start_time)/1000/duration); if (winetest_debug>2) trace("sound position=%g\n",buffer_param.vPosition.x); rc=IDirectSound3DBuffer_SetPosition(buffer, buffer_param.vPosition.x,buffer_param.vPosition.y, buffer_param.vPosition.z,DS3D_IMMEDIATE); ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %08x\n", rc); } } /* Check the sound duration was within 10% of the expected value */ now=GetTickCount(); ok(fabs(1000*duration-now+start_time)<=100*duration, "The sound played for %d ms instead of %g ms\n", now-start_time,1000*duration); HeapFree(GetProcessHeap(), 0, state.wave); if (is_primary) { /* Set the CooperativeLevel back to normal */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) " "failed: %08x\n",rc); } if (buffer3d) { ref=IDirectSound3DBuffer_Release(buffer); ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, " "should have 0\n",ref); } } } static HRESULT test_secondary(LPGUID lpGuid, int play, int has_3d, int has_3dbuffer, int has_listener, int has_duplicate, int move_listener, int move_sound) { HRESULT rc; LPDIRECTSOUND dso=NULL; LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; LPDIRECTSOUND3DLISTENER listener=NULL; DSBUFFERDESC bufdesc; WAVEFORMATEX wfx, wfx1; int ref; /* Create the DirectSound object */ rc=pDirectSoundCreate(lpGuid,&dso,NULL); ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); if (rc!=DS_OK) return rc; /* We must call SetCooperativeLevel before creating primary buffer */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); if (rc!=DS_OK) goto EXIT; ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; if (has_3d) bufdesc.dwFlags|=DSBCAPS_CTRL3D; else bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), "IDirectSound_CreateSoundBuffer() failed to create a %sprimary buffer: %08x\n",has_3d?"3D ":"", rc); if (rc==DSERR_CONTROLUNAVAIL) trace(" No Primary\n"); else if (rc==DS_OK && primary!=NULL) { rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL); ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc); if (rc!=DS_OK) goto EXIT1; if (has_listener) { rc=IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSound3DListener, (void **)&listener); ok(rc==DS_OK && listener!=NULL, "IDirectSoundBuffer_QueryInterface() failed to get a 3D listener: %08x\n",rc); ref=IDirectSoundBuffer_Release(primary); ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " "should have 0\n",ref); if (rc==DS_OK && listener!=NULL) { DS3DLISTENER listener_param; ZeroMemory(&listener_param,sizeof(listener_param)); /* DSOUND: Error: Invalid buffer */ rc=IDirectSound3DListener_GetAllParameters(listener,0); ok(rc==DSERR_INVALIDPARAM, "IDirectSound3dListener_GetAllParameters() should have " "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); /* DSOUND: Error: Invalid buffer */ rc=IDirectSound3DListener_GetAllParameters(listener, &listener_param); ok(rc==DSERR_INVALIDPARAM, "IDirectSound3dListener_GetAllParameters() should have " "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); listener_param.dwSize=sizeof(listener_param); rc=IDirectSound3DListener_GetAllParameters(listener, &listener_param); ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " "failed: %08x\n",rc); } else { ok(listener==NULL, "IDirectSoundBuffer_QueryInterface() " "failed but returned a listener anyway\n"); ok(rc!=DS_OK, "IDirectSoundBuffer_QueryInterface() succeeded " "but returned a NULL listener\n"); if (listener) { ref=IDirectSound3DListener_Release(listener); ok(ref==0,"IDirectSound3dListener_Release() listener has " "%d references, should have 0\n",ref); } goto EXIT2; } } init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); secondary=NULL; ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; if (has_3dbuffer) bufdesc.dwFlags|=DSBCAPS_CTRL3D; else bufdesc.dwFlags|= (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, wfx.nBlockAlign); bufdesc.lpwfxFormat=&wfx; if (winetest_interactive) { trace(" Testing a %s%ssecondary buffer %s%s%s%sat %dx%dx%d " "with a primary buffer at %dx%dx%d\n", has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", listener!=NULL?"listener ":"", listener&&move_sound?"and moving sound ":move_sound? "moving sound ":"", wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels); } rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); ok((rc==DS_OK && secondary!=NULL) || broken(rc == DSERR_CONTROLUNAVAIL), /* vmware drivers on w2k */ "IDirectSound_CreateSoundBuffer() failed to create a %s%ssecondary buffer %s%s%s%sat %dx%dx%d (%s): %08x\n", has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", listener!=NULL?"listener ":"", listener&&move_sound?"and moving sound ":move_sound? "moving sound ":"", wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, getDSBCAPS(bufdesc.dwFlags),rc); if (rc==DS_OK && secondary!=NULL) { IDirectSound3DBuffer *ds3d; rc=IDirectSoundBuffer_QueryInterface(secondary, &IID_IDirectSound3DBuffer, (void**)&ds3d); ok((has_3dbuffer && rc==DS_OK) || (!has_3dbuffer && rc==E_NOINTERFACE), "Wrong return trying to get 3D buffer on %s3D secondary interface: %08x\n", has_3dbuffer ? "" : "non-", rc); if(rc==DS_OK) IDirectSound3DBuffer_Release(ds3d); if (!has_3d) { LONG refvol,vol,refpan,pan; /* Check the initial secondary buffer's volume and pan */ rc=IDirectSoundBuffer_GetVolume(secondary,&vol); ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: %08x\n",rc); ok(vol==0,"wrong volume for a new secondary buffer: %d\n",vol); rc=IDirectSoundBuffer_GetPan(secondary,&pan); ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: %08x\n",rc); ok(pan==0,"wrong pan for a new secondary buffer: %d\n",pan); /* Check that changing the secondary buffer's volume and pan * does not impact the primary buffer's volume and pan */ rc=IDirectSoundBuffer_GetVolume(primary,&refvol); ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc); rc=IDirectSoundBuffer_GetPan(primary,&refpan); ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc); rc=IDirectSoundBuffer_SetVolume(secondary,-1000); ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); rc=IDirectSoundBuffer_GetVolume(secondary,&vol); ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); ok(vol==-1000,"secondary: wrong volume %d instead of -1000\n", vol); rc=IDirectSoundBuffer_SetPan(secondary,-1000); ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); rc=IDirectSoundBuffer_GetPan(secondary,&pan); ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); ok(pan==-1000,"secondary: wrong pan %d instead of -1000\n", pan); rc=IDirectSoundBuffer_GetVolume(primary,&vol); ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: %08x\n",rc); ok(vol==refvol,"The primary volume changed from %d to %d\n", refvol,vol); rc=IDirectSoundBuffer_GetPan(primary,&pan); ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %08x\n", rc); ok(pan==refpan,"The primary pan changed from %d to %d\n", refpan,pan); rc=IDirectSoundBuffer_SetVolume(secondary,0); ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: %08x\n",rc); rc=IDirectSoundBuffer_SetPan(secondary,0); ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: %08x\n",rc); } if (has_duplicate) { LPDIRECTSOUNDBUFFER duplicated=NULL; /* DSOUND: Error: Invalid source buffer */ rc=IDirectSound_DuplicateSoundBuffer(dso,0,0); ok(rc==DSERR_INVALIDPARAM, "IDirectSound_DuplicateSoundBuffer() should have returned " "DSERR_INVALIDPARAM, returned: %08x\n",rc); /* DSOUND: Error: Invalid dest buffer */ rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0); ok(rc==DSERR_INVALIDPARAM, "IDirectSound_DuplicateSoundBuffer() should have returned " "DSERR_INVALIDPARAM, returned: %08x\n",rc); /* DSOUND: Error: Invalid source buffer */ rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated); ok(rc==DSERR_INVALIDPARAM, "IDirectSound_DuplicateSoundBuffer() should have returned " "DSERR_INVALIDPARAM, returned: %08x\n",rc); duplicated=NULL; rc=IDirectSound_DuplicateSoundBuffer(dso,secondary, &duplicated); ok(rc==DS_OK && duplicated!=NULL, "IDirectSound_DuplicateSoundBuffer() failed to duplicate " "a secondary buffer: %08x\n",rc); if (rc==DS_OK && duplicated!=NULL) { ref=IDirectSoundBuffer_Release(secondary); ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " "references, should have 0\n",ref); secondary=duplicated; } } if (rc==DS_OK && secondary!=NULL) { double duration; duration=(move_listener || move_sound?4.0:1.0); test_buffer(dso,&secondary,0,FALSE,0,FALSE,0, winetest_interactive,duration,has_3dbuffer, listener,move_listener,move_sound,FALSE,0); ref=IDirectSoundBuffer_Release(secondary); ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, " "should have 0\n",has_duplicate?"duplicated":"secondary", ref); } } EXIT1: if (has_listener) { ref=IDirectSound3DListener_Release(listener); ok(ref==0,"IDirectSound3dListener_Release() listener has %d " "references, should have 0\n",ref); } else { ref=IDirectSoundBuffer_Release(primary); ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " "should have 0\n",ref); } } else { ok(primary==NULL,"IDirectSound_CreateSoundBuffer(primary) failed " "but primary created anyway\n"); ok(rc!=DS_OK,"IDirectSound_CreateSoundBuffer(primary) succeeded " "but primary not created\n"); if (primary) { ref=IDirectSoundBuffer_Release(primary); ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " "should have 0\n",ref); } } EXIT2: /* Set the CooperativeLevel back to normal */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc); EXIT: ref=IDirectSound_Release(dso); ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); if (ref!=0) return DSERR_GENERIC; return rc; } static HRESULT test_for_driver(LPGUID lpGuid) { HRESULT rc; LPDIRECTSOUND dso=NULL; int ref; /* Create the DirectSound object */ rc=pDirectSoundCreate(lpGuid,&dso,NULL); ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, "DirectSoundCreate() failed: %08x\n",rc); if (rc!=DS_OK) return rc; ref=IDirectSound_Release(dso); ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); if (ref!=0) return DSERR_GENERIC; return rc; } static HRESULT test_primary(LPGUID lpGuid) { HRESULT rc; LPDIRECTSOUND dso=NULL; LPDIRECTSOUNDBUFFER primary=NULL; DSBUFFERDESC bufdesc; DSCAPS dscaps; int ref, i; /* Create the DirectSound object */ rc=pDirectSoundCreate(lpGuid,&dso,NULL); ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); if (rc!=DS_OK) return rc; /* Get the device capabilities */ ZeroMemory(&dscaps, sizeof(dscaps)); dscaps.dwSize=sizeof(dscaps); rc=IDirectSound_GetCaps(dso,&dscaps); ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); if (rc!=DS_OK) goto EXIT; /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); if (rc!=DS_OK) goto EXIT; /* Testing the primary buffer */ primary=NULL; ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: %08x\n",rc); if (rc==DSERR_CONTROLUNAVAIL) trace(" No Primary\n"); else if (rc==DS_OK && primary!=NULL) { test_buffer(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0, FALSE,0); if (winetest_interactive) { LONG volume,pan; volume = DSBVOLUME_MAX; for (i = 0; i < 6; i++) { test_buffer(dso,&primary,1,TRUE,volume,TRUE,0, winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER), 1.0,0,NULL,0,0,FALSE,0); volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); } pan = DSBPAN_LEFT; for (i = 0; i < 7; i++) { test_buffer(dso,&primary,1,TRUE,0,TRUE,pan, winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,FALSE,0); pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); } } ref=IDirectSoundBuffer_Release(primary); ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " "should have 0\n",ref); } /* Set the CooperativeLevel back to normal */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc); EXIT: ref=IDirectSound_Release(dso); ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); if (ref!=0) return DSERR_GENERIC; return rc; } static HRESULT test_primary_3d(LPGUID lpGuid) { HRESULT rc; LPDIRECTSOUND dso=NULL; LPDIRECTSOUNDBUFFER primary=NULL; DSBUFFERDESC bufdesc; DSCAPS dscaps; int ref; /* Create the DirectSound object */ rc=pDirectSoundCreate(lpGuid,&dso,NULL); ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); if (rc!=DS_OK) return rc; /* Get the device capabilities */ ZeroMemory(&dscaps, sizeof(dscaps)); dscaps.dwSize=sizeof(dscaps); rc=IDirectSound_GetCaps(dso,&dscaps); ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); if (rc!=DS_OK) goto EXIT; /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); if (rc!=DS_OK) goto EXIT; primary=NULL; ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " "to create a primary buffer: %08x\n",rc); if (rc==DS_OK && primary!=NULL) { ref=IDirectSoundBuffer_Release(primary); ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " "should have 0\n",ref); primary=NULL; ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() " "failed to create a 3D primary buffer: %08x\n",rc); if (rc==DS_OK && primary!=NULL) { test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0, FALSE,0); ref=IDirectSoundBuffer_Release(primary); ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " "should have 0\n",ref); } } /* Set the CooperativeLevel back to normal */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n", rc); EXIT: ref=IDirectSound_Release(dso); ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); if (ref!=0) return DSERR_GENERIC; return rc; } static HRESULT test_primary_3d_with_listener(LPGUID lpGuid) { HRESULT rc; LPDIRECTSOUND dso=NULL; LPDIRECTSOUNDBUFFER primary=NULL; DSBUFFERDESC bufdesc; DSCAPS dscaps; int ref; /* Create the DirectSound object */ rc=pDirectSoundCreate(lpGuid,&dso,NULL); ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %08x\n", rc); if (rc!=DS_OK) return rc; /* Get the device capabilities */ ZeroMemory(&dscaps, sizeof(dscaps)); dscaps.dwSize=sizeof(dscaps); rc=IDirectSound_GetCaps(dso,&dscaps); ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); if (rc!=DS_OK) goto EXIT; /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: %08x\n",rc); if (rc!=DS_OK) goto EXIT; primary=NULL; ZeroMemory(&bufdesc, sizeof(bufdesc)); bufdesc.dwSize=sizeof(bufdesc); bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " "to create a 3D primary buffer: %08x\n",rc); if (rc==DS_OK && primary!=NULL) { LPDIRECTSOUND3DLISTENER listener=NULL; LPDIRECTSOUNDBUFFER temp_buffer=NULL; rc=IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSound3DListener,(void **)&listener); ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() " "failed to get a 3D listener: %08x\n",rc); if (rc==DS_OK && listener!=NULL) { /* Checking the COM interface */ rc=IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); ok(rc==DS_OK && temp_buffer!=NULL, "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); ok(temp_buffer==primary, "COM interface broken: %p != %p\n", temp_buffer,primary); if (rc==DS_OK && temp_buffer!=NULL) { ref=IDirectSoundBuffer_Release(temp_buffer); ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " "should have 1\n",ref); temp_buffer=NULL; rc=IDirectSound3DListener_QueryInterface(listener, &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); ok(rc==DS_OK && temp_buffer!=NULL, "IDirectSoundBuffer_QueryInterface() failed: %08x\n", rc); ok(temp_buffer==primary, "COM interface broken: %p != %p\n", temp_buffer,primary); ref=IDirectSoundBuffer_Release(temp_buffer); ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " "should have 1\n",ref); /* Testing the buffer */ test_buffer(dso,&primary,1,FALSE,0,FALSE,0, winetest_interactive && !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0, listener,0,0,FALSE,0); temp_buffer = NULL; rc = IDirectSound3DListener_QueryInterface(listener, &IID_IKsPropertySet, (void **)&temp_buffer); ok(rc==DS_OK && temp_buffer!=NULL, "IDirectSound3DListener_QueryInterface didn't handle IKsPropertySet: ret = %08x\n", rc); if(temp_buffer) IKsPropertySet_Release(temp_buffer); } /* Testing the reference counting */ ref=IDirectSound3DListener_Release(listener); ok(ref==0,"IDirectSound3DListener_Release() listener has %d " "references, should have 0\n",ref); } temp_buffer = NULL; rc = IDirectSoundBuffer_QueryInterface(primary, &IID_IKsPropertySet, (void **)&temp_buffer); ok(rc==DS_OK && temp_buffer!=NULL, "IDirectSoundBuffer_QueryInterface didn't handle IKsPropertySet on primary buffer: ret = %08x\n", rc); if(temp_buffer) IKsPropertySet_Release(temp_buffer); /* Testing the reference counting */ ref=IDirectSoundBuffer_Release(primary); ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " "should have 0\n",ref); } EXIT: ref=IDirectSound_Release(dso); ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); if (ref!=0) return DSERR_GENERIC; return rc; } static unsigned driver_count = 0; static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) { HRESULT rc; trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); driver_count++; rc = test_for_driver(lpGuid); if (rc == DSERR_NODRIVER) { trace(" No Driver\n"); return 1; } else if (rc == DSERR_ALLOCATED) { trace(" Already In Use\n"); return 1; } else if (rc == E_FAIL) { trace(" No Device\n"); return 1; } trace(" Testing the primary buffer\n"); test_primary(lpGuid); trace(" Testing 3D primary buffer\n"); test_primary_3d(lpGuid); trace(" Testing 3D primary buffer with listener\n"); test_primary_3d_with_listener(lpGuid); /* Testing secondary buffers */ test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0); test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0); /* Testing 3D secondary buffers */ test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0); test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0); test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0); test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0); test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0); test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0); test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0); test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0); test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1); test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1); return 1; } static void ds3d_tests(void) { HRESULT rc; rc=pDirectSoundEnumerateA(&dsenum_callback,NULL); ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc); trace("tested %u DirectSound drivers\n", driver_count); } START_TEST(ds3d) { HMODULE hDsound; CoInitialize(NULL); hDsound = LoadLibraryA("dsound.dll"); if (hDsound) { pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound, "DirectSoundEnumerateA"); pDirectSoundCreate = (void*)GetProcAddress(hDsound, "DirectSoundCreate"); ds3d_tests(); FreeLibrary(hDsound); } else skip("dsound.dll not found - skipping all tests\n"); CoUninitialize(); }