From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/tts.c | 25 +++++++++++++++++++ dlls/sapi/tts.c | 56 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 8303dfc6ebc..7e13abf7a0d 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -93,9 +93,34 @@ static void test_interfaces(void) ISpeechVoice_Release(speech_voice); }
+static void test_spvoice(void) +{ + ISpVoice *voice; + ISpMMSysAudio *audio_out; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpVoice, (void **)&voice); + ok(hr == S_OK, "Failed to create SpVoice: %#lx.\n", hr); + + hr = ISpVoice_SetOutput(voice, NULL, TRUE); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpMMSysAudio, (void **)&audio_out); + ok(hr == S_OK, "Failed to create SpMMAudioOut: %#lx.\n", hr); + + hr = ISpVoice_SetOutput(voice, (IUnknown *)audio_out, TRUE); + todo_wine ok(hr == S_FALSE, "got %#lx.\n", hr); + + ISpVoice_Release(voice); + ISpMMSysAudio_Release(audio_out); +} + START_TEST(tts) { CoInitialize(NULL); test_interfaces(); + test_spvoice(); CoUninitialize(); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 9f60c70e6c4..d080d65c732 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -40,6 +40,9 @@ struct speech_voice ISpVoice ISpVoice_iface; IConnectionPointContainer IConnectionPointContainer_iface; LONG ref; + + ISpStreamFormat *output; + CRITICAL_SECTION cs; };
static inline struct speech_voice *impl_from_ISpeechVoice(ISpeechVoice *iface) @@ -102,6 +105,9 @@ static ULONG WINAPI speech_voice_Release(ISpeechVoice *iface)
if (!ref) { + if (This->output) ISpStreamFormat_Release(This->output); + DeleteCriticalSection(&This->cs); + heap_free(This); }
@@ -515,11 +521,51 @@ static HRESULT WINAPI spvoice_GetInfo(ISpVoice *iface, SPEVENTSOURCEINFO *info) return E_NOTIMPL; }
-static HRESULT WINAPI spvoice_SetOutput(ISpVoice *iface, IUnknown *unk, BOOL changes) +static HRESULT WINAPI spvoice_SetOutput(ISpVoice *iface, IUnknown *unk, BOOL allow_format_changes) { - FIXME("(%p, %p, %d): stub.\n", iface, unk, changes); + struct speech_voice *This = impl_from_ISpVoice(iface); + ISpStreamFormat *stream = NULL; + ISpObjectToken *token = NULL; + HRESULT hr;
- return E_NOTIMPL; + TRACE("(%p, %p, %d).\n", iface, unk, allow_format_changes); + + if (!allow_format_changes) + FIXME("ignoring allow_format_changes = FALSE.\n"); + + if (!unk) + { + /* TODO: Create the default SpAudioOut token here once SpMMAudioEnum is implemented. */ + if (FAILED(hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpStreamFormat, (void **)&stream))) + return hr; + } + else + { + if (FAILED(hr = IUnknown_QueryInterface(unk, &IID_ISpStreamFormat, (void **)&stream))) + { + if (FAILED(hr = IUnknown_QueryInterface(unk, &IID_ISpObjectToken, (void **)&token))) + return E_INVALIDARG; + } + } + + if (!stream) + { + hr = ISpObjectToken_CreateInstance(token, NULL, CLSCTX_ALL, &IID_ISpStreamFormat, (void **)&stream); + ISpObjectToken_Release(token); + if (FAILED(hr)) + return hr; + } + + EnterCriticalSection(&This->cs); + + if (This->output) + ISpStreamFormat_Release(This->output); + This->output = stream; + + LeaveCriticalSection(&This->cs); + + return S_OK; }
static HRESULT WINAPI spvoice_GetOutputObjectToken(ISpVoice *iface, ISpObjectToken **token) @@ -798,6 +844,10 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->IConnectionPointContainer_iface.lpVtbl = &container_vtbl; This->ref = 1;
+ This->output = NULL; + + InitializeCriticalSection(&This->cs); + hr = ISpeechVoice_QueryInterface(&This->ISpeechVoice_iface, iid, obj);
ISpeechVoice_Release(&This->ISpeechVoice_iface);
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 d080d65c732..96fe7264577 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);
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/tts.c | 30 ++++++++++++++++++++++++++++++ dlls/sapi/tts.c | 26 ++++++++++++++++++++------ 2 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 225b1d8d172..4b58fbe7480 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -100,6 +100,7 @@ static void test_spvoice(void) ISpObjectTokenCategory *token_cat; ISpObjectToken *token; WCHAR *token_id = NULL, *default_token_id = NULL; + LONG rate; HRESULT hr;
hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, @@ -141,6 +142,35 @@ static void test_spvoice(void) ISpObjectToken_Release(token); ISpObjectTokenCategory_Release(token_cat);
+ rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == 0, "rate = %ld\n", rate); + + hr = ISpVoice_SetRate(voice, 1); + ok(hr == S_OK, "got %#lx.\n", hr); + + rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == 1, "rate = %ld\n", rate); + + hr = ISpVoice_SetRate(voice, -1000); + ok(hr == S_OK, "got %#lx.\n", hr); + + rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == -1000, "rate = %ld\n", rate); + + hr = ISpVoice_SetRate(voice, 1000); + ok(hr == S_OK, "got %#lx.\n", hr); + + rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == 1000, "rate = %ld\n", rate); + ISpVoice_Release(voice); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 96fe7264577..bd22f8beb88 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -43,6 +43,7 @@ struct speech_voice
ISpStreamFormat *output; ISpTTSEngine *engine; + LONG rate; CRITICAL_SECTION cs; };
@@ -715,18 +716,30 @@ static HRESULT WINAPI spvoice_GetAlertBoundary(ISpVoice *iface, SPEVENTENUM *bou return E_NOTIMPL; }
-static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG adjust) +static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG rate) { - FIXME("(%p, %ld): stub.\n", iface, adjust); + struct speech_voice *This = impl_from_ISpVoice(iface);
- return E_NOTIMPL; + TRACE("(%p, %ld).\n", iface, rate); + + EnterCriticalSection(&This->cs); + This->rate = rate; + LeaveCriticalSection(&This->cs); + + return S_OK; }
-static HRESULT WINAPI spvoice_GetRate(ISpVoice *iface, LONG *adjust) +static HRESULT WINAPI spvoice_GetRate(ISpVoice *iface, LONG *rate) { - FIXME("(%p, %p): stub.\n", iface, adjust); + struct speech_voice *This = impl_from_ISpVoice(iface);
- return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, rate); + + EnterCriticalSection(&This->cs); + *rate = This->rate; + LeaveCriticalSection(&This->cs); + + return S_OK; }
static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume) @@ -895,6 +908,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj)
This->output = NULL; This->engine = NULL; + This->rate = 0;
InitializeCriticalSection(&This->cs);
From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/tts.c | 25 +++++++++++++++++++++++++ dlls/sapi/tts.c | 25 +++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 4b58fbe7480..23523474a3b 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -101,6 +101,7 @@ static void test_spvoice(void) ISpObjectToken *token; WCHAR *token_id = NULL, *default_token_id = NULL; LONG rate; + USHORT volume; HRESULT hr;
hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, @@ -171,6 +172,30 @@ static void test_spvoice(void) ok(hr == S_OK, "got %#lx.\n", hr); ok(rate == 1000, "rate = %ld\n", rate);
+ volume = 0xbeef; + hr = ISpVoice_GetVolume(voice, &volume); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(volume == 100, "volume = %d\n", volume); + + hr = ISpVoice_SetVolume(voice, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + volume = 0xbeef; + hr = ISpVoice_GetVolume(voice, &volume); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(volume == 0, "volume = %d\n", volume); + + hr = ISpVoice_SetVolume(voice, 100); + ok(hr == S_OK, "got %#lx.\n", hr); + + volume = 0xbeef; + hr = ISpVoice_GetVolume(voice, &volume); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(volume == 100, "volume = %d\n", volume); + + hr = ISpVoice_SetVolume(voice, 101); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + ISpVoice_Release(voice); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index bd22f8beb88..0f86d234e88 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -43,6 +43,7 @@ struct speech_voice
ISpStreamFormat *output; ISpTTSEngine *engine; + USHORT volume; LONG rate; CRITICAL_SECTION cs; }; @@ -744,16 +745,31 @@ static HRESULT WINAPI spvoice_GetRate(ISpVoice *iface, LONG *rate)
static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume) { - FIXME("(%p, %d): stub.\n", iface, volume); + struct speech_voice *This = impl_from_ISpVoice(iface);
- return E_NOTIMPL; + TRACE("(%p, %d).\n", iface, volume); + + if (volume > 100) + return E_INVALIDARG; + + EnterCriticalSection(&This->cs); + This->volume = volume; + LeaveCriticalSection(&This->cs); + + return S_OK; }
static HRESULT WINAPI spvoice_GetVolume(ISpVoice *iface, USHORT *volume) { - FIXME("(%p, %p): stub.\n", iface, volume); + struct speech_voice *This = impl_from_ISpVoice(iface);
- return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, volume); + + EnterCriticalSection(&This->cs); + *volume = This->volume; + LeaveCriticalSection(&This->cs); + + return S_OK; }
static HRESULT WINAPI spvoice_WaitUntilDone(ISpVoice *iface, ULONG timeout) @@ -908,6 +924,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj)
This->output = NULL; This->engine = NULL; + This->volume = 100; This->rate = 0;
InitializeCriticalSection(&This->cs);
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 full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=134011
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
sapi: tts.c:112: Test failed: got 0x8004503a. tts.c:119: Test failed: got 0x80045007.
=== debian11 (build log) ===
/home/winetest/tools/testbot/var/wine-win32/../wine/dlls/sapi/tts.c:614: undefined reference to `create_default_token' /home/winetest/tools/testbot/var/wine-win32/../wine/dlls/sapi/tts.c:650: undefined reference to `create_default_token' collect2: error: ld returned 1 exit status Task: The win32 Wine build failed
=== debian11b (build log) ===
/home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/sapi/tts.c:614: undefined reference to `create_default_token' /home/winetest/tools/testbot/var/wine-wow64/../wine/dlls/sapi/tts.c:650: undefined reference to `create_default_token' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed
This merge request was closed by Shaun Ren.