Separated DirectSoundCreate8 into two functions and added a

IDirectSound implementation.
Added proper COM behavior for QueryInterface for IDirectSound and
IDirectSound8.
Fixed a bug in the dsound.h header file for IDirectSound8
CreateSoundBuffer and DuplicateSoundBuffer.
Added new tests for proper COM behavior and enables some commented out
code for tests that work on windows.  Added new tests for
IDirectSound8.
This commit is contained in:
Robert Reif 2004-07-04 00:13:44 +00:00 committed by Alexandre Julliard
parent 87bacf46ae
commit 31f817b6f9
7 changed files with 1875 additions and 792 deletions

View File

@ -9,6 +9,7 @@ EXTRALIBS = -ldxguid -luuid
C_SRCS = \
buffer.c \
capture.c \
dsound.c \
dsound_main.c \
mixer.c \
primary.c \

1672
dlls/dsound/dsound.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
1 stdcall DirectSoundCreate(ptr ptr ptr) DirectSoundCreate8
1 stdcall DirectSoundCreate(ptr ptr ptr)
2 stdcall DirectSoundEnumerateA(ptr ptr)
3 stdcall DirectSoundEnumerateW(ptr ptr)
4 stdcall -private DllCanUnloadNow() DSOUND_DllCanUnloadNow

View File

