Commit f5abeb84 authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Alexandre Julliard

dsound: Use a thread instead of a timer for greater precision.

parent 8dc7a72a
...@@ -670,14 +670,13 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device) ...@@ -670,14 +670,13 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
TRACE("(%p) ref was %u\n", device, ref + 1); TRACE("(%p) ref was %u\n", device, ref + 1);
if (!ref) { if (!ref) {
int i; int i;
timeKillEvent(device->timerID);
timeEndPeriod(DS_TIME_RES);
/* The kill event should have allowed the timer process to expire SetEvent(device->sleepev);
* but try to grab the lock just in case. Can't hold lock because if (device->thread) {
* secondarybuffer_destroy also grabs the lock */ WaitForSingleObject(device->thread, INFINITE);
RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE); CloseHandle(device->thread);
RtlReleaseResource(&(device->buffer_list_lock)); }
CloseHandle(device->sleepev);
EnterCriticalSection(&DSOUND_renderers_lock); EnterCriticalSection(&DSOUND_renderers_lock);
list_remove(&device->entry); list_remove(&device->entry);
...@@ -813,6 +812,7 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG ...@@ -813,6 +812,7 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
device->mmdevice = mmdevice; device->mmdevice = mmdevice;
device->guid = devGUID; device->guid = devGUID;
device->sleepev = CreateEventW(0, 0, 0, 0);
hr = DSOUND_ReopenDevice(device, FALSE); hr = DSOUND_ReopenDevice(device, FALSE);
if (FAILED(hr)) if (FAILED(hr))
...@@ -869,9 +869,10 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG ...@@ -869,9 +869,10 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG
ZeroMemory(&device->volpan, sizeof(device->volpan)); ZeroMemory(&device->volpan, sizeof(device->volpan));
hr = DSOUND_PrimaryCreate(device); hr = DSOUND_PrimaryCreate(device);
if (hr == DS_OK) if (hr == DS_OK) {
device->timerID = DSOUND_create_timer(DSOUND_timer, (DWORD_PTR)device); device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
else SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
} else
WARN("DSOUND_PrimaryCreate failed: %08x\n", hr); WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
*ppDevice = device; *ppDevice = device;
......
...@@ -68,9 +68,9 @@ struct DirectSoundDevice ...@@ -68,9 +68,9 @@ struct DirectSoundDevice
GUID guid; GUID guid;
DSCAPS drvcaps; DSCAPS drvcaps;
DWORD priolevel; DWORD priolevel, sleeptime;
PWAVEFORMATEX pwfx, primary_pwfx; PWAVEFORMATEX pwfx, primary_pwfx;
UINT timerID, playing_offs_bytes, in_mmdev_bytes, prebuf; UINT playing_offs_bytes, in_mmdev_bytes, prebuf;
DWORD fraglen; DWORD fraglen;
LPBYTE buffer; LPBYTE buffer;
DWORD writelead, buflen, state, playpos, mixpos; DWORD writelead, buflen, state, playpos, mixpos;
...@@ -97,6 +97,7 @@ struct DirectSoundDevice ...@@ -97,6 +97,7 @@ struct DirectSoundDevice
IAudioStreamVolume *volume; IAudioStreamVolume *volume;
IAudioRenderClient *render; IAudioRenderClient *render;
HANDLE sleepev, thread;
struct list entry; struct list entry;
}; };
...@@ -226,7 +227,7 @@ void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan) DECLSPEC_HIDDEN; ...@@ -226,7 +227,7 @@ void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan) DECLSPEC_HIDDEN;
void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) 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; 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 */ /* sound3d.c */
......
...@@ -820,7 +820,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device) ...@@ -820,7 +820,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
DSOUND_PrimaryStop(device); DSOUND_PrimaryStop(device);
} }
} else { } else if (device->state != STATE_STOPPED) {
DSOUND_WaveQueue(device, TRUE); DSOUND_WaveQueue(device, TRUE);
...@@ -843,22 +843,29 @@ static void DSOUND_PerformMix(DirectSoundDevice *device) ...@@ -843,22 +843,29 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
/* **** */ /* **** */
} }
void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD CALLBACK DSOUND_mixthread(void *p)
DWORD_PTR dw1, DWORD_PTR dw2)
{ {
DirectSoundDevice * device = (DirectSoundDevice*)dwUser; DirectSoundDevice *dev = p;
DWORD start_time = GetTickCount(); TRACE("(%p)\n", dev);
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);
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;
} }
...@@ -152,6 +152,8 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) ...@@ -152,6 +152,8 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
REFERENCE_TIME prebuf_rt; REFERENCE_TIME prebuf_rt;
WAVEFORMATEX *wfx = NULL; WAVEFORMATEX *wfx = NULL;
HRESULT hres; HRESULT hres;
REFERENCE_TIME period;
DWORD period_ms;
TRACE("(%p, %d)\n", device, forcewave); TRACE("(%p, %d)\n", device, forcewave);
...@@ -192,14 +194,15 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) ...@@ -192,14 +194,15 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
prebuf_rt = (10000000 * (UINT64)prebuf_frames) / device->pwfx->nSamplesPerSec; prebuf_rt = (10000000 * (UINT64)prebuf_frames) / device->pwfx->nSamplesPerSec;
hres = IAudioClient_Initialize(device->client, hres = IAudioClient_Initialize(device->client,
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
prebuf_rt, 0, device->pwfx, NULL); AUDCLNT_STREAMFLAGS_EVENTCALLBACK, prebuf_rt, 0, device->pwfx, NULL);
if(FAILED(hres)){ if(FAILED(hres)){
IAudioClient_Release(device->client); IAudioClient_Release(device->client);
device->client = NULL; device->client = NULL;
WARN("Initialize failed: %08x\n", hres); WARN("Initialize failed: %08x\n", hres);
return hres; return hres;
} }
IAudioClient_SetEventHandle(device->client, device->sleepev);
hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient, hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient,
(void**)&device->render); (void**)&device->render);
...@@ -234,6 +237,24 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) ...@@ -234,6 +237,24 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
return hres; 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; return S_OK;
} }
...@@ -379,7 +400,7 @@ HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) ...@@ -379,7 +400,7 @@ HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device)
TRACE("(%p)\n", device); TRACE("(%p)\n", device);
hr = IAudioClient_Start(device->client); hr = IAudioClient_Start(device->client);
if(FAILED(hr)){ if(FAILED(hr) && hr != AUDCLNT_E_NOT_STOPPED){
WARN("Start failed: %08x\n", hr); WARN("Start failed: %08x\n", hr);
return hr; return hr;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment