From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/tts.c | 28 +++++++++++++++++++++ dlls/sapi/tts.c | 58 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 4 deletions(-)
diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 7e13abf7a0d..225b1d8d172 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -97,6 +97,9 @@ static void test_spvoice(void) { ISpVoice *voice; ISpMMSysAudio *audio_out; + ISpObjectTokenCategory *token_cat; + ISpObjectToken *token; + WCHAR *token_id = NULL, *default_token_id = NULL; HRESULT hr;
hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, @@ -113,6 +116,31 @@ static void test_spvoice(void) hr = ISpVoice_SetOutput(voice, (IUnknown *)audio_out, TRUE); todo_wine ok(hr == S_FALSE, "got %#lx.\n", hr);
+ hr = ISpVoice_SetVoice(voice, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpVoice_GetVoice(voice, &token); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpObjectToken_GetId(token, &token_id); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenCategory, (void **)&token_cat); + ok(hr == S_OK, "Failed to create SpObjectTokenCategory: %#lx.\n", hr); + + hr = ISpObjectTokenCategory_SetId(token_cat, SPCAT_VOICES, FALSE); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = ISpObjectTokenCategory_GetDefaultTokenId(token_cat, &default_token_id); + ok(hr == S_OK, "got %#lx.\n", hr); + + ok(!wcscmp(token_id, default_token_id), "token_id != default_token_id\n"); + + CoTaskMemFree(token_id); + CoTaskMemFree(default_token_id); + ISpObjectToken_Release(token); + ISpObjectTokenCategory_Release(token_cat); + ISpVoice_Release(voice); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index bebda86f09d..95bbb755668 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -42,6 +42,7 @@ struct speech_voice LONG ref;
ISpStreamFormat *output; + ISpTTSEngine *engine; CRITICAL_SECTION cs; };
@@ -106,6 +107,7 @@ static ULONG WINAPI speech_voice_Release(ISpeechVoice *iface) if (!ref) { if (This->output) ISpStreamFormat_Release(This->output); + if (This->engine) ISpTTSEngine_Release(This->engine); DeleteCriticalSection(&This->cs);
heap_free(This); @@ -598,16 +600,63 @@ static HRESULT WINAPI spvoice_Resume(ISpVoice *iface)
static HRESULT WINAPI spvoice_SetVoice(ISpVoice *iface, ISpObjectToken *token) { - FIXME("(%p, %p): stub.\n", iface, token); + struct speech_voice *This = impl_from_ISpVoice(iface); + ISpTTSEngine *engine; + HRESULT hr;
- return E_NOTIMPL; + + TRACE("(%p, %p).\n", iface, token); + + if (!token) + { + if (FAILED(hr = create_default_token(SPCAT_VOICES, &token))) + return hr; + } + + 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) + ISpTTSEngine_Release(This->engine); + This->engine = engine; + + LeaveCriticalSection(&This->cs); + + return S_OK; }
static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token) { - FIXME("(%p, %p): stub.\n", iface, token); + struct speech_voice *This = impl_from_ISpVoice(iface); + ISpObjectWithToken *engine_token_iface; + HRESULT hr; + + TRACE("(%p, %p).\n", iface, token); + + if (!token) + return E_POINTER; + + EnterCriticalSection(&This->cs); + + if (!This->engine) + { + 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); + } + + LeaveCriticalSection(&This->cs);
- return token_create(NULL, &IID_ISpObjectToken, (void **)token); + return hr; }
static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *number) @@ -845,6 +894,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->ref = 1;
This->output = NULL; + This->engine = NULL;
InitializeCriticalSection(&This->cs);