dsound: use event based threads, v2

Andrew Eikum aeikum at codeweavers.com
Thu Dec 20 10:51:42 CST 2012


Looks good to me, no problems with any of the drivers. I think it'd be
good to get it in on Monday, as release day is tomorrow, but that's
not my call.

Andrew

On Wed, Dec 19, 2012 at 10:30:04AM +0100, Maarten Lankhorst wrote:
> Use a thread instead of a timer for greater precision.
> 
> Changes since v1:
> - Add WARN on failure of Start or GetStreamLatency
> - Set lower bound of sleep time to 5 ms
> - Change upper bound of sleep time to 2.5x period
> - Fixup comment
> 
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at ubuntu.com>
> ---
> I like how the most useful part of the changelog always gets stripped out.
> What's the point of even adding this info here?
> 
> Obligatory "Yes I know the error handling I added isn't perfect, and I did fix that in my failure rework patch" here..
> 
> ---
>  dlls/dsound/dsound.c         | 21 +++++++++++----------
>  dlls/dsound/dsound_private.h |  7 ++++---
>  dlls/dsound/mixer.c          | 39 +++++++++++++++++++++++----------------
>  dlls/dsound/primary.c        | 27 ++++++++++++++++++++++++---
>  4 files changed, 62 insertions(+), 32 deletions(-)
> 
> diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
> index ac85ba2..381d0e1 100644
> --- a/dlls/dsound/dsound.c
> +++ b/dlls/dsound/dsound.c
> @@ -670,14 +670,13 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
>      TRACE("(%p) ref was %u\n", device, ref + 1);
>      if (!ref) {
>          int i;
> -        timeKillEvent(device->timerID);
> -        timeEndPeriod(DS_TIME_RES);
>  
> -        /* The kill event should have allowed the timer process to expire
> -         * but try to grab the lock just in case. Can't hold lock because
> -         * secondarybuffer_destroy also grabs the lock */
> -        RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
> -        RtlReleaseResource(&(device->buffer_list_lock));
> +        SetEvent(device->sleepev);
> +        if (device->thread) {
> +            WaitForSingleObject(device->thread, INFINITE);
> +            CloseHandle(device->thread);
> +        }
> +        CloseHandle(device->sleepev);
>  
>          EnterCriticalSection(&DSOUND_renderers_lock);
>          list_remove(&device->entry);
> @@ -813,6 +812,7 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
>  
>      device->mmdevice = mmdevice;
>      device->guid = devGUID;
> +    device->sleepev = CreateEventW(0, 0, 0, 0);
>  
>      hr = DSOUND_ReopenDevice(device, FALSE);
>      if (FAILED(hr))
> @@ -869,9 +869,10 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
>      ZeroMemory(&device->volpan, sizeof(device->volpan));
>  
>      hr = DSOUND_PrimaryCreate(device);
> -    if (hr == DS_OK)
> -        device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device);
> -    else
> +    if (hr == DS_OK) {
> +        device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
> +        SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
> +    } else
>          WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
>  
>      *ppDevice = device;
> diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
> index 62656a5..1a3900c 100644
> --- a/dlls/dsound/dsound_private.h
> +++ b/dlls/dsound/dsound_private.h
> @@ -68,9 +68,9 @@ struct DirectSoundDevice
>  
>      GUID                        guid;
>      DSCAPS                      drvcaps;
> -    DWORD                       priolevel;
> +    DWORD                       priolevel, sleeptime;
>      PWAVEFORMATEX               pwfx, primary_pwfx;
> -    UINT                        timerID, playing_offs_bytes, in_mmdev_bytes, prebuf;
> +    UINT                        playing_offs_bytes, in_mmdev_bytes, prebuf;
>      DWORD                       fraglen;
>      LPBYTE                      buffer;
>      DWORD                       writelead, buflen, state, playpos, mixpos;
> @@ -97,6 +97,7 @@ struct DirectSoundDevice
>      IAudioStreamVolume *volume;
>      IAudioRenderClient *render;
>  
> +    HANDLE sleepev, thread;
>      struct list entry;
>  };
>  
> @@ -226,7 +227,7 @@ void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan) DECLSPEC_HIDDEN;
>  void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) DECLSPEC_HIDDEN;
>  DWORD DSOUND_secpos_to_bufpos(const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, float *overshot) DECLSPEC_HIDDEN;
>  
> -void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) DECLSPEC_HIDDEN;
> +DWORD CALLBACK DSOUND_mixthread(void *ptr) DECLSPEC_HIDDEN;
>  
>  /* sound3d.c */
>  
> diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
> index 84e029b..282808e 100644
> --- a/dlls/dsound/mixer.c
> +++ b/dlls/dsound/mixer.c
> @@ -820,7 +820,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
>  			DSOUND_PrimaryStop(device);
>  		}
>  
> -	} else {
> +	} else if (device->state != STATE_STOPPED) {
>  
>  		DSOUND_WaveQueue(device, TRUE);
>  
> @@ -843,22 +843,29 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
>  	/* **** */
>  }
>  
> -void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
> -                           DWORD_PTR dw1, DWORD_PTR dw2)
> +DWORD CALLBACK DSOUND_mixthread(void *p)
>  {
> -	DirectSoundDevice * device = (DirectSoundDevice*)dwUser;
> -	DWORD start_time =  GetTickCount();
> -	DWORD end_time;
> -	TRACE("(%d,%d,0x%lx,0x%lx,0x%lx)\n",timerID,msg,dwUser,dw1,dw2);
> -	TRACE("entering at %d\n", start_time);
> -
> -	RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
> -
> -	if (device->ref)
> -		DSOUND_PerformMix(device);
> +	DirectSoundDevice *dev = p;
> +	TRACE("(%p)\n", dev);
>  
> -	RtlReleaseResource(&(device->buffer_list_lock));
> +	while (dev->ref) {
> +		DWORD ret;
>  
> -	end_time = GetTickCount();
> -	TRACE("completed processing at %d, duration = %d\n", end_time, end_time - start_time);
> +		/*
> +		 * Some audio drivers are retarded and won't fire after being
> +		 * stopped, add a timeout to handle this.
> +		 */
> +		ret = WaitForSingleObject(dev->sleepev, dev->sleeptime);
> +		if (ret == WAIT_FAILED)
> +			WARN("wait returned error %u %08x!\n", GetLastError(), GetLastError());
> +		else if (ret != WAIT_OBJECT_0)
> +			WARN("wait returned %08x!\n", ret);
> +		if (!dev->ref)
> +			break;
> +
> +		RtlAcquireResourceShared(&(dev->buffer_list_lock), TRUE);
> +		DSOUND_PerformMix(dev);
> +		RtlReleaseResource(&(dev->buffer_list_lock));
> +	}
> +	return 0;
>  }
> diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
> index 3ac928b..dd810fd 100644
> --- a/dlls/dsound/primary.c
> +++ b/dlls/dsound/primary.c
> @@ -152,6 +152,8 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
>      REFERENCE_TIME prebuf_rt;
>      WAVEFORMATEX *wfx = NULL;
>      HRESULT hres;
> +    REFERENCE_TIME period;
> +    DWORD period_ms;
>  
>      TRACE("(%p, %d)\n", device, forcewave);
>  
> @@ -192,14 +194,15 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
>      prebuf_rt = (10000000 * (UINT64)prebuf_frames) / device->pwfx->nSamplesPerSec;
>  
>      hres = IAudioClient_Initialize(device->client,
> -            AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
> -            prebuf_rt, 0, device->pwfx, NULL);
> +            AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
> +            AUDCLNT_STREAMFLAGS_EVENTCALLBACK, prebuf_rt, 0, device->pwfx, NULL);
>      if(FAILED(hres)){
>          IAudioClient_Release(device->client);
>          device->client = NULL;
>          WARN("Initialize failed: %08x\n", hres);
>          return hres;
>      }
> +    IAudioClient_SetEventHandle(device->client, device->sleepev);
>  
>      hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient,
>              (void**)&device->render);
> @@ -234,6 +237,24 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
>          return hres;
>      }
>  
> +    /* Now kick off the timer so the event fires periodically */
> +    hres = IAudioClient_Start(device->client);
> +    if (FAILED(hres))
> +        WARN("starting failed with %08x\n", hres);
> +
> +    hres = IAudioClient_GetStreamLatency(device->client, &period);
> +    if (FAILED(hres)) {
> +        WARN("GetStreamLatency failed with %08x\n", hres);
> +        period_ms = 10;
> +    } else
> +        period_ms = (period + 9999) / 10000;
> +    TRACE("period %u ms fraglen %u prebuf %u\n", period_ms, device->fraglen, device->prebuf);
> +
> +    if (period_ms < 3)
> +        device->sleeptime = 5;
> +    else
> +        device->sleeptime = period_ms * 5 / 2;
> +
>      return S_OK;
>  }
>  
> @@ -379,7 +400,7 @@ HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device)
>      TRACE("(%p)\n", device);
>  
>      hr = IAudioClient_Start(device->client);
> -    if(FAILED(hr)){
> +    if(FAILED(hr) && hr != AUDCLNT_E_NOT_STOPPED){
>          WARN("Start failed: %08x\n", hr);
>          return hr;
>      }
> -- 
> 1.8.0
> 
> 
> 
> 



More information about the wine-devel mailing list