mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-02 04:43:38 +00:00
winecoreaudio: Implement and call timer_loop in unixlib.
This commit is contained in:
parent
c6a97c0f19
commit
357f0e9a49
|
@ -87,7 +87,7 @@ struct coreaudio_stream
|
|||
AUDCLNT_SHAREMODE share;
|
||||
HANDLE event;
|
||||
|
||||
BOOL playing;
|
||||
BOOL playing, please_quit;
|
||||
REFERENCE_TIME period;
|
||||
UINT32 period_frames;
|
||||
UINT32 bufsize_frames, resamp_bufsize_frames;
|
||||
|
@ -745,6 +745,12 @@ static NTSTATUS unix_release_stream( void *args )
|
|||
struct coreaudio_stream *stream = handle_get_stream(params->stream);
|
||||
SIZE_T size;
|
||||
|
||||
if(params->timer_thread){
|
||||
stream->please_quit = TRUE;
|
||||
NtWaitForSingleObject(params->timer_thread, FALSE, NULL);
|
||||
NtClose(params->timer_thread);
|
||||
}
|
||||
|
||||
if(stream->unit){
|
||||
AudioOutputUnitStop(stream->unit);
|
||||
AudioComponentInstanceDispose(stream->unit);
|
||||
|
@ -1370,6 +1376,35 @@ static NTSTATUS unix_reset(void *args)
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS unix_timer_loop(void *args)
|
||||
{
|
||||
struct timer_loop_params *params = args;
|
||||
struct coreaudio_stream *stream = handle_get_stream(params->stream);
|
||||
LARGE_INTEGER delay, next, last;
|
||||
int adjust;
|
||||
|
||||
delay.QuadPart = -stream->period;
|
||||
NtQueryPerformanceCounter(&last, NULL);
|
||||
next.QuadPart = last.QuadPart + stream->period;
|
||||
|
||||
while(!stream->please_quit){
|
||||
NtSetEvent(stream->event, NULL);
|
||||
NtDelayExecution(FALSE, &delay);
|
||||
NtQueryPerformanceCounter(&last, NULL);
|
||||
|
||||
adjust = next.QuadPart - last.QuadPart;
|
||||
if(adjust > stream->period / 2)
|
||||
adjust = stream->period / 2;
|
||||
else if(adjust < -stream->period / 2)
|
||||
adjust = -stream->period / 2;
|
||||
|
||||
delay.QuadPart = -(stream->period + adjust);
|
||||
next.QuadPart += stream->period;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS unix_get_render_buffer(void *args)
|
||||
{
|
||||
struct get_render_buffer_params *params = args;
|
||||
|
@ -1688,7 +1723,7 @@ unixlib_entry_t __wine_unix_call_funcs[] =
|
|||
unix_start,
|
||||
unix_stop,
|
||||
unix_reset,
|
||||
unix_not_implemented,
|
||||
unix_timer_loop,
|
||||
unix_get_render_buffer,
|
||||
unix_release_render_buffer,
|
||||
unix_get_capture_buffer,
|
||||
|
@ -2050,7 +2085,7 @@ unixlib_entry_t __wine_unix_call_wow64_funcs[] =
|
|||
unix_start,
|
||||
unix_stop,
|
||||
unix_reset,
|
||||
unix_not_implemented,
|
||||
unix_timer_loop,
|
||||
unix_wow64_get_render_buffer,
|
||||
unix_release_render_buffer,
|
||||
unix_wow64_get_capture_buffer,
|
||||
|
|
|
@ -91,8 +91,7 @@ struct ACImpl {
|
|||
IUnknown *pUnkFTMarshal;
|
||||
|
||||
EDataFlow dataflow;
|
||||
UINT32 channel_count, period_ms;
|
||||
HANDLE event;
|
||||
UINT32 channel_count;
|
||||
float *vols;
|
||||
|
||||
HANDLE timer;
|
||||
|
@ -127,8 +126,6 @@ typedef struct _SessionMgr {
|
|||
|
||||
static WCHAR drv_key_devicesW[256];
|
||||
|
||||
static HANDLE g_timer_q;
|
||||
|
||||
static CRITICAL_SECTION g_sessions_lock;
|
||||
static CRITICAL_SECTION_DEBUG g_sessions_lock_debug =
|
||||
{
|
||||
|
@ -212,15 +209,11 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
|||
swprintf(drv_key_devicesW, ARRAY_SIZE(drv_key_devicesW),
|
||||
L"Software\\Wine\\Drivers\\%s\\devices", filename);
|
||||
|
||||
g_timer_q = CreateTimerQueue();
|
||||
if(!g_timer_q)
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (reserved) break;
|
||||
DeleteCriticalSection(&g_sessions_lock);
|
||||
CloseHandle(g_timer_q);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -516,28 +509,17 @@ static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface)
|
|||
static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioClient3(iface);
|
||||
struct release_stream_params params;
|
||||
ULONG ref;
|
||||
|
||||
ref = InterlockedDecrement(&This->ref);
|
||||
TRACE("(%p) Refcount now %lu\n", This, ref);
|
||||
if(!ref){
|
||||
if(This->timer){
|
||||
HANDLE event;
|
||||
BOOL wait;
|
||||
event = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
|
||||
wait = wait && GetLastError() == ERROR_IO_PENDING;
|
||||
if(event && wait)
|
||||
WaitForSingleObject(event, INFINITE);
|
||||
CloseHandle(event);
|
||||
}
|
||||
if(This->stream){
|
||||
struct release_stream_params params;
|
||||
params.stream = This->stream;
|
||||
params.timer_thread = NULL;
|
||||
params.timer_thread = This->timer;
|
||||
UNIX_CALL(release_stream, ¶ms);
|
||||
}
|
||||
if(This->session){
|
||||
This->stream = 0;
|
||||
|
||||
EnterCriticalSection(&g_sessions_lock);
|
||||
list_remove(&This->entry);
|
||||
LeaveCriticalSection(&g_sessions_lock);
|
||||
|
@ -752,7 +734,6 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
|
|||
}
|
||||
|
||||
This->channel_count = fmt->nChannels;
|
||||
This->period_ms = period / 10000;
|
||||
|
||||
This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
|
||||
if(!This->vols){
|
||||
|
@ -922,18 +903,21 @@ static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
void CALLBACK ca_period_cb(void *user, BOOLEAN timer)
|
||||
static DWORD WINAPI ca_timer_thread(void *user)
|
||||
{
|
||||
struct timer_loop_params params;
|
||||
ACImpl *This = user;
|
||||
|
||||
if(This->event)
|
||||
SetEvent(This->event);
|
||||
params.stream = This->stream;
|
||||
SetThreadDescription(GetCurrentThread(), L"winecoreaudio_timer_loop");
|
||||
UNIX_CALL(timer_loop, ¶ms);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioClient3(iface);
|
||||
struct start_params params;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", This);
|
||||
|
||||
|
@ -942,19 +926,15 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
|
|||
|
||||
params.stream = This->stream;
|
||||
UNIX_CALL(start, ¶ms);
|
||||
if(FAILED(hr = params.result))
|
||||
return hr;
|
||||
|
||||
if(SUCCEEDED(params.result)){
|
||||
if(This->event && !This->timer){
|
||||
if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb, This, 0,
|
||||
This->period_ms, WT_EXECUTEINTIMERTHREAD)){
|
||||
This->timer = NULL;
|
||||
IAudioClient3_Stop(iface);
|
||||
WARN("Unable to create timer: %lu\n", GetLastError());
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
if(!This->timer) {
|
||||
This->timer = CreateThread(NULL, 0, ca_timer_thread, This, 0, NULL);
|
||||
SetThreadPriority(This->timer, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
return params.result;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
|
||||
|
@ -1004,13 +984,6 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
|
|||
params.stream = This->stream;
|
||||
params.event = event;
|
||||
UNIX_CALL(set_event_handle, ¶ms);
|
||||
|
||||
if(SUCCEEDED(params.result)){
|
||||
EnterCriticalSection(&g_sessions_lock);
|
||||
This->event = event;
|
||||
LeaveCriticalSection(&g_sessions_lock);
|
||||
}
|
||||
|
||||
return params.result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue