From: Bohdan Tkachenko <bohdan@tkachenko.dev> Previously both methods returned E_NOTIMPL. Store the priority on the speech_voice struct and validate the value against SPVPRI_NORMAL, SPVPRI_ALERT and SPVPRI_OVER. This unblocks Overwatch 2's Audio Captions accessibility TTS, which calls SetPriority during voice setup and aborts on any non-S_OK result. Add tests covering priority round-trips between SPVPRI_NORMAL, SPVPRI_ALERT and SPVPRI_OVER, and verify the default is SPVPRI_NORMAL. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59749 --- dlls/sapi/tests/tts.c | 24 ++++++++++++++++++++++++ dlls/sapi/tts.c | 29 +++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 429a2541528..3e374357ab1 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -495,6 +495,7 @@ static void test_spvoice(void) LONG rate; USHORT volume; SPVOICESTATUS status; + SPVPRIORITY priority; ULONG stream_num; DWORD regid; WAVEFORMATEX wfx; @@ -663,6 +664,29 @@ static void test_spvoice(void) ok(status.ulCurrentStream == 0, "got %lu.\n", status.ulCurrentStream); ok(status.hrLastResult == S_OK, "got %#lx.\n", status.hrLastResult); + priority = 0xdead; + hr = ISpVoice_GetPriority(voice, &priority); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(priority == SPVPRI_NORMAL, "got %d.\n", priority); + + hr = ISpVoice_SetPriority(voice, SPVPRI_ALERT); + ok(hr == S_OK, "got %#lx.\n", hr); + + priority = 0xdead; + hr = ISpVoice_GetPriority(voice, &priority); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(priority == SPVPRI_ALERT, "got %d.\n", priority); + + hr = ISpVoice_SetPriority(voice, SPVPRI_OVER); + ok(hr == S_OK, "got %#lx.\n", hr); + + priority = 0xdead; + hr = ISpVoice_GetPriority(voice, &priority); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(priority == SPVPRI_OVER, "got %d.\n", priority); + + hr = ISpVoice_SetPriority(voice, SPVPRI_NORMAL); + ok(hr == S_OK, "got %#lx.\n", hr); hr = CoRegisterClassObject(&CLSID_TestEngine, (IUnknown *)&test_engine_cf, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); ok(hr == S_OK, "got %#lx.\n", hr); diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index bf6bf0e0d0b..11de8a7b2fa 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -60,6 +60,7 @@ struct speech_voice struct async_queue queue; ULONG last_stream_num; HRESULT last_hr; + SPVPRIORITY priority; CRITICAL_SECTION cs; }; @@ -1004,11 +1005,9 @@ done: ISpAudio_Release(audio); } CoTaskMemFree(wfx); - EnterCriticalSection(&This->cs); This->last_hr = hr; LeaveCriticalSection(&This->cs); - ISpTTSEngine_Release(speak_task->engine); free_frag_list(speak_task->frag_list); ISpTTSEngineSite_Release(speak_task->site); @@ -1254,16 +1253,33 @@ static HRESULT WINAPI spvoice_Skip(ISpVoice *iface, const WCHAR *type, LONG item static HRESULT WINAPI spvoice_SetPriority(ISpVoice *iface, SPVPRIORITY priority) { - FIXME("(%p, %d): stub.\n", iface, priority); + struct speech_voice *This = impl_from_ISpVoice(iface); - return E_NOTIMPL; + TRACE("(%p, %d).\n", iface, priority); + + if (priority != SPVPRI_NORMAL && priority != SPVPRI_ALERT && priority != SPVPRI_OVER) + return E_INVALIDARG; + + EnterCriticalSection(&This->cs); + This->priority = priority; + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI spvoice_GetPriority(ISpVoice *iface, SPVPRIORITY *priority) { - FIXME("(%p, %p): stub.\n", iface, priority); + struct speech_voice *This = impl_from_ISpVoice(iface); - return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, priority); + + if (!priority) return E_POINTER; + + EnterCriticalSection(&This->cs); + *priority = This->priority; + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI spvoice_SetAlertBoundary(ISpVoice *iface, SPEVENTENUM boundary) @@ -1740,6 +1756,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->rate = 0; This->last_stream_num = 0; This->last_hr = S_OK; + This->priority = SPVPRI_NORMAL; memset(&This->state, 0, sizeof(This->state)); This->state.Volume = 100; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10906