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

This commit is contained in:
Shaun Ren 2023-07-13 19:51:36 -04:00 committed by Alexandre Julliard
parent 0d09ab378e
commit ee8c8f6533
2 changed files with 87 additions and 8 deletions

View file

@ -112,6 +112,8 @@ struct test_engine
DWORD flags;
GUID fmtid;
SPVTEXTFRAG *frag_list;
LONG rate;
USHORT volume;
};
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)
engine->speak_called = FALSE;
engine->flags = 0xdeadbeef;
memset(&engine->fmtid, 0xde, sizeof(engine->fmtid));
engine->rate = 0xdeadbeef;
engine->volume = 0xbeef;
for (frag = engine->frag_list; frag; frag = next)
{
@ -206,6 +210,7 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI
ISpTTSEngineSite *site)
{
struct test_engine *engine = impl_from_ISpTTSEngine(iface);
DWORD actions;
char *buf;
int i;
HRESULT hr;
@ -215,11 +220,26 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI
copy_frag_list(frag_list, &engine->frag_list);
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);
for (i = 0; i < 5; i++)
{
if (ISpTTSEngineSite_GetActions(site) & SPVES_ABORT)
break;
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);
}
free(buf);
@ -507,7 +527,10 @@ static void test_spvoice(void)
ok(hr == S_OK, "got %#lx.\n", hr);
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;
start = GetTickCount();
hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT, &stream_num);
@ -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(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)),
"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(duration > 800 && duration < 3000, "took %lu ms.\n", duration);
@ -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(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)),
"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:
reset_engine_params(&test_engine);

View file

@ -45,6 +45,7 @@ struct speech_voice
ISpStreamFormat *output;
ISpTTSEngine *engine;
LONG cur_stream_num;
DWORD actions;
USHORT volume;
LONG rate;
struct async_queue queue;
@ -777,6 +778,13 @@ static void speak_proc(struct async_task *task)
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)))
{
LeaveCriticalSection(&This->cs);
@ -789,6 +797,8 @@ static void speak_proc(struct async_task *task)
if (SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio)))
ISpAudio_SetState(audio, SPAS_RUN, 0);
This->actions = SPVES_RATE | SPVES_VOLUME;
LeaveCriticalSection(&This->cs);
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
EnterCriticalSection(&This->cs);
This->actions = SPVES_ABORT;
if (This->output && SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio)))
{
ISpAudio_SetState(audio, SPAS_CLOSED, 0);
@ -857,6 +868,10 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR
async_empty_queue(&This->queue);
EnterCriticalSection(&This->cs);
This->actions = SPVES_CONTINUE;
LeaveCriticalSection(&This->cs);
if (!contents || !*contents)
return S_OK;
}
@ -1007,6 +1022,7 @@ static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG rate)
EnterCriticalSection(&This->cs);
This->rate = rate;
This->actions |= SPVES_RATE;
LeaveCriticalSection(&This->cs);
return S_OK;
@ -1036,6 +1052,7 @@ static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume)
EnterCriticalSection(&This->cs);
This->volume = volume;
This->actions |= SPVES_VOLUME;
LeaveCriticalSection(&This->cs);
return S_OK;
@ -1205,9 +1222,16 @@ static HRESULT WINAPI ttsenginesite_GetEventInterest(ISpTTSEngineSite *iface, UL
static DWORD WINAPI ttsenginesite_GetActions(ISpTTSEngineSite *iface)
{
FIXME("(%p): stub.\n", iface);
struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface);
DWORD actions;
return SPVES_CONTINUE;
TRACE("(%p).\n", iface);
EnterCriticalSection(&This->voice->cs);
actions = This->voice->actions;
LeaveCriticalSection(&This->voice->cs);
return actions;
}
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
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)
{
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)
@ -1351,6 +1389,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj)
This->output = NULL;
This->engine = NULL;
This->cur_stream_num = 0;
This->actions = SPVES_CONTINUE;
This->volume = 100;
This->rate = 0;
memset(&This->queue, 0, sizeof(This->queue));