diff --git a/rostests/winetests/dsound/capture.c b/rostests/winetests/dsound/capture.c new file mode 100644 index 00000000000..87a5a59aca7 --- /dev/null +++ b/rostests/winetests/dsound/capture.c @@ -0,0 +1,709 @@ +/* + * Unit tests for capture functions + * + * Copyright (c) 2002 Francois Gouget + * Copyright (c) 2003 Robert Reif + * + * 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 "initguid.h" +#include "windows.h" +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.h" +#include "dsconf.h" + +#include "dsound_test.h" + +#define NOTIFICATIONS 5 + +static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID,LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; + +static const char * get_format_str(WORD format) +{ + static char msg[32]; +#define WAVE_FORMAT(f) case f: return #f + switch (format) { + WAVE_FORMAT(WAVE_FORMAT_PCM); + WAVE_FORMAT(WAVE_FORMAT_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD); + WAVE_FORMAT(WAVE_FORMAT_ALAW); + WAVE_FORMAT(WAVE_FORMAT_MULAW); + WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_DIGISTD); + WAVE_FORMAT(WAVE_FORMAT_DIGIFIX); + WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SONARC); + WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH); + WAVE_FORMAT(WAVE_FORMAT_ECHOSC1); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36); + WAVE_FORMAT(WAVE_FORMAT_APTX); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10); + WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2); + WAVE_FORMAT(WAVE_FORMAT_GSM610); + WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC); + WAVE_FORMAT(WAVE_FORMAT_DIGIREAL); + WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10); + WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM); + WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MPEG); + WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10); + WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND); + WAVE_FORMAT(WAVE_FORMAT_OLIGSM); + WAVE_FORMAT(WAVE_FORMAT_OLIADPCM); + WAVE_FORMAT(WAVE_FORMAT_OLICELP); + WAVE_FORMAT(WAVE_FORMAT_OLISBC); + WAVE_FORMAT(WAVE_FORMAT_OLIOPR); + WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT); + WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE); + } +#undef WAVE_FORMAT + sprintf(msg, "Unknown(0x%04x)", format); + return msg; +} + +const char * format_string(const WAVEFORMATEX* wfx) +{ + static char str[64]; + + sprintf(str, "%5dx%2dx%d %s", + wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels, + get_format_str(wfx->wFormatTag)); + + return str; +} + +static void IDirectSoundCapture_test(LPDIRECTSOUNDCAPTURE dsco, + BOOL initialized, LPCGUID lpGuid) +{ + HRESULT rc; + DSCCAPS dsccaps; + int ref; + IUnknown * unknown; + IDirectSoundCapture * dsc; + + /* Try to Query for objects */ + rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IUnknown, + (LPVOID*)&unknown); + ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IUnknown) " + "failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSoundCapture_Release(unknown); + + rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IDirectSoundCapture, + (LPVOID*)&dsc); + ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IDirectSoundCapture) " + "failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSoundCapture_Release(dsc); + + if (initialized == FALSE) { + /* try uninitialized object */ + rc=IDirectSoundCapture_GetCaps(dsco,0); + ok(rc==DSERR_UNINITIALIZED||rc==E_INVALIDARG, + "IDirectSoundCapture_GetCaps(NULL) should have returned " + "DSERR_UNINITIALIZED or E_INVALIDARG, returned: %08x\n", rc); + + rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSoundCapture_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSoundCapture_Initialize(dsco, lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED|| + rc==E_FAIL||rc==E_INVALIDARG, + "IDirectSoundCapture_Initialize() failed: %08x\n", rc); + if (rc==DSERR_NODRIVER||rc==E_INVALIDARG) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSoundCapture_Initialize(dsco, lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSoundCapture_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSoundCapture_GetCaps(dsco, 0); + ok(rc==DSERR_INVALIDPARAM, "IDirectSoundCapture_GetCaps(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + ZeroMemory(&dsccaps, sizeof(dsccaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dsco, &dsccaps); + ok(rc==DSERR_INVALIDPARAM, "IDirectSound_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dsccaps.dwSize=sizeof(dsccaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps); + ok(rc==DS_OK, "IDirectSoundCapture_GetCaps() failed: %08x\n", rc); + +EXIT: + ref=IDirectSoundCapture_Release(dsco); + ok(ref==0, "IDirectSoundCapture_Release() has %d references, " + "should have 0\n", ref); +} + +static void IDirectSoundCapture_tests(void) +{ + HRESULT rc; + LPDIRECTSOUNDCAPTURE dsco=NULL; + LPCLASSFACTORY cf=NULL; + + trace("Testing IDirectSoundCapture\n"); + + rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL, + &IID_IClassFactory, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) " + "failed: %08x\n", rc); + + rc=CoGetClassObject(&CLSID_DirectSoundCapture, CLSCTX_INPROC_SERVER, NULL, + &IID_IUnknown, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSoundCapture, IID_IUnknown) " + "failed: %08x\n", rc); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc); + if (rc==REGDB_E_CLASSNOTREG) { + trace(" Class Not Registered\n"); + return; + } + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, NULL); + + /* try the COM class factory method of creation with default capture + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc); + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultCapture); + + /* try the COM class factory method of creation with default voice + * capture device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %08x\n", rc); + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultVoiceCapture); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dsco); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSoundCapture,CLSID_DirectSoundPrivate) " + "should have failed: %08x\n",rc); + + /* try with no device specified */ + rc=pDirectSoundCaptureCreate(NULL,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(NULL) failed: %08x\n",rc); + if (rc==S_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with default capture device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultCapture,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(DSDEVID_DefaultCapture) failed: %08x\n", rc); + if (rc==DS_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with default voice capture device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoiceCapture,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(DSDEVID_DefaultVoiceCapture) failed: %08x\n", rc); + if (rc==DS_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoicePlayback,&dsco,NULL); + ok(rc==DSERR_NODRIVER, + "DirectSoundCaptureCreate(DSDEVID_DefaultVoicePlatback) " + "should have failed: %08x\n",rc); + if (rc==DS_OK && dsco) + IDirectSoundCapture_Release(dsco); +} + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDCAPTUREBUFFER dscbo; + LPWAVEFORMATEX wfx; + DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS]; + HANDLE event[NOTIFICATIONS]; + LPDIRECTSOUNDNOTIFY notify; + + DWORD buffer_size; + DWORD read; + DWORD offset; + DWORD size; + + DWORD last_pos; +} capture_state_t; + +static int capture_buffer_service(capture_state_t* state) +{ + HRESULT rc; + LPVOID ptr1,ptr2; + DWORD len1,len2; + DWORD capture_pos,read_pos; + + rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos, + &read_pos); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCurrentPosition() failed: %08x\n", rc); + if (rc!=DS_OK) + return 0; + + rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Lock() failed: %08x\n", rc); + if (rc!=DS_OK) + return 0; + + rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Unlock() failed: %08x\n", rc); + if (rc!=DS_OK) + return 0; + + state->offset = (state->offset + state->size) % state->buffer_size; + + return 1; +} + +static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, + LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record) +{ + HRESULT rc; + DSCBCAPS dscbcaps; + WAVEFORMATEX wfx; + DWORD size,status; + capture_state_t state; + int i, ref; + + /* Private dsound.dll: Error: Invalid caps pointer */ + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + /* Private dsound.dll: Error: Invalid caps pointer */ + dscbcaps.dwSize=0; + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dscbcaps.dwSize=sizeof(dscbcaps); + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: size = %d flags=0x%08x buffer size=%d\n", + dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes); + } + + /* Query the format size. Note that it may not match sizeof(wfx) */ + /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must + * be non-NULL */ + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetFormat() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + size=0; + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size); + ok(rc==DS_OK && size!=0,"IDirectSoundCaptureBuffer_GetFormat() should " + "have returned the needed size: rc=%08x, size=%d\n", rc,size); + + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetFormat() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Format: 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); + } + + /* Private dsound.dll: Error: Invalid status pointer */ + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetStatus() should " + "have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Status=0x%04x\n",status); + } + + ZeroMemory(&state, sizeof(state)); + state.dscbo=dscbo; + state.wfx=&wfx; + state.buffer_size = dscbcaps.dwBufferBytes; + for (i = 0; i < NOTIFICATIONS; i++) + state.event[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); + state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS; + + rc=IDirectSoundCaptureBuffer_QueryInterface(dscbo,&IID_IDirectSoundNotify, + (void **)&(state.notify)); + ok((rc==DS_OK)&&(state.notify!=NULL), + "IDirectSoundCaptureBuffer_QueryInterface() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + for (i = 0; i < NOTIFICATIONS; i++) { + state.posnotify[i].dwOffset = (i * state.size) + state.size - 1; + state.posnotify[i].hEventNotify = state.event[i]; + } + + rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS, + state.posnotify); + ok(rc==DS_OK,"IDirectSoundNotify_SetNotificationPositions() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + ref=IDirectSoundNotify_Release(state.notify); + ok(ref==0,"IDirectSoundNotify_Release(): has %d references, should have " + "0\n",ref); + if (ref!=0) + return; + + if (record) { + rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Start() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %08x\n", rc); + ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING), + "GetStatus: bad status: %x\n",status); + if (rc!=DS_OK) + return; + + /* wait for the notifications */ + for (i = 0; i < (NOTIFICATIONS * 2); i++) { + rc=WaitForMultipleObjects(NOTIFICATIONS,state.event,FALSE,3000); + ok(rc==(WAIT_OBJECT_0+(i%NOTIFICATIONS)), + "WaitForMultipleObjects failed: 0x%x\n",rc); + if (rc!=(WAIT_OBJECT_0+(i%NOTIFICATIONS))) { + ok((rc==WAIT_TIMEOUT)||(rc==WAIT_FAILED), + "Wrong notification: should be %d, got %d\n", + i%NOTIFICATIONS,rc-WAIT_OBJECT_0); + } + if (!capture_buffer_service(&state)) + break; + } + + rc=IDirectSoundCaptureBuffer_Stop(dscbo); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Stop() failed: %08x\n", rc); + if (rc!=DS_OK) + return; + } +} + +static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + LPDIRECTSOUNDCAPTURE dsco=NULL; + LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL; + DSCBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + DSCCAPS dsccaps; + DWORD f; + int ref; + + /* Private dsound.dll: Error: Invalid interface buffer */ + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + rc=pDirectSoundCaptureCreate(lpGuid,NULL,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + rc=pDirectSoundCaptureCreate(lpGuid,&dsco,NULL); + ok((rc==DS_OK)||(rc==DSERR_NODRIVER)||(rc==E_FAIL)||(rc==DSERR_ALLOCATED), + "DirectSoundCaptureCreate() failed: %08x\n",rc); + if (rc!=DS_OK) { + if (rc==DSERR_NODRIVER) + trace(" No Driver\n"); + else if (rc==E_FAIL) + trace(" No Device\n"); + else if (rc==DSERR_ALLOCATED) + trace(" Already In Use\n"); + goto EXIT; + } + + /* Private dsound.dll: Error: Invalid caps buffer */ + rc=IDirectSoundCapture_GetCaps(dsco,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* Private dsound.dll: Error: Invalid caps buffer */ + dsccaps.dwSize=0; + rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + dsccaps.dwSize=sizeof(dsccaps); + rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); + ok(rc==DS_OK,"IDirectSoundCapture_GetCaps() failed: %08x\n", rc); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: size=%d flags=0x%08x formats=%05x channels=%d\n", + dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats, + dsccaps.dwChannels); + } + + /* Private dsound.dll: Error: Invalid size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=0; + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + ZeroMemory(&wfx, sizeof(wfx)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + for (f=0;f + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.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) +{ + 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=(unsigned char)((double)127.5*(y+1.0)); + *b++=sample; + if (wfx->nChannels==2) + *b++=sample; + } else if (wfx->wBitsPerSample == 16) { + signed short sample=(signed short)((double)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=(signed int)((double)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) { + signed int sample=(signed int)((double)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; + 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); + } + else if (size == sizeof(WAVEFORMATEXTENSIBLE)) { + WAVEFORMATEXTENSIBLE wfxe; + rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL); + wfx = wfxe.Format; + } + 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); + else + state.wave=wave_generate_la(&wfx,duration,&state.wave_len); + + 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_3d) + 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,"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) { + 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; + 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) { + LPDIRECTSOUNDBUFFER temp_buffer=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); + } + + /* Testing the reference counting */ + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3DListener_Release() listener has %d " + "references, should have 0\n",ref); + } + + /* 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 BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + 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); +} + +START_TEST(ds3d) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound, + "DirectSoundEnumerateA"); + pDirectSoundCreate = (void*)GetProcAddress(hDsound, + "DirectSoundCreate"); + + ds3d_tests(); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/ds3d8.c b/rostests/winetests/dsound/ds3d8.c new file mode 100644 index 00000000000..8ad428d3edc --- /dev/null +++ b/rostests/winetests/dsound/ds3d8.c @@ -0,0 +1,1154 @@ +/* + * 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 "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; + +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_refill8(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; + + 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; + 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_silence8(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_service8(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_refill8(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_silence8(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_buffer8(LPDIRECTSOUND8 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) +{ + HRESULT rc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx,wfx2; + DWORD size,status,freq; + int ref; + + /* 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); + } else if (size == sizeof(WAVEFORMATEXTENSIBLE)) { + WAVEFORMATEXTENSIBLE wfxe; + rc=IDirectSoundBuffer_GetFormat(*dsbo,(WAVEFORMATEX*)&wfxe,size,NULL); + wfx = wfxe.Format; + } + 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) { + ok(freq==wfx.nSamplesPerSec,"The frequency returned by GetFrequency " + "%d does not match the format %d\n",freq,wfx.nSamplesPerSec); + } + + /* 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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_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) { + 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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(), + DSSCL_WRITEPRIMARY); + ok(rc==DS_OK, + "IDirectSound8_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); + + state.wave=wave_generate_la(&wfx,duration,&state.wave_len); + + state.dsbo=*dsbo; + state.wfx=&wfx; + state.buffer_size=dsbcaps.dwBufferBytes; + state.played=state.written=state.offset=0; + buffer_refill8(&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_service8(&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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_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_secondary8(LPGUID lpGuid, int play, + int has_3d, int has_3dbuffer, + int has_listener, int has_duplicate, + int move_listener, int move_sound) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + LPDIRECTSOUND3DLISTENER listener=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx, wfx1; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() 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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL), + "IDirectSound8_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_3d) + 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 (has_3d) { + /* a stereo 3D buffer should fail */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_CreateSoundBuffer(secondary) should have " + "returned DSERR_INVALIDPARAM, returned %08x\n", rc); + if (secondary) + ref=IDirectSoundBuffer_Release(secondary); + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,1); + } + + 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=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL,"IDirectSound8_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) { + 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: i%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=IDirectSound8_DuplicateSoundBuffer(dso,0,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid dest buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,0,&duplicated); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + duplicated=NULL; + rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary, + &duplicated); + ok(rc==DS_OK && duplicated!=NULL, + "IDirectSound8_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_buffer8(dso,&secondary,0,FALSE,0,FALSE,0, + winetest_interactive,duration,has_3dbuffer, + listener,move_listener,move_sound); + 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) { + if (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,"IDirectSound8_CreateSoundBuffer(primary) failed " + "but primary created anyway\n"); + ok(rc!=DS_OK,"IDirectSound8_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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_for_driver8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref, i; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL), + "IDirectSound8_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_buffer8(dso,&primary,1,TRUE,0,TRUE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0); + if (winetest_interactive) { + LONG volume,pan; + + volume = DSBVOLUME_MAX; + for (i = 0; i < 6; i++) { + test_buffer8(dso,&primary,1,TRUE,volume,TRUE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,NULL,0,0); + volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); + } + + pan = DSBPAN_LEFT; + for (i = 0; i < 7; i++) { + test_buffer8(dso,&primary,1,TRUE,0,TRUE,pan, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_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=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() " + "failed to create a 3D primary buffer: %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + test_buffer8(dso,&primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: %08x\n",rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d_with_listener8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %08x\n", rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_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=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " + "to create a 3D primary buffer %08x\n",rc); + if (rc==DS_OK && primary!=NULL) { + LPDIRECTSOUND3DLISTENER listener=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) { + LPDIRECTSOUNDBUFFER temp_buffer=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_buffer8(dso,&primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,listener,0,0); + } + + /* Testing the reference counting */ + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3DListener_Release() listener has %d " + "references, should have 0\n",ref); + } + + /* Testing the reference counting */ + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) +return DSERR_GENERIC; + + return rc; +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + rc = test_for_driver8(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_primary8(lpGuid); + + trace(" Testing 3D primary buffer\n"); + test_primary_3d8(lpGuid); + + trace(" Testing 3D primary buffer with listener\n"); + test_primary_3d_with_listener8(lpGuid); + + /* Testing secondary buffers */ + test_secondary8(lpGuid,winetest_interactive,0,0,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,0,0,0,1,0,0); + + /* Testing 3D secondary buffers */ + test_secondary8(lpGuid,winetest_interactive,1,0,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,0,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,0,1,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,0,1,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,1); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,1); + + return 1; +} + +static void ds3d8_tests(void) +{ + HRESULT rc; + rc=pDirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc); +} + +START_TEST(ds3d8) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound, + "DirectSoundEnumerateA"); + pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, + "DirectSoundCreate8"); + if (pDirectSoundCreate8) + ds3d8_tests(); + else + skip("ds3d8 test skipped\n"); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/dsound.c b/rostests/winetests/dsound/dsound.c new file mode 100644 index 00000000000..114dbb6ced2 --- /dev/null +++ b/rostests/winetests/dsound/dsound.c @@ -0,0 +1,1103 @@ +/* + * Tests basic sound playback in DirectSound. + * In particular we test each standard Windows sound format to make sure + * we handle the sound card/driver quirks correctly. + * + * 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 + * Copyright (c) 2007 Maarten Lankhorst + * + * 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 "wine/test.h" +#include "dsound.h" +#include "dsconf.h" +#include "mmreg.h" +#include "initguid.h" +#include "ks.h" +#include "ksmedia.h" + +#include "dsound_test.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*, + LPUNKNOWN)=NULL; + +static BOOL gotdx8; + +static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, + LPCGUID lpGuid) +{ + HRESULT rc; + DSCAPS dscaps; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + DWORD speaker_config, new_speaker_config; + + /* Try to Query for objects */ + rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IUnknown) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound_Release(unknown); + + rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IDirectSound) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound_Release(ds); + + rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==E_NOINTERFACE,"IDirectSound_QueryInterface(IID_IDirectSound8) " + "should have failed: %08x\n",rc); + if (rc==DS_OK) + IDirectSound8_Release(ds8); + + if (initialized == FALSE) { + /* try uninitialized object */ + rc=IDirectSound_GetCaps(dso,0); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps(NULL) " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_Compact(dso); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_Compact() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetSpeakerConfig() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound_Initialize(dso,lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "IDirectSound_Initialize() failed: %08x\n",rc); + if (rc==DSERR_NODRIVER) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSound_Initialize(dso,lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + ZeroMemory(&dscaps, sizeof(dscaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dscaps.dwSize=sizeof(dscaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %08x\n",rc); + + rc=IDirectSound_Compact(dso); + ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound_Compact() failed: %08x\n", rc); + + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %08x\n", rc); + + rc=IDirectSound_Compact(dso); + ok(rc==DS_OK,"IDirectSound_Compact() failed: %08x\n",rc); + + rc=IDirectSound_GetSpeakerConfig(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetSpeakerConfig(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc); + + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_WIDE); + rc=IDirectSound_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK) { + rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config); + ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK && speaker_config!=new_speaker_config) + trace("IDirectSound_GetSpeakerConfig() failed to set speaker " + "config: expected 0x%08x, got 0x%08x\n", + speaker_config,new_speaker_config); + } + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); +} + +static void IDirectSound_tests(void) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPCLASSFACTORY cf=NULL; + + trace("Testing IDirectSound\n"); + + rc=CoGetClassObject(&CLSID_DirectSound, CLSCTX_INPROC_SERVER, NULL, + &IID_IClassFactory, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound, IID_IClassFactory) " + "failed: %08x\n", rc); + + rc=CoGetClassObject(&CLSID_DirectSound, CLSCTX_INPROC_SERVER, NULL, + &IID_IUnknown, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound, IID_IUnknown) " + "failed: %08x\n", rc); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, NULL); + + /* try the COM class factory method of creation with default playback + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * playback device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dso); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSound,CLSID_DirectSoundPrivate) " + "should have failed: %08x\n",rc); + + /* try the COM class factory method of creation with a bad + * GUID and IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==REGDB_E_CLASSNOTREG, + "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound) " + "should have failed: %08x\n",rc); + + /* try with no device specified */ + rc=pDirectSoundCreate(NULL,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(NULL) failed: %08x\n",rc); + if (rc==S_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with default playback device specified */ + rc=pDirectSoundCreate(&DSDEVID_DefaultPlayback,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(DSDEVID_DefaultPlayback) failed: %08x\n", rc); + if (rc==DS_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with default voice playback device specified */ + rc=pDirectSoundCreate(&DSDEVID_DefaultVoicePlayback,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(DSDEVID_DefaultVoicePlayback) failed: %08x\n", rc); + if (rc==DS_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCreate(&DSDEVID_DefaultVoiceCapture,&dso,NULL); + ok(rc==DSERR_NODRIVER,"DirectSoundCreate(DSDEVID_DefaultVoiceCapture) " + "should have failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound_Release(dso); +} + +static HRESULT test_dsound(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + int ref; + + /* DSOUND: Error: Invalid interface buffer */ + rc=pDirectSoundCreate(lpGuid,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* 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; + + /* Try the enumerated device */ + IDirectSound_test(dso, TRUE, lpGuid); + + /* Try the COM class factory method of creation with enumerated device */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound_test(dso, FALSE, lpGuid); + + /* Create a DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUND dso1=NULL; + + /* Create a second DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso1,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc); + if (rc==DS_OK) { + /* Release the second DirectSound object */ + ref=IDirectSound_Release(dso1); + ok(ref==0,"IDirectSound_Release() has %d references, should have " + "0\n",ref); + ok(dso!=dso1,"DirectSound objects should be unique: dso=%p,dso1=%p\n",dso,dso1); + } + + /* Release the first DirectSound object */ + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + /* Create a DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUNDBUFFER secondary; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a secondary " + "buffer %08x\n",rc); + if (rc==DS_OK && secondary!=NULL) { + LPDIRECTSOUND3DBUFFER buffer3d; + rc=IDirectSound_QueryInterface(secondary, &IID_IDirectSound3DBuffer, + (void **)&buffer3d); + ok(rc==DS_OK && buffer3d!=NULL,"IDirectSound_QueryInterface() " + "failed: %08x\n",rc); + if (rc==DS_OK && buffer3d!=NULL) { + ref=IDirectSound3DBuffer_AddRef(buffer3d); + ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + ref=IDirectSoundBuffer_AddRef(secondary); + ok(ref==2,"IDirectSoundBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + /* release with buffer */ + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + return DS_OK; +} + +static HRESULT test_primary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "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; + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_CreateSoundBuffer() should have failed: %08x\n", rc); + + /* DSOUND: Error: NULL pointer is invalid */ + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "dsbo=%p\n",rc,primary); + + /* DSOUND: Error: Invalid size */ + /* DSOUND: Error: Invalid buffer description */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc)-1; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* DSOUND: Error: DSBCAPS_PRIMARYBUFFER flag with non-NULL lpwfxFormat */ + /* DSOUND: Error: Invalid buffer description pointer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* DSOUND: Error: No DSBCAPS_PRIMARYBUFFER flag with NULL lpwfxFormat */ + /* DSOUND: Error: Invalid buffer description pointer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* 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() 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; + bufdesc.lpwfxFormat = &wfx; + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK && primary!=NULL) + IDirectSoundBuffer_Release(primary); + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + 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) { + LONG vol; + + /* Try to create a second primary buffer */ + /* DSOUND: Error: The primary buffer already exists. + * Any changes made to the buffer description will be ignored. */ + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&second,NULL); + ok(rc==DS_OK && second==primary, + "IDirectSound_CreateSoundBuffer() should have returned original " + "primary buffer: %08x\n",rc); + ref=IDirectSoundBuffer_Release(second); + ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 1\n",ref); + + /* Try to duplicate a primary buffer */ + /* DSOUND: Error: Can't duplicate primary buffers */ + rc=IDirectSound_DuplicateSoundBuffer(dso,primary,&third); + /* rc=0x88780032 */ + ok(rc!=DS_OK,"IDirectSound_DuplicateSoundBuffer() primary buffer " + "should have failed %08x\n",rc); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc); + + if (winetest_interactive) { + trace("Playing a 5 seconds reference tone at the current " + "volume.\n"); + if (rc==DS_OK) + trace("(the current volume is %d according to DirectSound)\n", + vol); + trace("All subsequent tones should be identical to this one.\n"); + trace("Listen for stutter, changes in pitch, volume, etc.\n"); + } + test_buffer(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.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() 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; +} + +/* + * Test the primary buffer at different formats while keeping the + * secondary buffer at a constant format. + */ +static HRESULT test_primary_secondary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx2; + int f,ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "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 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() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + 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) { + for (f=0;f 16) + ok(((rc == DSERR_CONTROLUNAVAIL || rc == DSERR_INVALIDCALL || rc == DSERR_INVALIDPARAM /* 2003 */) && !secondary) + || rc == DS_OK, /* driver dependent? */ + "IDirectSound_CreateSoundBuffer() " + "should have returned (DSERR_CONTROLUNAVAIL or DSERR_INVALIDCALL) " + "and NULL, returned: %08x %p\n", rc, secondary); + else + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc); + } + else + ok(rc==E_INVALIDARG, "Creating %d bpp buffer on dx < 8 returned: %p %08x\n", + wfx.wBitsPerSample, secondary, rc); + + if (!gotdx8) + { + skip("Not doing the WAVE_FORMAT_EXTENSIBLE tests\n"); + /* Apparently they succeed with bogus values, + * which means that older dsound doesn't look at them + */ + goto no_wfe; + } + + if (secondary) + IDirectSoundBuffer_Release(secondary); + secondary = NULL; + + bufdesc.lpwfxFormat=(WAVEFORMATEX*)&wfxe; + wfxe.Format = wfx; + wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + wfxe.Format.cbSize = 1; + wfxe.Samples.wValidBitsPerSample = wfx.wBitsPerSample; + wfxe.dwChannelMask = (wfx.nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO); + + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL /* 2003 */) && !secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + + wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx) + 1; + + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(((rc==DSERR_CONTROLUNAVAIL || rc==DSERR_INVALIDCALL || rc==DSERR_INVALIDPARAM) + && !secondary) + || rc==DS_OK, /* 2003 / 2008 */ + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + + wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfx); + wfxe.SubFormat = GUID_NULL; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok((rc==DSERR_INVALIDPARAM || rc==DSERR_INVALIDCALL) && !secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + ++wfxe.Samples.wValidBitsPerSample; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DSERR_INVALIDPARAM && !secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + --wfxe.Samples.wValidBitsPerSample; + + wfxe.Samples.wValidBitsPerSample = 0; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary, + "IDirectSound_CreateSoundBuffer() returned: %08x %p\n", + rc, secondary); + if (secondary) + { + IDirectSoundBuffer_Release(secondary); + secondary=NULL; + } + wfxe.Samples.wValidBitsPerSample = wfxe.Format.wBitsPerSample; + + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a secondary buffer %08x\n",rc); + +no_wfe: + if (rc==DS_OK && secondary!=NULL) { + if (winetest_interactive) { + trace(" Testing a secondary buffer at %dx%dx%d " + "with a primary buffer at %dx%dx%d\n", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels); + } + test_buffer(dso,&secondary,0,FALSE,0,FALSE,0, + winetest_interactive,1.0,0,NULL,0,0,FALSE,0); + + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " + "should have 0\n",ref); + } + } +EXIT1: + 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() 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_block_align(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER secondary=NULL; + DSBUFFERDESC bufdesc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx; + DWORD pos, pos2; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,16,2); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; + bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec + 1; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK,"IDirectSound_CreateSoundBuffer() " + "should have returned DS_OK, returned: %08x\n", rc); + + if (rc==DS_OK && secondary!=NULL) { + ZeroMemory(&dsbcaps, sizeof(dsbcaps)); + dsbcaps.dwSize = sizeof(dsbcaps); + rc=IDirectSoundBuffer_GetCaps(secondary,&dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() should have returned DS_OK, " + "returned: %08x\n", rc); + if (rc==DS_OK && wfx.nBlockAlign > 1) + { + ok(dsbcaps.dwBufferBytes==(wfx.nAvgBytesPerSec + wfx.nBlockAlign), + "Buffer size not a multiple of nBlockAlign: requested %d, " + "got %d, should be %d\n", bufdesc.dwBufferBytes, + dsbcaps.dwBufferBytes, wfx.nAvgBytesPerSec + wfx.nBlockAlign); + + rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 0); + ok(rc == DS_OK, "Could not set position to 0: %08x\n", rc); + rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos, NULL); + ok(rc == DS_OK, "Could not get position: %08x\n", rc); + rc = IDirectSoundBuffer_SetCurrentPosition(secondary, 1); + ok(rc == DS_OK, "Could not set position to 1: %08x\n", rc); + rc = IDirectSoundBuffer_GetCurrentPosition(secondary, &pos2, NULL); + ok(rc == DS_OK, "Could not get new position: %08x\n", rc); + ok(pos == pos2, "Positions not the same! Old position: %d, new position: %d\n", pos, pos2); + } + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d references, " + "should have 0\n",ref); + } + + 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 struct fmt { + int bits; + int channels; +} fmts[] = { { 8, 1 }, { 8, 2 }, { 16, 1 }, {16, 2 } }; + +static HRESULT test_frequency(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx1; + DWORD f, r; + int ref; + int rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, + 48000, 96000 }; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "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 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() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + 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) { + rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT1; + + for (f=0;f + + + + . + + wine + uuid + dsound + dxguid + ole32 + user32 + capture.c + ds3d8.c + ds3d.c + dsound8.c + dsound.c + duplex.c + propset.c + testlist.c + + diff --git a/rostests/winetests/dsound/dsound8.c b/rostests/winetests/dsound/dsound8.c new file mode 100644 index 00000000000..a2b16d85bbb --- /dev/null +++ b/rostests/winetests/dsound/dsound8.c @@ -0,0 +1,940 @@ +/* + * Tests basic sound playback in DirectSound. + * In particular we test each standard Windows sound format to make sure + * we handle the sound card/driver quirks correctly. + * + * 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 "dsconf.h" +#include "mmreg.h" +#include "ks.h" +#include "ksmedia.h" + +#include "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; + +int align(int length, int align) +{ + return (length / align) * align; +} + +static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized, + LPCGUID lpGuid) +{ + HRESULT rc; + DSCAPS dscaps; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + DWORD speaker_config, new_speaker_config; + DWORD certified; + + /* Try to Query for objects */ + rc=IDirectSound8_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IUnknown) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound8_Release(unknown); + + rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound) failed: %08x\n", rc); + if (rc==DS_OK) + IDirectSound_Release(ds); + + rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound8) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK) + IDirectSound8_Release(ds8); + + if (initialized == FALSE) { + /* try uninitialized object */ + rc=IDirectSound8_GetCaps(dso,0); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps(NULL) " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_Compact(dso); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_Compact() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetSpeakerConfig() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_VerifyCertification(dso, &certified); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_VerifyCertification() " + "should have returned DSERR_UNINITIALIZED, returned: %08x\n", rc); + + rc=IDirectSound8_Initialize(dso,lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "IDirectSound8_Initialize() failed: %08x\n",rc); + if (rc==DSERR_NODRIVER) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSound8_Initialize(dso,lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound8_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %08x\n", rc); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound8_GetCaps(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + ZeroMemory(&dscaps, sizeof(dscaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + dscaps.dwSize=sizeof(dscaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + + rc=IDirectSound8_Compact(dso); + ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound8_Compact() failed: %08x\n", rc); + + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc); + + rc=IDirectSound8_Compact(dso); + ok(rc==DS_OK,"IDirectSound8_Compact() failed: %08x\n",rc); + + rc=IDirectSound8_GetSpeakerConfig(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetSpeakerConfig(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + + rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc); + + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_WIDE); + rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK) { + rc=IDirectSound8_GetSpeakerConfig(dso,&new_speaker_config); + ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %08x\n", rc); + if (rc==DS_OK && speaker_config!=new_speaker_config) + trace("IDirectSound8_GetSpeakerConfig() failed to set speaker " + "config: expected 0x%08x, got 0x%08x\n", + speaker_config,new_speaker_config); + } + + rc=IDirectSound8_VerifyCertification(dso, &certified); + ok(rc==DS_OK||rc==E_NOTIMPL,"IDirectSound8_VerifyCertification() failed: %08x\n", rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); +} + +static void IDirectSound8_tests(void) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPCLASSFACTORY cf=NULL; + + trace("Testing IDirectSound8\n"); + + rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL, + &IID_IClassFactory, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IClassFactory) " + "failed: %08x\n", rc); + + rc=CoGetClassObject(&CLSID_DirectSound8, CLSCTX_INPROC_SERVER, NULL, + &IID_IUnknown, (void**)&cf); + ok(rc==S_OK,"CoGetClassObject(CLSID_DirectSound8, IID_IUnknown) " + "failed: %08x\n", rc); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance() failed: %08x\n", rc); + if (rc==REGDB_E_CLASSNOTREG) { + trace(" Class Not Registered\n"); + return; + } + if (dso) + IDirectSound8_test(dso, FALSE, NULL); + + /* try the COM class factory method of creation with default playback + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", rc); + if (dso) + IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * playback device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %08x\n", rc); + if (dso) + IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dso); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSound8,CLSID_DirectSoundPrivate) " + "should have failed: %08x\n",rc); + + /* try the COM class factory method of creation with a bad + * GUID and IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==REGDB_E_CLASSNOTREG, + "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound8) " + "should have failed: %08x\n",rc); + + /* try with no device specified */ + rc=pDirectSoundCreate8(NULL,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with default playback device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultPlayback,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with default voice playback device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultVoicePlayback,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultVoiceCapture,&dso,NULL); + ok(rc==DSERR_NODRIVER,"DirectSoundCreate8(DSDEVID_DefaultVoiceCapture) " + "should have failed: %08x\n",rc); +} + +static HRESULT test_dsound8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + int ref; + + /* DSOUND: Error: Invalid interface buffer */ + rc=pDirectSoundCreate8(lpGuid,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate8() should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* Create the DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Try the enumerated device */ + IDirectSound8_test(dso, TRUE, lpGuid); + + /* Try the COM class factory method of creation with enumerated device */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %08x\n", rc); + if (dso) + IDirectSound8_test(dso, FALSE, lpGuid); + + /* Create a DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUND8 dso1=NULL; + + /* Create a second DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso1,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK) { + /* Release the second DirectSound8 object */ + ref=IDirectSound8_Release(dso1); + ok(ref==0,"IDirectSound8_Release() has %d references, " + "should have 0\n",ref); + ok(dso!=dso1,"DirectSound8 objects should be unique: " + "dso=%p,dso1=%p\n",dso,dso1); + } + + /* Release the first DirectSound8 object */ + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + /* Create a DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %08x\n",rc); + if (rc==DS_OK) { + LPDIRECTSOUNDBUFFER secondary; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound8_CreateSoundBuffer() failed to create a secondary " + "buffer: %08x\n",rc); + if (rc==DS_OK && secondary!=NULL) { + LPDIRECTSOUND3DBUFFER buffer3d; + LPDIRECTSOUNDBUFFER8 buffer8; + rc=IDirectSound8_QueryInterface(secondary, + &IID_IDirectSound3DBuffer, + (void **)&buffer3d); + ok(rc==DS_OK && buffer3d!=NULL, + "IDirectSound8_QueryInterface() failed: %08x\n", rc); + if (rc==DS_OK && buffer3d!=NULL) { + ref=IDirectSound3DBuffer_AddRef(buffer3d); + ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + rc=IDirectSound8_QueryInterface(secondary, + &IID_IDirectSoundBuffer8, + (void **)&buffer8); + if (rc==DS_OK && buffer8!=NULL) { + ref=IDirectSoundBuffer8_AddRef(buffer8); + ok(ref==3,"IDirectSoundBuffer8_AddRef() has %d references, " + "should have 3\n",ref); + } + ref=IDirectSoundBuffer_AddRef(secondary); + ok(ref==4,"IDirectSoundBuffer_AddRef() has %d references, " + "should have 4\n",ref); + } + /* release with buffer */ + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + return DS_OK; +} + +static HRESULT test_primary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; + LPDIRECTSOUNDBUFFER8 pb8 = NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,0,0,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_CreateSoundBuffer should have returned " + "DSERR_INVALIDPARAM, returned: %08x\n",rc); + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,0,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: rc=%08x,dsbo=%p\n", + rc,primary); + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize = sizeof(DSBUFFERDESC); + + /* DSOUND: Error: Invalid dsound buffer interface pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,0,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x," + "dsbo=%p\n",rc,primary); + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + + /* DSOUND: Error: Invalid size */ + /* DSOUND: Error: Invalid buffer description */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have failed: rc=%08x," + "primary=%p\n",rc,primary); + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() 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; + bufdesc.lpwfxFormat = &wfx; + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n", rc); + if (rc==DS_OK && primary!=NULL) + IDirectSoundBuffer_Release(primary); + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound8_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) { + LONG vol; + + /* Try to create a second primary buffer */ + /* DSOUND: Error: The primary buffer already exists. + * Any changes made to the buffer description will be ignored. */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&second,NULL); + ok(rc==DS_OK && second==primary, + "IDirectSound8_CreateSoundBuffer() should have returned original " + "primary buffer: %08x\n",rc); + ref=IDirectSoundBuffer_Release(second); + ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 1\n",ref); + + /* Try to duplicate a primary buffer */ + /* DSOUND: Error: Can't duplicate primary buffers */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,primary,&third); + /* rc=0x88780032 */ + ok(rc!=DS_OK,"IDirectSound8_DuplicateSoundBuffer() primary buffer " + "should have failed %08x\n",rc); + + /* Primary buffers don't have an IDirectSoundBuffer8 */ + rc = IDirectSoundBuffer_QueryInterface(primary, &IID_IDirectSoundBuffer8, (LPVOID*)&pb8); + ok(FAILED(rc), "Primary buffer does have an IDirectSoundBuffer8: %08x\n", rc); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %08x\n", rc); + + if (winetest_interactive) { + trace("Playing a 5 seconds reference tone at the current volume.\n"); + if (rc==DS_OK) + trace("(the current volume is %d according to DirectSound)\n", + vol); + trace("All subsequent tones should be identical to this one.\n"); + trace("Listen for stutter, changes in pitch, volume, etc.\n"); + } + test_buffer8(dso,&primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,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=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +/* + * Test the primary buffer at different formats while keeping the + * secondary buffer at a constant format. + */ +static HRESULT test_primary_secondary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx2; + int ref; + unsigned int f; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate8() failed: %08x\n",rc); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %08x\n",rc); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %08x\n", rc); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL, + "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer " + "%08x\n",rc); + + if (rc==DS_OK && primary!=NULL) { + for (f=0;f + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.h" +#include "dsconf.h" + +#include "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID, LPCGUID, + LPCDSCBUFFERDESC, LPCDSBUFFERDESC, HWND, DWORD, LPDIRECTSOUNDFULLDUPLEX *, + LPDIRECTSOUNDCAPTUREBUFFER8*, LPDIRECTSOUNDBUFFER8*, LPUNKNOWN)=NULL; + +static void IDirectSoundFullDuplex_test(LPDIRECTSOUNDFULLDUPLEX dsfdo, + BOOL initialized, LPCGUID lpGuidCapture, + LPCGUID lpGuidRender) +{ + HRESULT rc; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + IDirectSoundCapture * dsc; + IDirectSoundFullDuplex * dsfd; + + /* Try to Query for objects */ + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IUnknown) failed: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSoundFullDuplex_Release(unknown); + ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound) failed: %08x\n", rc); + if (rc==DS_OK) { + ref=IDirectSound_Release(ds); + ok(ref==0, "IDirectSound_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSound8) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + IDirectSoundFullDuplex * dsfd1; + rc=IDirectSound8_QueryInterface(ds8,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd1); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSoundFullDuplex) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + ref=IDirectSoundFullDuplex_Release(dsfd1); + ok(ref==1, "IDirectSoundFullDuplex_Release() has %d references, " + "should have 1\n", ref); + } + ref=IDirectSound8_Release(ds8); + ok(ref==0, "IDirectSound8_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundCapture,(LPVOID*)&dsc); + ok(rc==(initialized?DS_OK:E_NOINTERFACE),"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundCapture) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + ref=IDirectSoundCapture_Release(dsc); + ok(ref==0, "IDirectSoundCapture_Release() has %d references, " + "should have 0\n", ref); + } + + rc=IDirectSoundFullDuplex_QueryInterface(dsfdo,&IID_IDirectSoundFullDuplex,(LPVOID*)&dsfd); + ok(rc==DS_OK,"IDirectSoundFullDuplex_QueryInterface(IID_IDirectSoundFullDuplex) " + "failed: %08x\n",rc); + if (rc==DS_OK) { + ok (dsfdo==dsfd, "different interfaces\n"); + ref=IDirectSound8_Release(dsfd); + } + + ref=IDirectSoundFullDuplex_Release(dsfdo); + ok(ref==0, "IDirectSoundFullDuplex_Release() has %d references, " + "should have 0\n", ref); +} + +static void IDirectSoundFullDuplex_tests(void) +{ + HRESULT rc; + LPDIRECTSOUNDFULLDUPLEX dsfdo = NULL; + DSCBUFFERDESC DSCBufferDesc; + DSBUFFERDESC DSBufferDesc; + LPDIRECTSOUNDCAPTUREBUFFER8 pDSCBuffer8; + LPDIRECTSOUNDBUFFER8 pDSBuffer8; + WAVEFORMATEX wfex; + + trace("Testing IDirectSoundFullDuplex\n"); + + /* try the COM class factory method of creation with no devices specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex, + (void**)&dsfdo); + ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG||rc==CLASS_E_CLASSNOTAVAILABLE, + "CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc); + if (rc==REGDB_E_CLASSNOTREG) { + trace(" Class Not Registered\n"); + return; + } else if (rc==CLASS_E_CLASSNOTAVAILABLE) { + trace(" Class Not Available\n"); + return; + } + if (dsfdo) + IDirectSoundFullDuplex_test(dsfdo, FALSE, NULL, NULL); + + /* try the COM class factory method of creation with default devices + * specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex, + (void**)&dsfdo); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc); + if (dsfdo) + IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultCapture, + &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * devices specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &IID_IDirectSoundFullDuplex, + (void**)&dsfdo); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundFullDuplex) failed: 0x%08x\n", rc); + if (dsfdo) + IDirectSoundFullDuplex_test(dsfdo, FALSE, &DSDEVID_DefaultVoiceCapture, + &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundFullDuplex, NULL, + CLSCTX_INPROC_SERVER, &CLSID_DirectSoundPrivate, + (void**)&dsfdo); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSoundFullDuplex,CLSID_DirectSoundPrivate) " + "should have failed: 0x%08x\n", rc); + + ZeroMemory(&wfex, sizeof(wfex)); + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = 1; + wfex.nSamplesPerSec = 8000; + wfex.wBitsPerSample = 16; + wfex.nBlockAlign = (wfex.wBitsPerSample * wfex.nChannels) / 8; + wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign; + + ZeroMemory(&DSCBufferDesc, sizeof(DSCBufferDesc)); + DSCBufferDesc.dwSize = sizeof(DSCBufferDesc); + DSCBufferDesc.dwFlags = DSCBCAPS_WAVEMAPPED; + DSCBufferDesc.dwBufferBytes = 8192; + DSCBufferDesc.lpwfxFormat = &wfex; + + ZeroMemory(&DSBufferDesc, sizeof(DSBufferDesc)); + DSBufferDesc.dwSize = sizeof(DSBufferDesc); + DSBufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS; + DSBufferDesc.dwBufferBytes = 8192; + DSBufferDesc.lpwfxFormat = &wfex; + + /* try with no device specified */ + rc=pDirectSoundFullDuplexCreate(NULL,NULL,&DSCBufferDesc,&DSBufferDesc, + get_hwnd(),DSSCL_EXCLUSIVE ,&dsfdo,&pDSCBuffer8, + &pDSBuffer8,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(NULL,NULL) failed: %08x\n",rc); + if (rc==S_OK && dsfdo) + IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL); + + /* try with default devices specified */ + rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultCapture, + &DSDEVID_DefaultPlayback,&DSCBufferDesc, + &DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE,&dsfdo, + &pDSCBuffer8,&pDSBuffer8,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(DSDEVID_DefaultCapture," + "DSDEVID_DefaultPlayback) failed: %08x\n", rc); + if (rc==DS_OK && dsfdo) + IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL); + + /* try with default voice devices specified */ + rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoiceCapture, + &DSDEVID_DefaultVoicePlayback, + &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE, + &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoiceCapture," + "DSDEVID_DefaultVoicePlayback) failed: %08x\n", rc); + if (rc==DS_OK && dsfdo) + IDirectSoundFullDuplex_test(dsfdo, TRUE, NULL, NULL); + + /* try with bad devices specified */ + rc=pDirectSoundFullDuplexCreate(&DSDEVID_DefaultVoicePlayback, + &DSDEVID_DefaultVoiceCapture, + &DSCBufferDesc,&DSBufferDesc,get_hwnd(),DSSCL_EXCLUSIVE, + &dsfdo,&pDSCBuffer8,&pDSBuffer8,NULL); + ok(rc==DSERR_NODRIVER||rc==DSERR_INVALIDCALL, + "DirectSoundFullDuplexCreate(DSDEVID_DefaultVoicePlayback," + "DSDEVID_DefaultVoiceCapture) should have failed: %08x\n", rc); + if (rc==DS_OK && dsfdo) + IDirectSoundFullDuplex_Release(dsfdo); +} + +START_TEST(duplex) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound, + "DirectSoundFullDuplexCreate"); + if (pDirectSoundFullDuplexCreate) + IDirectSoundFullDuplex_tests(); + else + skip("duplex test skipped\n"); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/propset.c b/rostests/winetests/dsound/propset.c new file mode 100644 index 00000000000..70a8e0d9f24 --- /dev/null +++ b/rostests/winetests/dsound/propset.c @@ -0,0 +1,748 @@ +/* + * Unit tests for CLSID_DirectSoundPrivate property set functions + * (used by dxdiag) + * + * Copyright (c) 2003 Robert Reif + * + * 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 + */ + +#define COBJMACROS +#include + +#include "wine/test.h" +#include "dsound.h" +#include "dsconf.h" + +#include "dsound_test.h" + +#ifndef DSBCAPS_CTRLDEFAULT +#define DSBCAPS_CTRLDEFAULT \ + DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME +#endif + +#include "initguid.h" + +DEFINE_GUID(DSPROPSETID_VoiceManager, + 0x62A69BAE,0xDF9D,0x11D1,0x99,0xA6,0x00,0xC0,0x4F,0xC9,0x9D,0x46); +DEFINE_GUID(DSPROPSETID_EAX20_ListenerProperties, + 0x306a6a8,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); +DEFINE_GUID(DSPROPSETID_EAX20_BufferProperties, + 0x306a6a7,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); +DEFINE_GUID(DSPROPSETID_I3DL2_ListenerProperties, + 0xDA0F0520,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); +DEFINE_GUID(DSPROPSETID_I3DL2_BufferProperties, + 0xDA0F0521,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); +DEFINE_GUID(DSPROPSETID_ZOOMFX_BufferProperties, + 0xCD5368E0,0x3450,0x11D3,0x8B,0x6E,0x00,0x10,0x5A,0x9B,0x7B,0xBC); + +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; +static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID*)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID,LPDIRECTSOUND*, + LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*, + LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID, + LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureCreate8)(LPCGUID, + LPDIRECTSOUNDCAPTURE8*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID,LPCGUID, + LPCDSCBUFFERDESC,LPCDSBUFFERDESC,HWND,DWORD,LPDIRECTSOUNDFULLDUPLEX*, + LPDIRECTSOUNDCAPTUREBUFFER8*,LPDIRECTSOUNDBUFFER8*,LPUNKNOWN)=NULL; + +static BOOL CALLBACK callback(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA data, + LPVOID context) +{ + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" Description: %s\n", data->Description); + trace(" Module: %s\n", data->Module); + trace(" Interface: %s\n", data->Interface); + trace(" WaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static BOOL CALLBACK callback1(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA data, + LPVOID context) +{ + char descriptionA[0x100]; + char moduleA[MAX_PATH]; + + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" DescriptionA: %s\n", data->DescriptionA); + WideCharToMultiByte(CP_ACP, 0, data->DescriptionW, -1, descriptionA, sizeof(descriptionA), NULL, NULL); + trace(" DescriptionW: %s\n", descriptionA); + trace(" ModuleA: %s\n", data->ModuleA); + WideCharToMultiByte(CP_ACP, 0, data->ModuleW, -1, moduleA, sizeof(moduleA), NULL, NULL); + trace(" ModuleW: %s\n", moduleA); + trace(" WaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static BOOL CALLBACK callbackA(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA data, + LPVOID context) +{ + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" Description: %s\n", data->Description); + trace(" Module: %s\n", data->Module); + trace(" Interface: %s\n", data->Interface); + trace(" WaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static BOOL CALLBACK callbackW(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data, + LPVOID context) +{ + char descriptionA[0x100]; + char moduleA[MAX_PATH]; + char interfaceA[MAX_PATH]; + + trace("found device:\n"); + trace("\tType: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace("\tDataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace("\tDeviceId: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + WideCharToMultiByte(CP_ACP, 0, data->Description, -1, descriptionA, sizeof(descriptionA), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, data->Module, -1, moduleA, sizeof(moduleA), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, data->Interface, -1, interfaceA, sizeof(interfaceA), NULL, NULL); + trace("\tDescription: %s\n", descriptionA); + trace("\tModule: %s\n", moduleA); + trace("\tInterface: %s\n", interfaceA); + trace("\tWaveDeviceId: %d\n", data->WaveDeviceId); + + return TRUE; +} + +static void propset_private_tests(void) +{ + HRESULT rc; + IClassFactory * pcf; + IKsPropertySet * pps; + ULONG support; + + /* try direct sound first */ + /* DSOUND: Error: Invalid interface buffer */ + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IClassFactory, NULL); + ok(rc==DSERR_INVALIDPARAM,"DllGetClassObject(CLSID_DirectSound, " + "IID_IClassFactory) should have returned DSERR_INVALIDPARAM, " + "returned: %08x\n",rc); + + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IDirectSound, (void **)(&pcf)); + ok(rc==E_NOINTERFACE,"DllGetClassObject(CLSID_DirectSound, " + "IID_IDirectSound) should have returned E_NOINTERFACE, " + "returned: %08x\n",rc); + + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IUnknown, (void **)(&pcf)); + ok(rc==DS_OK,"DllGetClassObject(CLSID_DirectSound, " + "IID_IUnknown) failed: %08x\n",rc); + + rc = (pDllGetClassObject)(&CLSID_DirectSound, &IID_IClassFactory, (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound, IID_IClassFactory) " + "failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound doesn't have an IKsPropertySet */ + /* DSOUND: Error: Invalid interface buffer */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + NULL); + ok(rc==DSERR_INVALIDPARAM, "CreateInstance(IID_IKsPropertySet) should have " + "returned DSERR_INVALIDPARAM, returned: %08x\n",rc); + + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %08x\n",rc); + + /* and the direct sound 8 version */ + if (pDirectSoundCreate8) { + rc = (pDllGetClassObject)(&CLSID_DirectSound8, &IID_IClassFactory, (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound8, IID_IClassFactory) " + "failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound 8 doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %08x\n",rc); + } + + /* try direct sound capture next */ + if (pDirectSoundCaptureCreate) { + rc = (pDllGetClassObject)(&CLSID_DirectSoundCapture, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) " + "failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound capture doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE,returned: %08x\n",rc); + } + + /* and the direct sound capture 8 version */ + if (pDirectSoundCaptureCreate8) { + rc = (pDllGetClassObject)(&CLSID_DirectSoundCapture8, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture8, " + "IID_IClassFactory) failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound capture 8 doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %08x\n",rc); + } + + /* try direct sound full duplex next */ + if (pDirectSoundFullDuplexCreate) { + rc = (pDllGetClassObject)(&CLSID_DirectSoundFullDuplex, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundFullDuplex, " + "IID_IClassFactory) failed: %08x\n",rc); + if (pcf==0) + return; + + /* direct sound full duplex doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned NOINTERFACE, returned: %08x\n",rc); + } + + /* try direct sound private last */ + rc = (pDllGetClassObject)(&CLSID_DirectSoundPrivate, &IID_IClassFactory, + (void **)(&pcf)); + + /* some early versions of Direct Sound do not have this */ + if (rc==CLASS_E_CLASSNOTAVAILABLE) + return; + + /* direct sound private does have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==DS_OK, "CreateInstance(IID_IKsPropertySet) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " + "support = 0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1 */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: " + "support = 0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: " + "support = 0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W) failed: %08x\n", + rc); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + return; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: " + "support = 0x%x\n",support); + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: support = " + "0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: support = " + "0x%x\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: support = " + "0x%x\n",support); + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_DATA data; + ULONG bytes; + + data.Callback = callback; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1_DATA data; + ULONG bytes; + + data.Callback = callback1; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA data; + ULONG bytes; + + data.Callback = callbackA; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W) failed: %08x\n", + rc); + if (rc!=DS_OK) + return; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: " + "support = 0x%x\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: support = 0x%x\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA data; + ULONG bytes; + + data.Callback = callbackW; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%x\n",rc); + } +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + int ref; + + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + 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) { + if (rc==DSERR_NODRIVER) + trace(" No Driver\n"); + else if (rc == DSERR_ALLOCATED) + trace(" Already In Use\n"); + else if (rc == E_FAIL) + trace(" No Device\n"); + 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() failed: %08x\n", + rc); + if (rc!=DS_OK) + goto EXIT; + + /* Testing 3D buffers */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_LOCHARDWARE|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK&&primary!=NULL) + || broken(rc==DSERR_INVALIDPARAM), + "IDirectSound_CreateSoundBuffer() failed to " + "create a hardware 3D primary buffer: %08x\n",rc); + if(rc==DSERR_INVALIDPARAM) { + skip("broken driver\n"); + goto EXIT; + } + if (rc==DS_OK&&primary!=NULL) { + ZeroMemory(&wfx, sizeof(wfx)); + wfx.wFormatTag=WAVE_FORMAT_PCM; + wfx.nChannels=1; + wfx.wBitsPerSample=16; + wfx.nSamplesPerSec=44100; + wfx.nBlockAlign=wfx.nChannels*wfx.wBitsPerSample/8; + wfx.nAvgBytesPerSec=wfx.nSamplesPerSec*wfx.nBlockAlign; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2; + bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec; + bufdesc.lpwfxFormat=&wfx; + trace(" Testing a secondary buffer at %dx%dx%d\n", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK&&secondary!=NULL,"IDirectSound_CreateSoundBuffer() " + "failed to create a secondary buffer: %08x\n",rc); + if (rc==DS_OK&&secondary!=NULL) { + IKsPropertySet * pPropertySet=NULL; + rc=IDirectSoundBuffer_QueryInterface(secondary, + &IID_IKsPropertySet, + (void **)&pPropertySet); + /* it's not an error for this to fail */ + if(rc==DS_OK) { + ULONG ulTypeSupport; + trace(" Supports property sets\n"); + /* it's not an error for these to fail */ + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_VoiceManager, + 0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_VoiceManager supported\n"); + else + trace(" DSPROPSETID_VoiceManager not supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_EAX20_ListenerProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_EAX20_ListenerProperties " + "supported\n"); + else + trace(" DSPROPSETID_EAX20_ListenerProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_EAX20_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_EAX20_BufferProperties supported\n"); + else + trace(" DSPROPSETID_EAX20_BufferProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_I3DL2_ListenerProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_I3DL2_ListenerProperties " + "supported\n"); + else + trace(" DSPROPSETID_I3DL2_ListenerProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_I3DL2_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_I3DL2_BufferProperties supported\n"); + else + trace(" DSPROPSETID_I3DL2_BufferProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_ZOOMFX_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_ZOOMFX_BufferProperties " + "supported\n"); + else + trace(" DSPROPSETID_ZOOMFX_BufferProperties not " + "supported\n"); + ref=IKsPropertySet_Release(pPropertySet); + /* try a few common ones */ + ok(ref==0,"IKsPropertySet_Release() secondary has %d " + "references, should have 0\n",ref); + } else + trace(" Doesn't support property sets\n"); + + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " + "references, should have 0\n",ref); + } + + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + if (dso!=NULL) { + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + } + return 1; +} + +static void propset_buffer_tests(void) +{ + HRESULT rc; + rc=pDirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %08x\n",rc); +} + +START_TEST(propset) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibrary("dsound.dll"); + if (hDsound) + { + + pDirectSoundEnumerateA = (void*)GetProcAddress(hDsound, + "DirectSoundEnumerateA"); + pDllGetClassObject = (void *)GetProcAddress(hDsound, + "DllGetClassObject"); + pDirectSoundCreate = (void*)GetProcAddress(hDsound, + "DirectSoundCreate"); + pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, + "DirectSoundCreate8"); + pDirectSoundCaptureCreate=(void*)GetProcAddress(hDsound, + "DirectSoundCaptureCreate"); + pDirectSoundCaptureCreate8=(void*)GetProcAddress(hDsound, + "DirectSoundCaptureCreate8"); + pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound, + "DirectSoundFullDuplexCreate"); + + propset_private_tests(); + propset_buffer_tests(); + + FreeLibrary(hDsound); + } + else + skip("dsound.dll not found!\n"); + + CoUninitialize(); +} diff --git a/rostests/winetests/dsound/testlist.c b/rostests/winetests/dsound/testlist.c new file mode 100644 index 00000000000..2afeb2ffd66 --- /dev/null +++ b/rostests/winetests/dsound/testlist.c @@ -0,0 +1,27 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_capture(void); +extern void func_ds3d8(void); +extern void func_ds3d(void); +extern void func_dsound8(void); +extern void func_dsound(void); +extern void func_duplex(void); +extern void func_propset(void); + +const struct test winetest_testlist[] = +{ + { "capture", func_capture }, + { "ds3d8", func_ds3d8 }, + { "ds3d", func_ds3d }, + { "dsound8", func_dsound8 }, + { "dsound", func_dsound }, + { "duplex", func_duplex }, + { "propset", func_propset }, + { 0, 0 } +};