@ -438,773 +438,6 @@ HRESULT WINAPI DirectSoundEnumerateW(
return DS_OK;
}
static void _dump_DSBCAPS(DWORD xmask) {
struct {
DWORD mask;
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_CTRLDEFAULT)
FE(DSBCAPS_CTRLALL)
FE(DSBCAPS_STICKYFOCUS)
FE(DSBCAPS_GLOBALFOCUS)
FE(DSBCAPS_GETCURRENTPOSITION2)
FE(DSBCAPS_MUTE3DATMAXDISTANCE)
#undef FE
};
int i;
for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
if ((flags[i].mask & xmask) == flags[i].mask)
DPRINTF("%s ",flags[i].name);
}
/*******************************************************************************
* IDirectSound
*/
static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
LPDIRECTSOUND8 iface,HWND hwnd,DWORD level
) {
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p,%08lx,%ld(%s))\n",This,(DWORD)hwnd,level,
level == DSSCL_NORMAL ? "DSSCL_NORMAL" :
level == DSSCL_PRIORITY ? "DSSCL_PRIORITY" :
level == DSSCL_EXCLUSIVE ? "DSSCL_EXCLUSIVE" :
level == DSSCL_WRITEPRIMARY ? "DSSCL_WRITEPRIMARY" : "Unknown");
if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
FIXME("level=%s not fully supported\n",
level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
}
This->priolevel = level;
return DS_OK;
}
static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
LPDIRECTSOUND8 iface,LPCDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER8 ppdsb,LPUNKNOWN lpunk
) {
ICOM_THIS(IDirectSoundImpl,iface);
LPWAVEFORMATEX wfex;
HRESULT hres = DS_OK;
TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
if (This == NULL) {
WARN("invalid parameter: This == NULL\n");
return DSERR_INVALIDPARAM;
}
if (dsbd == NULL) {
WARN("invalid parameter: dsbd == NULL\n");
return DSERR_INVALIDPARAM;
}
if (dsbd->dwSize != sizeof(DSBUFFERDESC) && dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
WARN("invalid parameter: dsbd\n");
return DSERR_INVALIDPARAM;
}
if (ppdsb == NULL) {
WARN("invalid parameter: ppdsb == NULL\n");
return DSERR_INVALIDPARAM;
}
if (TRACE_ON(dsound)) {
TRACE("(structsize=%ld)\n",dsbd->dwSize);
TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
_dump_DSBCAPS(dsbd->dwFlags);
DPRINTF(")\n");
TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
}
wfex = dsbd->lpwfxFormat;
if (wfex)
TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
"bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
wfex->nAvgBytesPerSec, wfex->nBlockAlign,
wfex->wBitsPerSample, wfex->cbSize);
if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
if (This->primary) {
WARN("Primary Buffer already created\n");
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary));
*ppdsb = (LPDIRECTSOUNDBUFFER8)(This->primary);
} else {
This->dsbd = *dsbd;
hres = PrimaryBufferImpl_Create(This, (PrimaryBufferImpl**)&(This->primary), &(This->dsbd));
if (This->primary) {
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary));
*ppdsb = (LPDIRECTSOUNDBUFFER8)(This->primary);
} else
WARN("PrimaryBufferImpl_Create failed\n");
}
} else {
IDirectSoundBufferImpl * dsb;
hres = IDirectSoundBufferImpl_Create(This, (IDirectSoundBufferImpl**)&dsb, dsbd);
if (dsb) {
hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
if (*ppdsb) {
dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
} else
WARN("SecondaryBufferImpl_Create failed\n");
} else
WARN("IDirectSoundBufferImpl_Create failed\n");
}
return hres;
}
static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
LPDIRECTSOUND8 iface,LPDIRECTSOUNDBUFFER8 psb,LPLPDIRECTSOUNDBUFFER8 ppdsb
) {
ICOM_THIS(IDirectSoundImpl,iface);
IDirectSoundBufferImpl* pdsb;
IDirectSoundBufferImpl* dsb;
HRESULT hres = DS_OK;
TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
if (This == NULL) {
WARN("invalid parameter: This == NULL\n");
return DSERR_INVALIDPARAM;
}
if (psb == NULL) {
WARN("invalid parameter: psb == NULL\n");
return DSERR_INVALIDPARAM;
}
if (ppdsb == NULL) {
WARN("invalid parameter: ppdsb == NULL\n");
return DSERR_INVALIDPARAM;
}
/* FIXME: hack to make sure we have a secondary buffer */
if ((DWORD)((SecondaryBufferImpl *)psb)->dsb == (DWORD)This) {
ERR("trying to duplicate primary buffer\n");
*ppdsb = NULL;
return DSERR_INVALIDCALL;
}
pdsb = ((SecondaryBufferImpl *)psb)->dsb;
dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
if (dsb == NULL) {
WARN("out of memory\n");
*ppdsb = NULL;
return DSERR_OUTOFMEMORY;
}
memcpy(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
if (pdsb->hwbuf) {
TRACE("duplicating hardware buffer\n");
hres = IDsDriver_DuplicateSoundBuffer(This->driver, pdsb->hwbuf, (LPVOID *)&dsb->hwbuf);
if (hres != DS_OK) {
TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to software buffer\n");
dsb->hwbuf = NULL;
/* allocate buffer */
if (This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
if (dsb->buffer == NULL) {
WARN("out of memory\n");
HeapFree(GetProcessHeap(),0,dsb);
*ppdsb = NULL;
return DSERR_OUTOFMEMORY;
}
dsb->buffer->memory = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
if (dsb->buffer->memory == NULL) {
WARN("out of memory\n");
HeapFree(GetProcessHeap(),0,dsb->buffer);
HeapFree(GetProcessHeap(),0,dsb);
*ppdsb = NULL;
return DSERR_OUTOFMEMORY;
}
dsb->buffer->ref = 1;
/* FIXME: copy buffer ? */
}
}
} else {
dsb->hwbuf = NULL;
dsb->buffer->ref++;
}
dsb->ref = 0;
dsb->state = STATE_STOPPED;
dsb->playpos = 0;
dsb->buf_mixpos = 0;
dsb->dsound = This;
dsb->ds3db = NULL;
dsb->iks = NULL; /* FIXME? */
dsb->dsb = NULL;
memcpy(&(dsb->wfx), &(pdsb->wfx), sizeof(dsb->wfx));
InitializeCriticalSection(&(dsb->lock));
/* register buffer */
RtlAcquireResourceExclusive(&(This->lock), TRUE);
{
IDirectSoundBufferImpl **newbuffers;
if (This->buffers)
newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
else
newbuffers = (IDirectSoundBufferImpl**)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1));
if (newbuffers) {
This->buffers = newbuffers;
This->buffers[This->nrofbuffers] = dsb;
This->nrofbuffers++;
TRACE("buffer count is now %d\n", This->nrofbuffers);
} else {
ERR("out of memory for buffer list! Current buffer count is %d\n", This->nrofbuffers);
IDirectSoundBuffer8_Release(psb);
DeleteCriticalSection(&(dsb->lock));
RtlReleaseResource(&(This->lock));
HeapFree(GetProcessHeap(),0,dsb);
*ppdsb = 0;
return DSERR_OUTOFMEMORY;
}
}
RtlReleaseResource(&(This->lock));
IDirectSound_AddRef(iface);
hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
if (*ppdsb) {
dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
} else
WARN("SecondaryBufferImpl_Create failed\n");
return hres;
}
static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND8 iface,LPDSCAPS lpDSCaps) {
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p,%p)\n",This,lpDSCaps);
if (This == NULL) {
WARN("invalid parameter: This == NULL\n");
return DSERR_INVALIDPARAM;
}
if (lpDSCaps == NULL) {
WARN("invalid parameter: lpDSCaps = NULL\n");
return DSERR_INVALIDPARAM;
}
/* check is there is enough room */
if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
lpDSCaps->dwSize, sizeof(*lpDSCaps));
return DSERR_INVALIDPARAM;
}
lpDSCaps->dwFlags = This->drvcaps.dwFlags;
TRACE("(flags=0x%08lx)\n",lpDSCaps->dwFlags);
lpDSCaps->dwMinSecondarySampleRate = This->drvcaps.dwMinSecondarySampleRate;
lpDSCaps->dwMaxSecondarySampleRate = This->drvcaps.dwMaxSecondarySampleRate;
lpDSCaps->dwPrimaryBuffers = This->drvcaps.dwPrimaryBuffers;
lpDSCaps->dwMaxHwMixingAllBuffers = This->drvcaps.dwMaxHwMixingAllBuffers;
lpDSCaps->dwMaxHwMixingStaticBuffers = This->drvcaps.dwMaxHwMixingStaticBuffers;
lpDSCaps->dwMaxHwMixingStreamingBuffers = This->drvcaps.dwMaxHwMixingStreamingBuffers;
lpDSCaps->dwFreeHwMixingAllBuffers = This->drvcaps.dwFreeHwMixingAllBuffers;
lpDSCaps->dwFreeHwMixingStaticBuffers = This->drvcaps.dwFreeHwMixingStaticBuffers;
lpDSCaps->dwFreeHwMixingStreamingBuffers = This->drvcaps.dwFreeHwMixingStreamingBuffers;
lpDSCaps->dwMaxHw3DAllBuffers = This->drvcaps.dwMaxHw3DAllBuffers;
lpDSCaps->dwMaxHw3DStaticBuffers = This->drvcaps.dwMaxHw3DStaticBuffers;
lpDSCaps->dwMaxHw3DStreamingBuffers = This->drvcaps.dwMaxHw3DStreamingBuffers;
lpDSCaps->dwFreeHw3DAllBuffers = This->drvcaps.dwFreeHw3DAllBuffers;
lpDSCaps->dwFreeHw3DStaticBuffers = This->drvcaps.dwFreeHw3DStaticBuffers;
lpDSCaps->dwFreeHw3DStreamingBuffers = This->drvcaps.dwFreeHw3DStreamingBuffers;
lpDSCaps->dwTotalHwMemBytes = This->drvcaps.dwTotalHwMemBytes;
lpDSCaps->dwFreeHwMemBytes = This->drvcaps.dwFreeHwMemBytes;
lpDSCaps->dwMaxContigFreeHwMemBytes = This->drvcaps.dwMaxContigFreeHwMemBytes;
/* driver doesn't have these */
lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */
lpDSCaps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */
return DS_OK;
}
static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND8 iface) {
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
return InterlockedIncrement(&This->ref);
}
static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND8 iface) {
ICOM_THIS(IDirectSoundImpl,iface);
ULONG ulReturn;
TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId());
ulReturn = InterlockedDecrement(&This->ref);
if (ulReturn == 0) {
HRESULT hres;
UINT i;
timeKillEvent(This->timerID);
timeEndPeriod(DS_TIME_RES);
/* wait for timer to expire */
Sleep(DS_TIME_RES+1);
RtlAcquireResourceShared(&(This->lock), TRUE);
if (This->buffers) {
for( i=0;i<This->nrofbuffers;i++)
IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->buffers[i]);
}
RtlReleaseResource(&(This->lock));
if (This->primary) {
WARN("primary buffer not released\n");
IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->primary);
}
hres = DSOUND_PrimaryDestroy(This);
if (hres != DS_OK)
WARN("DSOUND_PrimaryDestroy failed\n");
if (This->driver)
IDsDriver_Close(This->driver);
if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
waveOutClose(This->hwo);
if (This->driver)
IDsDriver_Release(This->driver);
RtlDeleteResource(&This->lock);
DeleteCriticalSection(&This->mixlock);
HeapFree(GetProcessHeap(),0,This);
dsound = NULL;
TRACE("(%p) released\n",This);
}
return ulReturn;
}
static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
LPDIRECTSOUND8 iface,DWORD config
) {
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p,0x%08lx)\n",This,config);
This->speaker_config = config;
WARN("not fully functional\n");
return DS_OK;
}
static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
LPDIRECTSOUND8 iface,REFIID riid,LPVOID *ppobj
) {
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
if (ppobj == NULL) {
WARN("invalid parameter\n");
return E_INVALIDARG;
}
*ppobj = NULL; /* assume failure */
if ( IsEqualGUID(riid, &IID_IUnknown) ||
IsEqualGUID(riid, &IID_IDirectSound) ||
IsEqualGUID(riid, &IID_IDirectSound8) ) {
IDirectSound8_AddRef((LPDIRECTSOUND8)This);
*ppobj = This;
return S_OK;
}
if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
WARN("app requested IDirectSound3DListener on dsound object\n");
return E_NOINTERFACE;
}
FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
return E_NOINTERFACE;
}
static HRESULT WINAPI IDirectSoundImpl_Compact(
LPDIRECTSOUND8 iface)
{
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p)\n", This);
return DS_OK;
}
static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
LPDIRECTSOUND8 iface,
LPDWORD lpdwSpeakerConfig)
{
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
if (lpdwSpeakerConfig == NULL) {
WARN("invalid parameter\n");
return DSERR_INVALIDPARAM;
}
WARN("not fully functional\n");
*lpdwSpeakerConfig = This->speaker_config;
return DS_OK;
}
static HRESULT WINAPI IDirectSoundImpl_Initialize(
LPDIRECTSOUND8 iface,
LPCGUID lpcGuid)
{
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
return DS_OK;
}
static HRESULT WINAPI IDirectSoundImpl_VerifyCertification(
LPDIRECTSOUND8 iface,
LPDWORD pdwCertified)
{
ICOM_THIS(IDirectSoundImpl,iface);
TRACE("(%p, %p)\n", This, pdwCertified);
*pdwCertified = DS_CERTIFIED;
return DS_OK;
}
static ICOM_VTABLE(IDirectSound8) dsvt =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
IDirectSoundImpl_QueryInterface,
IDirectSoundImpl_AddRef,
IDirectSoundImpl_Release,
IDirectSoundImpl_CreateSoundBuffer,
IDirectSoundImpl_GetCaps,
IDirectSoundImpl_DuplicateSoundBuffer,
IDirectSoundImpl_SetCooperativeLevel,
IDirectSoundImpl_Compact,
IDirectSoundImpl_GetSpeakerConfig,
IDirectSoundImpl_SetSpeakerConfig,
IDirectSoundImpl_Initialize,
IDirectSoundImpl_VerifyCertification
};
/*******************************************************************************
* DirectSoundCreate (DSOUND.1)
*
* Creates and initializes a DirectSound interface.
*
* PARAMS
* lpcGUID [I] Address of the GUID that identifies the sound device.
* ppDS [O] Address of a variable to receive the interface pointer.
* pUnkOuter [I] Must be NULL.
*
* RETURNS
* Success: DS_OK
* Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
* DSERR_NODRIVER, DSERR_OUTOFMEMORY
*/
HRESULT WINAPI DirectSoundCreate8(LPCGUID lpcGUID,LPDIRECTSOUND8 *ppDS,IUnknown *pUnkOuter )
{
IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS;
PIDSDRIVER drv = NULL;
unsigned wod, wodn;
HRESULT err = DSERR_INVALIDPARAM;
GUID devGuid;
BOOLEAN found = FALSE;
TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ippDS,pUnkOuter);
if (ippDS == NULL) {
WARN("invalid parameter: ippDS == NULL\n");
return DSERR_INVALIDPARAM;
}
/* Get dsound configuration */
setup_dsound_options();
/* Default device? */
if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
lpcGUID = &DSDEVID_DefaultPlayback;
if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) {
WARN("invalid parameter: lpcGUID\n");
*ippDS = NULL;
return DSERR_INVALIDPARAM;
}
if (dsound) {
if (IsEqualGUID(&devGuid, &dsound->guid) ) {
/* FIXME: this is wrong, need to create a new instance */
ERR("dsound already opened\n");
IDirectSound_AddRef((LPDIRECTSOUND)dsound);
*ippDS = dsound;
return DS_OK;
} else {
ERR("different dsound already opened\n");
}
}
/* Enumerate WINMM audio devices and find the one we want */
wodn = waveOutGetNumDevs();
if (!wodn) {
WARN("no driver\n");
*ippDS = NULL;
return DSERR_NODRIVER;
}
TRACE(" expecting GUID %s.\n", debugstr_guid(&devGuid));
for (wod=0; wod<wodn; wod++) {
GUID guid;
err = mmErr(waveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDGUID,(DWORD)(&guid),0));
if (err != DS_OK) {
WARN("waveOutMessage failed; err=%lx\n",err);
*ippDS = NULL;
return err;
}
TRACE("got GUID %s for wod %d.\n", debugstr_guid(&guid), wod);
if (IsEqualGUID( &devGuid, &guid) ) {
err = DS_OK;
found = TRUE;
break;
}
}
if (err != DS_OK) {
WARN("invalid parameter\n");
*ippDS = NULL;
return DSERR_INVALIDPARAM;
}
if (found == FALSE) {
WARN("No device found matching given ID - trying with default one !\n");
wod = ds_default_playback;
}
/* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
waveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0);
/* Disable the direct sound driver to force emulation if requested. */
if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
drv = NULL;
/* Allocate memory */
*ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
if (*ippDS == NULL) {
WARN("out of memory\n");
return DSERR_OUTOFMEMORY;
}
(*ippDS)->lpVtbl = &dsvt;
(*ippDS)->ref = 1;
(*ippDS)->driver = drv;
(*ippDS)->priolevel = DSSCL_NORMAL;
(*ippDS)->fraglen = 0;
(*ippDS)->hwbuf = NULL;
(*ippDS)->buffer = NULL;
(*ippDS)->buflen = 0;
(*ippDS)->writelead = 0;
(*ippDS)->state = STATE_STOPPED;
(*ippDS)->nrofbuffers = 0;
(*ippDS)->buffers = NULL;
(*ippDS)->primary = NULL;
(*ippDS)->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
/* 3D listener initial parameters */
(*ippDS)->listener = NULL;
(*ippDS)->ds3dl.dwSize = sizeof(DS3DLISTENER);
(*ippDS)->ds3dl.vPosition.x = 0.0;
(*ippDS)->ds3dl.vPosition.y = 0.0;
(*ippDS)->ds3dl.vPosition.z = 0.0;
(*ippDS)->ds3dl.vVelocity.x = 0.0;
(*ippDS)->ds3dl.vVelocity.y = 0.0;
(*ippDS)->ds3dl.vVelocity.z = 0.0;
(*ippDS)->ds3dl.vOrientFront.x = 0.0;
(*ippDS)->ds3dl.vOrientFront.y = 0.0;
(*ippDS)->ds3dl.vOrientFront.z = 1.0;
(*ippDS)->ds3dl.vOrientTop.x = 0.0;
(*ippDS)->ds3dl.vOrientTop.y = 1.0;
(*ippDS)->ds3dl.vOrientTop.z = 0.0;
(*ippDS)->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
(*ippDS)->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
(*ippDS)->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
(*ippDS)->prebuf = ds_snd_queue_max;
(*ippDS)->guid = devGuid;
/* Get driver description */
if (drv) {
err = IDsDriver_GetDriverDesc(drv,&((*ippDS)->drvdesc));
if (err != DS_OK) {
WARN("IDsDriver_GetDriverDesc failed\n");
HeapFree(GetProcessHeap(),0,*ippDS);
*ippDS = NULL;
return err;
}
} else {
/* if no DirectSound interface available, use WINMM API instead */
(*ippDS)->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
}
(*ippDS)->drvdesc.dnDevNode = wod;
/* Set default wave format (may need it for waveOutOpen) */
(*ippDS)->wfx.wFormatTag = WAVE_FORMAT_PCM;
/* We rely on the sound driver to return the actual sound format of
* the device if it does not support 22050x8x2 and is given the
* WAVE_DIRECTSOUND flag.
*/
(*ippDS)->wfx.nSamplesPerSec = 22050;
(*ippDS)->wfx.wBitsPerSample = 8;
(*ippDS)->wfx.nChannels = 2;
(*ippDS)->wfx.nBlockAlign = (*ippDS)->wfx.wBitsPerSample * (*ippDS)->wfx.nChannels / 8;
(*ippDS)->wfx.nAvgBytesPerSec = (*ippDS)->wfx.nSamplesPerSec * (*ippDS)->wfx.nBlockAlign;
(*ippDS)->wfx.cbSize = 0;
/* If the driver requests being opened through MMSYSTEM
* (which is recommended by the DDK), it is supposed to happen
* before the DirectSound interface is opened */
if ((*ippDS)->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
{
DWORD flags = CALLBACK_FUNCTION;
/* disable direct sound if requested */
if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
flags |= WAVE_DIRECTSOUND;
err = mmErr(waveOutOpen(&((*ippDS)->hwo),
(*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx),
(DWORD)DSOUND_callback, (DWORD)(*ippDS),
flags));
if (err != DS_OK) {
WARN("waveOutOpen failed\n");
HeapFree(GetProcessHeap(),0,*ippDS);
*ippDS = NULL;
return err;
}
}
if (drv) {
err = IDsDriver_Open(drv);
if (err != DS_OK) {
WARN("IDsDriver_Open failed\n");
HeapFree(GetProcessHeap(),0,*ippDS);
*ippDS = NULL;
return err;
}
/* the driver is now open, so it's now allowed to call GetCaps */
err = IDsDriver_GetCaps(drv,&((*ippDS)->drvcaps));
if (err != DS_OK) {
WARN("IDsDriver_GetCaps failed\n");
HeapFree(GetProcessHeap(),0,*ippDS);
*ippDS = NULL;
return err;
}
} else {
WAVEOUTCAPSA woc;
err = mmErr(waveOutGetDevCapsA((*ippDS)->drvdesc.dnDevNode, &woc, sizeof(woc)));
if (err != DS_OK) {
WARN("waveOutGetDevCaps failed\n");
HeapFree(GetProcessHeap(),0,*ippDS);
*ippDS = NULL;
return err;
}
ZeroMemory(&(*ippDS)->drvcaps, sizeof((*ippDS)->drvcaps));
if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
(woc.dwFormats & WAVE_FORMAT_2M08) ||
(woc.dwFormats & WAVE_FORMAT_4M08) ||
(woc.dwFormats & WAVE_FORMAT_48M08) ||
(woc.dwFormats & WAVE_FORMAT_96M08)) {
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
}
if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
(woc.dwFormats & WAVE_FORMAT_2M16) ||
(woc.dwFormats & WAVE_FORMAT_4M16) ||
(woc.dwFormats & WAVE_FORMAT_48M16) ||
(woc.dwFormats & WAVE_FORMAT_96M16)) {
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
}
if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
(woc.dwFormats & WAVE_FORMAT_2S08) ||
(woc.dwFormats & WAVE_FORMAT_4S08) ||
(woc.dwFormats & WAVE_FORMAT_48S08) ||
(woc.dwFormats & WAVE_FORMAT_96S08)) {
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
}
if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
(woc.dwFormats & WAVE_FORMAT_2S16) ||
(woc.dwFormats & WAVE_FORMAT_4S16) ||
(woc.dwFormats & WAVE_FORMAT_48S16) ||
(woc.dwFormats & WAVE_FORMAT_96S16)) {
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
(*ippDS)->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
}
if (ds_emuldriver)
(*ippDS)->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
(*ippDS)->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
(*ippDS)->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
(*ippDS)->drvcaps.dwPrimaryBuffers = 1;
}
(*ippDS)->volpan.lVolume = 0;
(*ippDS)->volpan.lPan = 0;
DSOUND_RecalcVolPan(&((*ippDS)->volpan));
InitializeCriticalSection(&((*ippDS)->mixlock));
RtlInitializeResource(&((*ippDS)->lock));
if (!dsound) {
HRESULT hres;
dsound = (*ippDS);
hres = DSOUND_PrimaryCreate(dsound);
if (hres != DS_OK) {
WARN("DSOUND_PrimaryCreate failed\n");
return hres;
}
timeBeginPeriod(DS_TIME_RES);
dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
(DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
}
return DS_OK;
}
/*******************************************************************************
* DirectSound ClassFactory
*/

