Commit ee8c8f65 authored by Shaun Ren's avatar Shaun Ren Committed by Alexandre Julliard

sapi: Implement ISpTTSEngineSite::GetActions/Rate/Volume.

parent 0d09ab37
...@@ -112,6 +112,8 @@ struct test_engine ...@@ -112,6 +112,8 @@ struct test_engine
DWORD flags; DWORD flags;
GUID fmtid; GUID fmtid;
SPVTEXTFRAG *frag_list; SPVTEXTFRAG *frag_list;
LONG rate;
USHORT volume;
}; };
static void copy_frag_list(const SPVTEXTFRAG *frag_list, SPVTEXTFRAG **ret_frag_list) static void copy_frag_list(const SPVTEXTFRAG *frag_list, SPVTEXTFRAG **ret_frag_list)
...@@ -154,6 +156,8 @@ static void reset_engine_params(struct test_engine *engine) ...@@ -154,6 +156,8 @@ static void reset_engine_params(struct test_engine *engine)
engine->speak_called = FALSE; engine->speak_called = FALSE;
engine->flags = 0xdeadbeef; engine->flags = 0xdeadbeef;
memset(&engine->fmtid, 0xde, sizeof(engine->fmtid)); memset(&engine->fmtid, 0xde, sizeof(engine->fmtid));
engine->rate = 0xdeadbeef;
engine->volume = 0xbeef;
for (frag = engine->frag_list; frag; frag = next) for (frag = engine->frag_list; frag; frag = next)
{ {
...@@ -206,6 +210,7 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI ...@@ -206,6 +210,7 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI
ISpTTSEngineSite *site) ISpTTSEngineSite *site)
{ {
struct test_engine *engine = impl_from_ISpTTSEngine(iface); struct test_engine *engine = impl_from_ISpTTSEngine(iface);
DWORD actions;
char *buf; char *buf;
int i; int i;
HRESULT hr; HRESULT hr;
...@@ -215,11 +220,26 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI ...@@ -215,11 +220,26 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI
copy_frag_list(frag_list, &engine->frag_list); copy_frag_list(frag_list, &engine->frag_list);
engine->speak_called = TRUE; engine->speak_called = TRUE;
actions = ISpTTSEngineSite_GetActions(site);
ok(actions == (SPVES_CONTINUE | SPVES_RATE | SPVES_VOLUME), "got %#lx.\n", actions);
hr = ISpTTSEngineSite_GetRate(site, &engine->rate);
ok(hr == S_OK, "got %#lx.\n", hr);
actions = ISpTTSEngineSite_GetActions(site);
ok(actions == (SPVES_CONTINUE | SPVES_VOLUME), "got %#lx.\n", actions);
hr = ISpTTSEngineSite_GetVolume(site, &engine->volume);
ok(hr == S_OK, "got %#lx.\n", hr);
actions = ISpTTSEngineSite_GetActions(site);
ok(actions == SPVES_CONTINUE, "got %#lx.\n", actions);
buf = calloc(1, 22050 * 2 / 5); buf = calloc(1, 22050 * 2 / 5);
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
{ {
if (ISpTTSEngineSite_GetActions(site) & SPVES_ABORT)
break;
hr = ISpTTSEngineSite_Write(site, buf, 22050 * 2 / 5, NULL); hr = ISpTTSEngineSite_Write(site, buf, 22050 * 2 / 5, NULL);
ok(hr == S_OK, "got %#lx.\n", hr); ok(hr == S_OK || hr == SP_AUDIO_STOPPED, "got %#lx.\n", hr);
Sleep(100); Sleep(100);
} }
free(buf); free(buf);
...@@ -507,7 +527,10 @@ static void test_spvoice(void) ...@@ -507,7 +527,10 @@ static void test_spvoice(void)
ok(hr == S_OK, "got %#lx.\n", hr); ok(hr == S_OK, "got %#lx.\n", hr);
ok(stream_num == 0xdeadbeef, "got %lu.\n", stream_num); ok(stream_num == 0xdeadbeef, "got %lu.\n", stream_num);
test_engine.speak_called = FALSE; ISpVoice_SetRate(voice, 0);
ISpVoice_SetVolume(voice, 100);
reset_engine_params(&test_engine);
stream_num = 0xdeadbeef; stream_num = 0xdeadbeef;
start = GetTickCount(); start = GetTickCount();
hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT, &stream_num); hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT, &stream_num);
...@@ -520,6 +543,8 @@ static void test_spvoice(void) ...@@ -520,6 +543,8 @@ static void test_spvoice(void)
ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen); ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen);
ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)), ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)),
"got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart)); "got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart));
ok(test_engine.rate == 0, "got %ld.\n", test_engine.rate);
ok(test_engine.volume == 100, "got %d.\n", test_engine.volume);
ok(stream_num == 1, "got %lu.\n", stream_num); ok(stream_num == 1, "got %lu.\n", stream_num);
ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration);
...@@ -540,6 +565,21 @@ static void test_spvoice(void) ...@@ -540,6 +565,21 @@ static void test_spvoice(void)
ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen); ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen);
ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)), ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)),
"got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart)); "got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart));
ok(test_engine.rate == 0, "got %ld.\n", test_engine.rate);
ok(test_engine.volume == 100, "got %d.\n", test_engine.volume);
Sleep(2000);
reset_engine_params(&test_engine);
hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT | SPF_ASYNC, NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
Sleep(200);
start = GetTickCount();
hr = ISpVoice_Speak(voice, NULL, SPF_PURGEBEFORESPEAK, NULL);
duration = GetTickCount() - start;
ok(hr == S_OK, "got %#lx.\n", hr);
ok(duration < 300, "took %lu ms.\n", duration);
done: done:
reset_engine_params(&test_engine); reset_engine_params(&test_engine);
......
...@@ -45,6 +45,7 @@ struct speech_voice ...@@ -45,6 +45,7 @@ struct speech_voice
ISpStreamFormat *output; ISpStreamFormat *output;
ISpTTSEngine *engine; ISpTTSEngine *engine;
LONG cur_stream_num; LONG cur_stream_num;
DWORD actions;
USHORT volume; USHORT volume;
LONG rate; LONG rate;
struct async_queue queue; struct async_queue queue;
...@@ -777,6 +778,13 @@ static void speak_proc(struct async_task *task) ...@@ -777,6 +778,13 @@ static void speak_proc(struct async_task *task)
EnterCriticalSection(&This->cs); EnterCriticalSection(&This->cs);
if (This->actions & SPVES_ABORT)
{
LeaveCriticalSection(&This->cs);
hr = S_OK;
goto done;
}
if (FAILED(hr = set_output_format(This->output, This->engine, &fmtid, &wfx))) if (FAILED(hr = set_output_format(This->output, This->engine, &fmtid, &wfx)))
{ {
LeaveCriticalSection(&This->cs); LeaveCriticalSection(&This->cs);
...@@ -789,6 +797,8 @@ static void speak_proc(struct async_task *task) ...@@ -789,6 +797,8 @@ static void speak_proc(struct async_task *task)
if (SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio))) if (SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio)))
ISpAudio_SetState(audio, SPAS_RUN, 0); ISpAudio_SetState(audio, SPAS_RUN, 0);
This->actions = SPVES_RATE | SPVES_VOLUME;
LeaveCriticalSection(&This->cs); LeaveCriticalSection(&This->cs);
hr = ISpTTSEngine_Speak(engine, speak_task->flags, &fmtid, wfx, speak_task->frag_list, speak_task->site); hr = ISpTTSEngine_Speak(engine, speak_task->flags, &fmtid, wfx, speak_task->frag_list, speak_task->site);
...@@ -847,6 +857,7 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR ...@@ -847,6 +857,7 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR
EnterCriticalSection(&This->cs); EnterCriticalSection(&This->cs);
This->actions = SPVES_ABORT;
if (This->output && SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio))) if (This->output && SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio)))
{ {
ISpAudio_SetState(audio, SPAS_CLOSED, 0); ISpAudio_SetState(audio, SPAS_CLOSED, 0);
...@@ -857,6 +868,10 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR ...@@ -857,6 +868,10 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR
async_empty_queue(&This->queue); async_empty_queue(&This->queue);
EnterCriticalSection(&This->cs);
This->actions = SPVES_CONTINUE;
LeaveCriticalSection(&This->cs);
if (!contents || !*contents) if (!contents || !*contents)
return S_OK; return S_OK;
} }
...@@ -1007,6 +1022,7 @@ static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG rate) ...@@ -1007,6 +1022,7 @@ static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG rate)
EnterCriticalSection(&This->cs); EnterCriticalSection(&This->cs);
This->rate = rate; This->rate = rate;
This->actions |= SPVES_RATE;
LeaveCriticalSection(&This->cs); LeaveCriticalSection(&This->cs);
return S_OK; return S_OK;
...@@ -1036,6 +1052,7 @@ static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume) ...@@ -1036,6 +1052,7 @@ static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume)
EnterCriticalSection(&This->cs); EnterCriticalSection(&This->cs);
This->volume = volume; This->volume = volume;
This->actions |= SPVES_VOLUME;
LeaveCriticalSection(&This->cs); LeaveCriticalSection(&This->cs);
return S_OK; return S_OK;
...@@ -1205,9 +1222,16 @@ static HRESULT WINAPI ttsenginesite_GetEventInterest(ISpTTSEngineSite *iface, UL ...@@ -1205,9 +1222,16 @@ static HRESULT WINAPI ttsenginesite_GetEventInterest(ISpTTSEngineSite *iface, UL
static DWORD WINAPI ttsenginesite_GetActions(ISpTTSEngineSite *iface) static DWORD WINAPI ttsenginesite_GetActions(ISpTTSEngineSite *iface)
{ {
FIXME("(%p): stub.\n", iface); struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface);
DWORD actions;
TRACE("(%p).\n", iface);
EnterCriticalSection(&This->voice->cs);
actions = This->voice->actions;
LeaveCriticalSection(&This->voice->cs);
return SPVES_CONTINUE; return actions;
} }
static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *buf, ULONG cb, ULONG *cb_written) static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *buf, ULONG cb, ULONG *cb_written)
...@@ -1224,16 +1248,30 @@ static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *b ...@@ -1224,16 +1248,30 @@ static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *b
static HRESULT WINAPI ttsenginesite_GetRate(ISpTTSEngineSite *iface, LONG *rate) static HRESULT WINAPI ttsenginesite_GetRate(ISpTTSEngineSite *iface, LONG *rate)
{ {
FIXME("(%p, %p): stub.\n", iface, rate); struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface);
return E_NOTIMPL; TRACE("(%p, %p).\n", iface, rate);
EnterCriticalSection(&This->voice->cs);
*rate = This->voice->rate;
This->voice->actions &= ~SPVES_RATE;
LeaveCriticalSection(&This->voice->cs);
return S_OK;
} }
static HRESULT WINAPI ttsenginesite_GetVolume(ISpTTSEngineSite *iface, USHORT *volume) static HRESULT WINAPI ttsenginesite_GetVolume(ISpTTSEngineSite *iface, USHORT *volume)
{ {
FIXME("(%p, %p): stub.\n", iface, volume); struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface);
return E_NOTIMPL; TRACE("(%p, %p).\n", iface, volume);
EnterCriticalSection(&This->voice->cs);
*volume = This->voice->volume;
This->voice->actions &= ~SPVES_VOLUME;
LeaveCriticalSection(&This->voice->cs);
return S_OK;
} }
static HRESULT WINAPI ttsenginesite_GetSkipInfo(ISpTTSEngineSite *iface, SPVSKIPTYPE *type, LONG *skip_count) static HRESULT WINAPI ttsenginesite_GetSkipInfo(ISpTTSEngineSite *iface, SPVSKIPTYPE *type, LONG *skip_count)
...@@ -1351,6 +1389,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) ...@@ -1351,6 +1389,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj)
This->output = NULL; This->output = NULL;
This->engine = NULL; This->engine = NULL;
This->cur_stream_num = 0; This->cur_stream_num = 0;
This->actions = SPVES_CONTINUE;
This->volume = 100; This->volume = 100;
This->rate = 0; This->rate = 0;
memset(&This->queue, 0, sizeof(This->queue)); memset(&This->queue, 0, sizeof(This->queue));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment