dsound: Use a thread instead of a timer for greater precision.
This commit is contained in:
parent
8dc7a72a14
commit
f5abeb8471
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
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;
|
||||||
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)
|
||||||
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)
|
||||||
/* **** */
|
/* **** */
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
while (dev->ref) {
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
if (device->ref)
|
/*
|
||||||
DSOUND_PerformMix(device);
|
* 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;
|
||||||
|
|
||||||
RtlReleaseResource(&(device->buffer_list_lock));
|
RtlAcquireResourceShared(&(dev->buffer_list_lock), TRUE);
|
||||||
|
DSOUND_PerformMix(dev);
|
||||||
end_time = GetTickCount();
|
RtlReleaseResource(&(dev->buffer_list_lock));
|
||||||
TRACE("completed processing at %d, duration = %d\n", end_time, end_time - start_time);
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue