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(a)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
>
>
>
>