dmsynth: Create a render thread on sink activation.

This commit is contained in:
Rémi Bernon 2023-09-05 13:43:07 +02:00 committed by Alexandre Julliard
parent 27aed609c6
commit 0d56c54d8b
2 changed files with 154 additions and 3 deletions

View file

@ -25,6 +25,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(dmsynth);
#define BUFFER_SUBDIVISIONS 8
struct synth_sink
{
IDirectMusicSynthSink IDirectMusicSynthSink_iface;
@ -35,10 +37,17 @@ struct synth_sink
IReferenceClock *master_clock;
IDirectMusicSynth *synth; /* No reference hold! */
IDirectSound *dsound;
IDirectSoundBuffer *dsound_buffer;
BOOL active;
REFERENCE_TIME activate_time;
CRITICAL_SECTION cs;
REFERENCE_TIME latency_time;
DWORD written; /* number of bytes written out */
HANDLE stop_event;
HANDLE render_thread;
};
static inline struct synth_sink *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface)
@ -65,8 +74,93 @@ static void synth_sink_get_format(struct synth_sink *This, WAVEFORMATEX *format)
}
}
struct render_thread_params
{
struct synth_sink *sink;
IDirectMusicSynth *synth;
IDirectSoundBuffer *buffer;
HANDLE started_event;
};
static DWORD CALLBACK synth_sink_render_thread(void *args)
{
struct render_thread_params *params = args;
DSBCAPS caps = {.dwSize = sizeof(DSBCAPS)};
IDirectSoundBuffer *buffer = params->buffer;
IDirectMusicSynth *synth = params->synth;
struct synth_sink *sink = params->sink;
IDirectSoundNotify *notify;
HANDLE buffer_event;
HRESULT hr;
TRACE("Starting thread, args %p\n", args);
SetThreadDescription(GetCurrentThread(), L"wine_dmsynth_sink");
if (FAILED(hr = IDirectSoundBuffer_Stop(buffer)))
ERR("Failed to stop sound buffer, hr %#lx.\n", hr);
if (!(buffer_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
ERR("Failed to create buffer event, error %lu\n", GetLastError());
else if (FAILED(hr = IDirectSoundBuffer_GetCaps(buffer, &caps)))
ERR("Failed to query sound buffer caps, hr %#lx.\n", hr);
else if (FAILED(hr = IDirectSoundBuffer_QueryInterface(buffer, &IID_IDirectSoundNotify,
(void **)&notify)))
ERR("Failed to query IDirectSoundNotify iface, hr %#lx.\n", hr);
else
{
DSBPOSITIONNOTIFY positions[BUFFER_SUBDIVISIONS] = {{.dwOffset = 0, .hEventNotify = buffer_event}};
int i;
for (i = 1; i < ARRAY_SIZE(positions); ++i)
{
positions[i] = positions[i - 1];
positions[i].dwOffset += caps.dwBufferBytes / ARRAY_SIZE(positions);
}
if (FAILED(hr = IDirectSoundNotify_SetNotificationPositions(notify,
ARRAY_SIZE(positions), positions)))
ERR("Failed to set notification positions, hr %#lx\n", hr);
IDirectSoundNotify_Release(notify);
}
if (FAILED(hr = IDirectSoundBuffer_Play(buffer, 0, 0, DSBPLAY_LOOPING)))
ERR("Failed to start sound buffer, hr %#lx.\n", hr);
SetEvent(params->started_event);
while (hr == S_OK)
{
HANDLE handles[] = {sink->stop_event, buffer_event};
DWORD ret;
if (!(ret = WaitForMultipleObjects(ARRAY_SIZE(handles), handles, FALSE, INFINITE))
|| ret >= ARRAY_SIZE(handles))
{
ERR("WaitForMultipleObjects returned %lu\n", ret);
hr = HRESULT_FROM_WIN32(ret);
break;
}
}
if (FAILED(hr))
{
ERR("Thread unexpected termination, hr %#lx\n", hr);
return hr;
}
IDirectSoundBuffer_Release(buffer);
IDirectMusicSynth_Release(synth);
CloseHandle(buffer_event);
return 0;
}
static HRESULT synth_sink_activate(struct synth_sink *This)
{
IDirectMusicSynthSink *iface = &This->IDirectMusicSynthSink_iface;
DSBUFFERDESC desc = {.dwSize = sizeof(DSBUFFERDESC)};
struct render_thread_params params;
WAVEFORMATEX format;
HRESULT hr;
if (!This->synth) return DMUS_E_SYNTHNOTCONFIGURED;
@ -77,13 +171,54 @@ static HRESULT synth_sink_activate(struct synth_sink *This)
if (FAILED(hr = IReferenceClock_GetTime(This->master_clock, &This->activate_time))) return hr;
This->latency_time = This->activate_time;
if ((params.buffer = This->dsound_buffer))
IDirectMusicBuffer_AddRef(params.buffer);
else
{
synth_sink_get_format(This, &format);
desc.lpwfxFormat = (WAVEFORMATEX *)&format;
desc.dwBufferBytes = format.nAvgBytesPerSec;
if (FAILED(hr = IDirectMusicSynthSink_GetDesiredBufferSize(iface, &desc.dwBufferBytes)))
ERR("Failed to get desired buffer size, hr %#lx\n", hr);
desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;
if (FAILED(hr = IDirectSound8_CreateSoundBuffer(This->dsound, &desc, &params.buffer, NULL)))
{
ERR("Failed to create sound buffer, hr %#lx.\n", hr);
return hr;
}
}
params.sink = This;
params.synth = This->synth;
IDirectMusicSynth_AddRef(This->synth);
if (!(params.started_event = CreateEventW(NULL, FALSE, FALSE, NULL))
|| !(This->render_thread = CreateThread(NULL, 0, synth_sink_render_thread, &params, 0, NULL)))
{
ERR("Failed to create render thread, error %lu\n", GetLastError());
hr = HRESULT_FROM_WIN32(GetLastError());
IDirectSoundBuffer_Release(params.buffer);
IDirectMusicSynth_Release(params.synth);
CloseHandle(params.started_event);
return hr;
}
WaitForSingleObject(params.started_event, INFINITE);
CloseHandle(params.started_event);
This->active = TRUE;
return S_OK;
}
static HRESULT synth_sink_deactivate(struct synth_sink *This)
{
if (!This->active) return S_OK;
SetEvent(This->stop_event);
WaitForSingleObject(This->render_thread, INFINITE);
This->render_thread = NULL;
This->active = FALSE;
return S_OK;
}
@ -133,8 +268,15 @@ static ULONG WINAPI synth_sink_Release(IDirectMusicSynthSink *iface)
TRACE("(%p): new ref = %lu\n", This, ref);
if (!ref) {
if (This->active)
IDirectMusicSynthSink_Activate(iface, FALSE);
if (This->master_clock)
IReferenceClock_Release(This->master_clock);
This->cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->cs);
CloseHandle(This->stop_event);
free(This);
}
@ -238,15 +380,17 @@ static HRESULT WINAPI synth_sink_SetDirectSound(IDirectMusicSynthSink *iface,
TRACE("(%p)->(%p, %p)\n", This, dsound, dsound_buffer);
if (dsound_buffer) FIXME("Ignoring IDirectSoundBuffer parameter.\n");
if (This->active) return DMUS_E_SYNTHACTIVE;
if (This->dsound) IDirectSound_Release(This->dsound);
This->dsound = NULL;
if (This->dsound_buffer) IDirectSoundBuffer_Release(This->dsound_buffer);
This->dsound_buffer = NULL;
if (!dsound) return S_OK;
if (!This->synth) return DMUS_E_SYNTHNOTCONFIGURED;
if ((This->dsound = dsound)) IDirectSound_AddRef(This->dsound);
if ((This->dsound_buffer = dsound_buffer)) IDirectSoundBuffer_AddRef(This->dsound_buffer);
return S_OK;
}
@ -413,7 +557,10 @@ static HRESULT WINAPI latency_clock_GetTime(IReferenceClock *iface, REFERENCE_TI
if (!time) return E_INVALIDARG;
if (!This->active) return E_FAIL;
EnterCriticalSection(&This->cs);
*time = This->latency_time;
LeaveCriticalSection(&This->cs);
return S_OK;
}
@ -462,6 +609,10 @@ HRESULT synth_sink_create(IUnknown **ret_iface)
obj->IReferenceClock_iface.lpVtbl = &latency_clock_vtbl;
obj->ref = 1;
obj->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&obj->cs);
obj->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
TRACE("Created DirectMusicSynthSink %p\n", obj);
*ret_iface = (IUnknown *)&obj->IDirectMusicSynthSink_iface;
return S_OK;

View file

@ -1294,7 +1294,7 @@ static void test_IDirectMusicSynthSink(void)
hr = IDirectMusicSynthSink_Activate(sink, TRUE);
ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr);
ref = get_refcount(synth);
ok(ref == 1, "got %#lx\n", ref);
todo_wine ok(ref == 1, "got %#lx\n", ref);
hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size);
ok(hr == S_OK, "got %#lx\n", hr);
@ -1328,7 +1328,7 @@ static void test_IDirectMusicSynthSink(void)
hr = IDirectMusicSynthSink_Init(sink, NULL);
ok(hr == S_OK, "got %#lx\n", hr);
ref = get_refcount(synth);
ok(ref == 1, "got %#lx\n", ref);
todo_wine ok(ref == 1, "got %#lx\n", ref);
hr = IDirectMusicSynthSink_Activate(sink, TRUE);
ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr);