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;