Instead of creating the TTS voice engine directly in SetVoice, we save the specified voice token, and only create them in speak_proc when necessary.
From: Shaun Ren sren@codeweavers.com
Instead of creating the TTS voice engine directly in SetVoice, we save the specified voice token, and only create them in speak_proc when necessary. --- dlls/sapi/tts.c | 53 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 17 deletions(-)
diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 410a57b4bfc..a3149562f1e 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -43,6 +43,7 @@ struct speech_voice LONG ref;
ISpStreamFormat *output; + ISpObjectToken *engine_token; ISpTTSEngine *engine; LONG cur_stream_num; DWORD actions; @@ -163,6 +164,7 @@ static ULONG WINAPI speech_voice_Release(ISpeechVoice *iface) { async_cancel_queue(&This->queue); if (This->output) ISpStreamFormat_Release(This->output); + if (This->engine_token) ISpObjectToken_Release(This->engine_token); if (This->engine) ISpTTSEngine_Release(This->engine); DeleteCriticalSection(&This->cs);
@@ -660,7 +662,7 @@ static HRESULT WINAPI spvoice_Resume(ISpVoice *iface) static HRESULT WINAPI spvoice_SetVoice(ISpVoice *iface, ISpObjectToken *token) { struct speech_voice *This = impl_from_ISpVoice(iface); - ISpTTSEngine *engine; + WCHAR *id = NULL, *old_id = NULL; HRESULT hr;
TRACE("(%p, %p).\n", iface, token); @@ -673,26 +675,37 @@ static HRESULT WINAPI spvoice_SetVoice(ISpVoice *iface, ISpObjectToken *token) else ISpObjectToken_AddRef(token);
- hr = ISpObjectToken_CreateInstance(token, NULL, CLSCTX_ALL, &IID_ISpTTSEngine, (void **)&engine); - ISpObjectToken_Release(token); - if (FAILED(hr)) - return hr; - EnterCriticalSection(&This->cs);
+ if (This->engine_token && + SUCCEEDED(ISpObjectToken_GetId(token, &id)) && + SUCCEEDED(ISpObjectToken_GetId(This->engine_token, &old_id)) && + !wcscmp(id, old_id)) + { + ISpObjectToken_Release(token); + goto done; + } + + if (This->engine_token) + ISpObjectToken_Release(This->engine_token); + This->engine_token = token; + if (This->engine) + { ISpTTSEngine_Release(This->engine); - This->engine = engine; + This->engine = NULL; + }
+done: LeaveCriticalSection(&This->cs); - + CoTaskMemFree(id); + CoTaskMemFree(old_id); return S_OK; }
static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token) { struct speech_voice *This = impl_from_ISpVoice(iface); - ISpObjectWithToken *engine_token_iface; HRESULT hr;
TRACE("(%p, %p).\n", iface, token); @@ -702,17 +715,14 @@ static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token)
EnterCriticalSection(&This->cs);
- if (!This->engine) + if (!This->engine_token) { LeaveCriticalSection(&This->cs); return create_default_token(SPCAT_VOICES, token); }
- if (SUCCEEDED(hr = ISpTTSEngine_QueryInterface(This->engine, &IID_ISpObjectWithToken, (void **)&engine_token_iface))) - { - hr = ISpObjectWithToken_GetObjectToken(engine_token_iface, token); - ISpObjectWithToken_Release(engine_token_iface); - } + ISpObjectToken_AddRef(This->engine_token); + *token = This->engine_token;
LeaveCriticalSection(&This->cs);
@@ -788,6 +798,14 @@ static void speak_proc(struct async_task *task) goto done; }
+ if (!This->engine && + FAILED(hr = ISpObjectToken_CreateInstance(This->engine_token, NULL, CLSCTX_ALL, &IID_ISpTTSEngine, (void **)&This->engine))) + { + LeaveCriticalSection(&This->cs); + ERR("failed creating engine: %#lx.\n", hr); + goto done; + } + if (FAILED(hr = set_output_format(This->output, This->engine, &fmtid, &wfx))) { LeaveCriticalSection(&This->cs); @@ -891,9 +909,9 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR return hr; }
- if (!This->engine) + if (!This->engine_token) { - /* Create a new engine with the default voice. */ + /* Set the engine token to default. */ if (FAILED(hr = ISpVoice_SetVoice(iface, NULL))) return hr; } @@ -1397,6 +1415,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->ref = 1;
This->output = NULL; + This->engine_token = NULL; This->engine = NULL; This->cur_stream_num = 0; This->actions = SPVES_CONTINUE;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=142338
Your paranoid android.
=== debian11 (32 bit report) ===
sapi: tts.c:622: Test failed: got 0x80040154. tts.c:623: Test failed: ISpTTSEngine::Speak was not called. tts.c:624: Test failed: got 0xdeadbeef. tts.c:625: Test failed: frag_list is NULL. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0040ba27).
=== debian11b (64 bit WoW report) ===
mf: Unhandled exception: divide by zero in 64-bit code (0x0000000042e22c).
sapi: tts.c:622: Test failed: got 0x80040154. tts.c:623: Test failed: ISpTTSEngine::Speak was not called. tts.c:624: Test failed: got 0xdeadbeef. tts.c:625: Test failed: frag_list is NULL. Unhandled exception: page fault on read access to 0x0000000000000000 in 64-bit code (0x0000000040a90f).