View File

@ -45,6 +45,11 @@ extern int ds_default_capture;
* Predeclare the interface implementation structures
*/
typedef struct IDirectSoundImpl IDirectSoundImpl;
typedef struct IDirectSound_IUnknown IDirectSound_IUnknown;
typedef struct IDirectSound_IDirectSound IDirectSound_IDirectSound;
typedef struct IDirectSound8_IUnknown IDirectSound8_IUnknown;
typedef struct IDirectSound8_IDirectSound IDirectSound8_IDirectSound;
typedef struct IDirectSound8_IDirectSound8 IDirectSound8_IDirectSound8;
typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl;
typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl;
typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
@ -95,6 +100,10 @@ struct IDirectSoundImpl
IDirectSound3DListenerImpl* listener;
DS3DLISTENER ds3dl;
BOOL ds3dl_need_recalc;
LPUNKNOWN pUnknown;
LPDIRECTSOUND pDS;
LPDIRECTSOUND8 pDS8;
};
/* reference counted buffer memory for duplicated buffer memory */
@ -104,6 +113,66 @@ typedef struct BufferMemory
LPBYTE memory;
} BufferMemory;
HRESULT WINAPI IDirectSoundImpl_Create(
LPCGUID lpcGUID,
LPDIRECTSOUND8 * ppds);
/*****************************************************************************
* IDirectSound COM components
*/
struct IDirectSound_IUnknown {
ICOM_VFIELD(IUnknown);
DWORD ref;
LPDIRECTSOUND8 pds;
};
HRESULT WINAPI IDirectSound_IUnknown_Create(
LPDIRECTSOUND8 pds,
LPUNKNOWN * ppunk);
struct IDirectSound_IDirectSound {
ICOM_VFIELD(IDirectSound);
DWORD ref;
LPDIRECTSOUND8 pds;
};
HRESULT WINAPI IDirectSound_IDirectSound_Create(
LPDIRECTSOUND8 pds,
LPDIRECTSOUND * ppds);
/*****************************************************************************
* IDirectSound8 COM components
*/
struct IDirectSound8_IUnknown {
ICOM_VFIELD(IUnknown);
DWORD ref;
LPDIRECTSOUND8 pds;
};
HRESULT WINAPI IDirectSound8_IUnknown_Create(
LPDIRECTSOUND8 pds,
LPUNKNOWN * ppunk);
struct IDirectSound8_IDirectSound {
ICOM_VFIELD(IDirectSound);
DWORD ref;
LPDIRECTSOUND8 pds;
};
HRESULT WINAPI IDirectSound8_IDirectSound_Create(
LPDIRECTSOUND8 pds,
LPDIRECTSOUND * ppds);
struct IDirectSound8_IDirectSound8 {
ICOM_VFIELD(IDirectSound8);
DWORD ref;
LPDIRECTSOUND8 pds;
};
HRESULT WINAPI IDirectSound8_IDirectSound8_Create(
LPDIRECTSOUND8 pds,
LPDIRECTSOUND8 * ppds);
/*****************************************************************************
* IDirectSoundBuffer implementation structure
*/

View File

@ -36,6 +36,7 @@
#include "windef.h"
#include "wingdi.h"
#include "dsound.h"
#include "dxerr9.h"
#include "dsound_test.h"
@ -46,32 +47,51 @@ static HRESULT test_dsound(LPGUID lpGuid)
LPDIRECTSOUND dso=NULL;
DSCAPS dscaps;
int ref;
IUnknown * unknown;
IDirectSound * ds;
IDirectSound8 * ds8;
/* DSOUND: Error: Invalid interface buffer */
rc=DirectSoundCreate(lpGuid,0,NULL);
ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate should have failed: 0x%lx\n",rc);
ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate should have failed: %s\n",DXGetErrorString9(rc));
/* Create the DirectSound object */
rc=DirectSoundCreate(lpGuid,&dso,NULL);
ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
ok(rc==DS_OK,"DirectSoundCreate failed: %s\n",DXGetErrorString9(rc));
if (rc!=DS_OK)
return rc;
/* Try to Query for objects */
rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown);
ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IUnknown) failed: %s\n",DXGetErrorString9(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: %s\n",DXGetErrorString9(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: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK)
IDirectSound8_Release(ds8);
/* DSOUND: Error: Invalid caps buffer */
rc=IDirectSound_GetCaps(dso,0);
ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: %s\n",DXGetErrorString9(rc));
ZeroMemory(&dscaps, sizeof(dscaps));
/* DSOUND: Error: Invalid caps buffer */
rc=IDirectSound_GetCaps(dso,&dscaps);
ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: 0x%lx\n",rc);
ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: %s\n",DXGetErrorString9(rc));
dscaps.dwSize=sizeof(dscaps);
/* DSOUND: Running on a certified driver */
rc=IDirectSound_GetCaps(dso,&dscaps);
ok(rc==DS_OK,"GetCaps failed: 0x%lx\n",rc);
ok(rc==DS_OK,"GetCaps failed: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK) {
trace(" DirectSound Caps: flags=0x%08lx secondary min=%ld max=%ld\n",
dscaps.dwFlags,dscaps.dwMinSecondarySampleRate,
@ -84,17 +104,15 @@ static HRESULT test_dsound(LPGUID lpGuid)
if (ref!=0)
return DSERR_GENERIC;
#if 0
/* FIXME: this works on windows */
/* Create a DirectSound object */
rc=DirectSoundCreate(lpGuid,&dso,NULL);
ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
ok(rc==DS_OK,"DirectSoundCreate failed: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK) {
LPDIRECTSOUND dso1=NULL;
/* Create a second DirectSound object */
rc=DirectSoundCreate(lpGuid,&dso1,NULL);
ok(rc==DS_OK,"DirectSoundCreate failed: 0x%lx\n",rc);
ok(rc==DS_OK,"DirectSoundCreate failed: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK) {
/* Release the second DirectSound object */
ref=IDirectSound_Release(dso1);
@ -109,7 +127,96 @@ static HRESULT test_dsound(LPGUID lpGuid)
return DSERR_GENERIC;
} else
return rc;
#endif
return DS_OK;
}
static HRESULT test_dsound8(LPGUID lpGuid)
{
HRESULT rc;
LPDIRECTSOUND8 dso=NULL;
DSCAPS dscaps;
int ref;
IUnknown * unknown;
IDirectSound * ds;
IDirectSound8 * ds8;
/* DSOUND: Error: Invalid interface buffer */
rc=DirectSoundCreate8(lpGuid,0,NULL);
ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate8 should have failed: %s\n",DXGetErrorString9(rc));
/* Create the DirectSound8 object */
rc=DirectSoundCreate8(lpGuid,&dso,NULL);
ok(rc==DS_OK,"DirectSoundCreate8 failed: %s\n",DXGetErrorString9(rc));
if (rc!=DS_OK)
return rc;
/* Try to Query for objects */
rc=IDirectSound8_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown);
ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IUnknown) failed: %s\n",DXGetErrorString9(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: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK)
IDirectSound_Release(ds);
rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8);
ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound8) failed: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK)
IDirectSound8_Release(ds8);
/* DSOUND: Error: Invalid caps buffer */
rc=IDirectSound8_GetCaps(dso,0);
ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: %s\n",DXGetErrorString9(rc));
ZeroMemory(&dscaps, sizeof(dscaps));
/* DSOUND: Error: Invalid caps buffer */
rc=IDirectSound8_GetCaps(dso,&dscaps);
ok(rc==DSERR_INVALIDPARAM,"GetCaps should have failed: %s\n",DXGetErrorString9(rc));
dscaps.dwSize=sizeof(dscaps);
/* DSOUND: Running on a certified driver */
rc=IDirectSound8_GetCaps(dso,&dscaps);
ok(rc==DS_OK,"GetCaps failed: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK) {
trace(" DirectSound Caps: flags=0x%08lx secondary min=%ld max=%ld\n",
dscaps.dwFlags,dscaps.dwMinSecondarySampleRate,
dscaps.dwMaxSecondarySampleRate);
}
/* Release the DirectSound8 object */
ref=IDirectSound8_Release(dso);
ok(ref==0,"IDirectSound_Release has %d references, should have 0\n",ref);
if (ref!=0)
return DSERR_GENERIC;
/* Create a DirectSound8 object */
rc=DirectSoundCreate8(lpGuid,&dso,NULL);
ok(rc==DS_OK,"DirectSoundCreate failed: %s\n",DXGetErrorString9(rc));
if (rc==DS_OK) {
LPDIRECTSOUND8 dso1=NULL;
/* Create a second DirectSound8 object */
rc=DirectSoundCreate8(lpGuid,&dso1,NULL);
ok(rc==DS_OK,"DirectSoundCreate8 failed: %s\n",DXGetErrorString9(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=0x%08lx,dso1=0x%08lx\n",(DWORD)dso,(DWORD)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;
return DS_OK;
}
@ -294,6 +401,7 @@ static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription,
{
trace("*** Testing %s - %s\n",lpcstrDescription,lpcstrModule);
test_dsound(lpGuid);
test_dsound8(lpGuid);
test_primary(lpGuid);
test_secondary(lpGuid);

View File

@ -456,9 +456,9 @@ ICOM_DEFINE(IDirectSound,IUnknown)
#define INTERFACE IDirectSound8
#define IDirectSound8_METHODS \
IUnknown_METHODS \
STDMETHOD(CreateSoundBuffer)(THIS_ LPCDSBUFFERDESC lpcDSBufferDesc, LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer, IUnknown *pUnkOuter) PURE; \
STDMETHOD(CreateSoundBuffer)(THIS_ LPCDSBUFFERDESC lpcDSBufferDesc, LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer, IUnknown *pUnkOuter) PURE; \
STDMETHOD(GetCaps)(THIS_ LPDSCAPS lpDSCaps) PURE; \
STDMETHOD(DuplicateSoundBuffer)(THIS_ LPDIRECTSOUNDBUFFER8 lpDsbOriginal, LPLPDIRECTSOUNDBUFFER8 lplpDsbDuplicate) PURE; \
STDMETHOD(DuplicateSoundBuffer)(THIS_ LPDIRECTSOUNDBUFFER lpDsbOriginal, LPLPDIRECTSOUNDBUFFER lplpDsbDuplicate) PURE; \
STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwLevel) PURE; \
STDMETHOD(Compact)(THIS) PURE; \
STDMETHOD(GetSpeakerConfig)(THIS_ LPDWORD lpdwSpeakerConfig) PURE; \