dsound: use event based threads, v2
Maarten Lankhorst
m.b.lankhorst at gmail.com
Wed Dec 19 03:30:04 CST 2012
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-patches
mailing list