diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c index 2d63e78cc6c..30ee96d0d35 100644 --- a/dlls/dsound/capture.c +++ b/dlls/dsound/capture.c @@ -64,6 +64,16 @@ static HRESULT DSOUND_CreateDirectSoundCaptureBuffer( IDirectSoundCaptureImpl *ipDSC, LPCDSCBUFFERDESC lpcDSCBufferDesc, LPVOID* ppobj ); +static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize( + LPDIRECTSOUNDFULLDUPLEX iface, + LPCGUID pCaptureGuid, + LPCGUID pRendererGuid, + LPCDSCBUFFERDESC lpDscBufferDesc, + LPCDSBUFFERDESC lpDsBufferDesc, + HWND hWnd, + DWORD dwLevel, + LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, + LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 ); static ICOM_VTABLE(IDirectSoundCapture) dscvt; static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt; @@ -427,9 +437,13 @@ IDirectSoundCaptureImpl_Initialize( } err = DS_OK; + /* Disable the direct sound driver to force emulation if requested. */ + if (ds_hw_accel == DS_HW_ACCEL_EMULATION) + This->driver = NULL; + /* Get driver description */ if (This->driver) { - ERR("You have a sound card that is Direct Sound Capture capable but the driver is not finished\n"); + ERR("You have a sound card that is Direct Sound Capture capable but the driver is not finished. You can add a line to the wine config file in [dsound]: \"HardwareAcceleration\" = \"Emulation\" to force emulation mode.\n"); /* FIXME: remove this return to test driver */ return DSERR_NODRIVER; TRACE("using DirectSound driver\n"); @@ -455,6 +469,7 @@ IDirectSoundCaptureImpl_Initialize( /* the driver is now open, so it's now allowed to call GetCaps */ if (This->driver) { + This->drvcaps.dwSize = sizeof(This->drvcaps); err = IDsCaptureDriver_GetCaps(This->driver,&(This->drvcaps)); if (err != DS_OK) { WARN("IDsCaptureDriver_GetCaps failed\n"); @@ -580,10 +595,12 @@ DSOUND_CreateDirectSoundCaptureBuffer( } else { LPBYTE newbuf; DWORD buflen; + DWORD flags = CALLBACK_FUNCTION; + if (ds_hw_accel != DS_HW_ACCEL_EMULATION) + flags |= WAVE_DIRECTSOUND; err = mmErr(waveInOpen(&(ipDSC->hwi), ipDSC->drvdesc.dnDevNode, &(ipDSC->wfx), - (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, - CALLBACK_FUNCTION | WAVE_DIRECTSOUND)); + (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags)); if (err != DS_OK) { WARN("waveInOpen failed\n"); ipDSC->hwi = 0; @@ -757,6 +774,7 @@ IDirectSoundCaptureBufferImpl_GetCurrentPosition( if (This->dsound->driver) { return IDsCaptureDriverBuffer_GetPosition(This->dsound->hwbuf, lpdwCapturePosition, lpdwReadPosition ); } else if (This->dsound->hwi) { + EnterCriticalSection(&(This->dsound->lock)); TRACE("old This->dsound->state=%ld\n",This->dsound->state); if (lpdwCapturePosition) { MMTIME mtime; @@ -777,6 +795,7 @@ IDirectSoundCaptureBufferImpl_GetCurrentPosition( *lpdwReadPosition = This->dsound->read_position; } TRACE("new This->dsound->state=%ld\n",This->dsound->state); + LeaveCriticalSection(&(This->dsound->lock)); if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition); if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition); } else { @@ -838,6 +857,8 @@ IDirectSoundCaptureBufferImpl_GetStatus( } *lpdwStatus = 0; + EnterCriticalSection(&(This->dsound->lock)); + TRACE("old This->dsound->state=%ld, old lpdwStatus=%08lx\n",This->dsound->state,*lpdwStatus); if ((This->dsound->state == STATE_STARTING) || (This->dsound->state == STATE_CAPTURING)) { @@ -846,6 +867,7 @@ IDirectSoundCaptureBufferImpl_GetStatus( *lpdwStatus |= DSCBSTATUS_LOOPING; } TRACE("new This->dsound->state=%ld, new lpdwStatus=%08lx\n",This->dsound->state,*lpdwStatus); + LeaveCriticalSection(&(This->dsound->lock)); TRACE("status=%lx\n", *lpdwStatus); TRACE("returning DS_OK\n"); @@ -1170,6 +1192,63 @@ static ICOM_VTABLE(IDirectSoundCaptureBuffer8) dscbvt = IDirectSoundCaptureBufferImpl_GetFXStatus }; +/*************************************************************************** + * DirectSoundFullDuplexCreate8 [DSOUND.8] + * + * Create and initialize a DirectSoundFullDuplex interface + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM, + * DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER + */ +HRESULT WINAPI +DirectSoundFullDuplexCreate8( + LPCGUID pcGuidCaptureDevice, + LPCGUID pcGuidRenderDevice, + LPCDSCBUFFERDESC pcDSCBufferDesc, + LPCDSBUFFERDESC pcDSBufferDesc, + HWND hWnd, + DWORD dwLevel, + LPDIRECTSOUNDFULLDUPLEX *ppDSFD, + LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8, + LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, + LPUNKNOWN pUnkOuter) +{ + IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD; + TRACE("(%s,%s,%p,%p,%lx,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice), + debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc, + (DWORD)hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter); + + if ( pUnkOuter ) { + WARN("pUnkOuter != 0\n"); + return DSERR_NOAGGREGATION; + } + + *ippDSFD = (IDirectSoundFullDuplexImpl*)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl)); + + if (*ippDSFD == NULL) { + TRACE("couldn't allocate memory\n"); + return DSERR_OUTOFMEMORY; + } + else + { + ICOM_THIS(IDirectSoundFullDuplexImpl, *ippDSFD); + + This->ref = 1; + + InitializeCriticalSection( &(This->lock) ); + + ICOM_VTBL(This) = &dsfdvt; + + return IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This, + pcGuidCaptureDevice, pcGuidRenderDevice, + pcDSCBufferDesc, pcDSBufferDesc, + hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8); + } +} + static HRESULT WINAPI IDirectSoundFullDuplexImpl_QueryInterface( LPDIRECTSOUNDFULLDUPLEX iface, @@ -1192,6 +1271,7 @@ IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface ) TRACE( "(%p) was 0x%08lx\n", This, This->ref ); uRef = ++(This->ref); + LeaveCriticalSection( &(This->lock) ); return uRef; diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index b92e7cae4de..dc64502432e 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -115,6 +115,7 @@ int ds_hel_margin = DS_HEL_MARGIN; int ds_hel_queue = DS_HEL_QUEUE; int ds_snd_queue_max = DS_SND_QUEUE_MAX; int ds_snd_queue_min = DS_SND_QUEUE_MIN; +int ds_hw_accel = DS_HW_ACCEL_FULL; /* * Call the callback provided to DirectSoundEnumerateA. @@ -199,6 +200,17 @@ void setup_dsound_options(void) if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH )) ds_snd_queue_min = atoi(buffer); + if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) { + if (strcmp(buffer, "Full") == 0) + ds_hw_accel = DS_HW_ACCEL_FULL; + else if (strcmp(buffer, "Standard") == 0) + ds_hw_accel = DS_HW_ACCEL_STANDARD; + else if (strcmp(buffer, "Basic") == 0) + ds_hw_accel = DS_HW_ACCEL_BASIC; + else if (strcmp(buffer, "Emulation") == 0) + ds_hw_accel = DS_HW_ACCEL_EMULATION; + } + if (appkey) RegCloseKey( appkey ); RegCloseKey( hkey ); @@ -212,7 +224,13 @@ void setup_dsound_options(void) WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX); if (ds_snd_queue_min != DS_SND_QUEUE_MIN) WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN); - + if (ds_hw_accel != DS_HW_ACCEL_FULL) + WARN("ds_hw_accel = %s (default=Full)\n", + ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" : + ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" : + ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" : + ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" : + "Unknown"); } @@ -604,6 +622,10 @@ HRESULT WINAPI DirectSoundCreate8(REFGUID lpGUID,LPDIRECTSOUND8 *ppDS,IUnknown * /* 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) @@ -654,6 +676,12 @@ HRESULT WINAPI DirectSoundCreate8(REFGUID lpGUID,LPDIRECTSOUND8 *ppDS,IUnknown * * 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; + /* FIXME: is this right? */ (*ippDS)->drvdesc.dnDevNode = 0; err = DSERR_ALLOCATED; @@ -665,7 +693,7 @@ HRESULT WINAPI DirectSoundCreate8(REFGUID lpGUID,LPDIRECTSOUND8 *ppDS,IUnknown * err = mmErr(waveOutOpen(&((*ippDS)->hwo), (*ippDS)->drvdesc.dnDevNode, &((*ippDS)->wfx), (DWORD)DSOUND_callback, (DWORD)(*ippDS), - CALLBACK_FUNCTION | WAVE_DIRECTSOUND)); + flags)); (*ippDS)->drvdesc.dnDevNode++; /* next wave device */ } diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 2a99731d3fc..1ad3ffdff0f 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -26,11 +26,18 @@ #define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer * (changing this won't help you) */ +/* direct sound hardware acceleration levels */ +#define DS_HW_ACCEL_FULL 0 /* default on Windows 98 */ +#define DS_HW_ACCEL_STANDARD 1 /* default on Windows 2000 */ +#define DS_HW_ACCEL_BASIC 2 +#define DS_HW_ACCEL_EMULATION 3 + extern int ds_emuldriver; extern int ds_hel_margin; extern int ds_hel_queue; extern int ds_snd_queue_max; extern int ds_snd_queue_min; +extern int ds_hw_accel; /***************************************************************************** * Predeclare the interface implementation structures diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index d93cb8f44e0..d2faa8b8a33 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -901,11 +901,7 @@ void DSOUND_PerformMix(void) /* DSOUND_callback may need this lock */ LeaveCriticalSection(&(dsound->mixlock)); #endif - /* FIXME: OSS doesn't allow independent stopping of input and output streams */ - /* in full duplex mode so don't stop when capturing. This should be moved into */ - /* the OSS driver someday. */ - if ( (dsound_capture == NULL) || (dsound_capture->state != STATE_CAPTURING) ) - DSOUND_PrimaryStop(dsound); + DSOUND_PrimaryStop(dsound); #ifdef SYNC_CALLBACK EnterCriticalSection(&(dsound->mixlock)); #endif diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c index 887bf74767f..e65074183c1 100644 --- a/dlls/dsound/primary.c +++ b/dlls/dsound/primary.c @@ -213,6 +213,9 @@ HRESULT DSOUND_PrimaryStop(IDirectSoundImpl *This) if (This->hwbuf) { err = IDsDriverBuffer_Stop(This->hwbuf); if (err == DSERR_BUFFERLOST) { + DWORD flags = CALLBACK_FUNCTION; + if (ds_hw_accel != DS_HW_ACCEL_EMULATION) + flags |= WAVE_DIRECTSOUND; /* Wine-only: the driver wants us to reopen the device */ /* FIXME: check for errors */ IDsDriverBuffer_Release(This->hwbuf); @@ -220,7 +223,7 @@ HRESULT DSOUND_PrimaryStop(IDirectSoundImpl *This) This->hwo = 0; err = mmErr(waveOutOpen(&(This->hwo), This->drvdesc.dnDevNode, &(This->wfx), (DWORD)DSOUND_callback, (DWORD)This, - CALLBACK_FUNCTION | WAVE_DIRECTSOUND)); + flags)); if (err == DS_OK) err = IDsDriver_CreateSoundBuffer(This->driver,&(This->wfx), DSBCAPS_PRIMARYBUFFER,0, @@ -323,13 +326,16 @@ static HRESULT WINAPI PrimaryBufferImpl_SetFormat( dsound->wfx.nSamplesPerSec * dsound->wfx.nBlockAlign; if (dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) { + DWORD flags = CALLBACK_FUNCTION; + if (ds_hw_accel != DS_HW_ACCEL_EMULATION) + flags |= WAVE_DIRECTSOUND; /* FIXME: check for errors */ DSOUND_PrimaryClose(dsound); waveOutClose(dsound->hwo); dsound->hwo = 0; err = mmErr(waveOutOpen(&(dsound->hwo), dsound->drvdesc.dnDevNode, &(dsound->wfx), (DWORD)DSOUND_callback, (DWORD)dsound, - CALLBACK_FUNCTION | WAVE_DIRECTSOUND)); + flags)); if (err == DS_OK) DSOUND_PrimaryOpen(dsound); }