Module: wine Branch: master Commit: 0d56c54d8b5d754ab71576232b04df39b5e46414 URL: https://gitlab.winehq.org/wine/wine/-/commit/0d56c54d8b5d754ab71576232b04df3...
Author: Rémi Bernon rbernon@codeweavers.com Date: Tue Sep 5 13:43:07 2023 +0200
dmsynth: Create a render thread on sink activation.
---
dlls/dmsynth/synthsink.c | 153 ++++++++++++++++++++++++++++++++++++++++++- dlls/dmsynth/tests/dmsynth.c | 4 +- 2 files changed, 154 insertions(+), 3 deletions(-)
diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 28cee0c3a28..fb7ea5fd283 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -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 **)¬ify))) + 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, ¶ms.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, ¶ms, 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; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 25ecff97048..6529bdeac34 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -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);