From: Bernhard Kölbl besentv@gmail.com
Signed-off-by: Bernhard Kölbl besentv@gmail.com --- dlls/windows.media.speech/recognizer.c | 148 ++++++++++++++++++++++- dlls/windows.media.speech/tests/speech.c | 7 +- 2 files changed, 149 insertions(+), 6 deletions(-)
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 958006201e5..73ce4958f90 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -160,6 +160,11 @@ struct session
struct list completed_handlers; struct list result_handlers; + + HANDLE session_thread; + HANDLE session_paused_event, session_resume_event; + BOOLEAN session_running, session_paused; + CRITICAL_SECTION cs; };
/* @@ -173,6 +178,51 @@ static inline struct session *impl_from_ISpeechContinuousRecognitionSession( ISp return CONTAINING_RECORD(iface, struct session, ISpeechContinuousRecognitionSession_iface); }
+static DWORD CALLBACK session_thread_cb( void *args ) +{ + ISpeechContinuousRecognitionSession *iface = args; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + BOOLEAN running, paused = FALSE; + + EnterCriticalSection(&impl->cs); + running = impl->session_running; + LeaveCriticalSection(&impl->cs); + + while (running) + { + EnterCriticalSection(&impl->cs); + paused = impl->session_paused; + running = impl->session_running; + LeaveCriticalSection(&impl->cs); + + /* TODO: Send mic data to recognizer. */ + + if (paused) + { + TRACE("paused!\n"); + SetEvent(impl->session_paused_event); + WaitForSingleObject(impl->session_resume_event, INFINITE); + } + + Sleep(500); /* Sleep to slow down spinning for now. */ + } + + return 0; +} + +static HRESULT WINAPI shutdown_session_thread( ISpeechContinuousRecognitionSession *iface ) +{ + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + + SetEvent(impl->session_resume_event); /* Set the resume even just in case the session was paused. */ + if (WaitForSingleObject(impl->session_thread, 1000)) + ERR("Wait for shutting down the ISpeechContinuousRecognitionSession timed out!\n"); + CloseHandle(impl->session_thread); + impl->session_thread = NULL; + + return S_OK; +} + static HRESULT WINAPI session_QueryInterface( ISpeechContinuousRecognitionSession *iface, REFIID iid, void **out ) { struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); @@ -208,8 +258,21 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface
if (!ref) { + BOOLEAN running = FALSE; + + EnterCriticalSection(&impl->cs); + running = impl->session_running; + LeaveCriticalSection(&impl->cs); + + if (running) shutdown_session_thread(iface); + typed_event_handlers_clear(&impl->completed_handlers); typed_event_handlers_clear(&impl->result_handlers); + CloseHandle(impl->session_paused_event); + CloseHandle(impl->session_resume_event); + impl->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&impl->cs); + IVector_ISpeechRecognitionConstraint_Release(impl->constraints); free(impl); } @@ -249,13 +312,31 @@ static HRESULT WINAPI session_set_AutoStopSilenceTimeout( ISpeechContinuousRecog
static HRESULT WINAPI start_callback( IInspectable *invoker ) { - return S_OK; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession((ISpeechContinuousRecognitionSession *)invoker); + HRESULT hr = S_OK; + + impl->session_running = TRUE; + impl->session_thread = CreateThread(NULL, 0, session_thread_cb, impl, 0, NULL); + + return hr; }
static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + HRESULT hr = S_OK; + FIXME("iface %p, action %p stub!\n", iface, action); - return async_action_create(NULL, start_callback, action); + + EnterCriticalSection(&impl->cs); + if (!impl->session_thread && !impl->session_running && !impl->session_paused) + { + hr = async_action_create((IInspectable *)iface, start_callback, action); + } + else hr = 0x80131509; + LeaveCriticalSection(&impl->cs); + + return hr; }
static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSession *iface, @@ -268,13 +349,28 @@ static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSe
static HRESULT WINAPI stop_callback( IInspectable *invoker ) { + shutdown_session_thread((ISpeechContinuousRecognitionSession *)invoker); return S_OK; }
static HRESULT WINAPI session_StopAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + HRESULT hr = 0x80131509; + FIXME("iface %p, action %p stub!\n", iface, action); - return async_action_create(NULL, stop_callback, action); + + EnterCriticalSection(&impl->cs); + if (impl->session_thread && impl->session_running && !impl->session_paused) + { + impl->session_running = FALSE; + LeaveCriticalSection(&impl->cs); + + hr = async_action_create((IInspectable *)iface, stop_callback, action); + } + else LeaveCriticalSection(&impl->cs); + + return hr; }
static HRESULT WINAPI session_CancelAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) @@ -285,19 +381,51 @@ static HRESULT WINAPI session_CancelAsync( ISpeechContinuousRecognitionSession *
static HRESULT WINAPI pause_callback( IInspectable *invoker ) { + struct session *impl = impl_from_ISpeechContinuousRecognitionSession((ISpeechContinuousRecognitionSession *)invoker); + + WaitForSingleObject(impl->session_paused_event, INFINITE); return S_OK; }
static HRESULT WINAPI session_PauseAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + HRESULT hr = 0x80131509; + FIXME("iface %p, action %p stub!\n", iface, action); - return async_action_create(NULL, pause_callback, action); + + EnterCriticalSection(&impl->cs); + if (impl->session_thread && impl->session_running && !impl->session_paused) + { + impl->session_paused = TRUE; + LeaveCriticalSection(&impl->cs); + + hr = async_action_create((IInspectable *)iface, pause_callback, action); + } + else LeaveCriticalSection(&impl->cs); + + return hr; }
static HRESULT WINAPI session_Resume( ISpeechContinuousRecognitionSession *iface ) { + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + HRESULT hr = 0x80131509; + FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + + EnterCriticalSection(&impl->cs); + if (impl->session_thread && impl->session_running && impl->session_paused) + { + impl->session_paused = FALSE; + LeaveCriticalSection(&impl->cs); + + SetEvent(impl->session_resume_event); + hr = S_OK; + } + else LeaveCriticalSection(&impl->cs); + + return hr; }
static HRESULT WINAPI session_add_Completed( ISpeechContinuousRecognitionSession *iface, @@ -814,10 +942,17 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface /* Init ISpeechContinuousRecognitionSession */ session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl; session->ref = 1; + session->session_paused_event = CreateEventW(NULL, FALSE, FALSE, NULL); + session->session_resume_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (FAILED(hr = HRESULT_FROM_WIN32(GetLastError())) || !session->session_paused_event || !session->session_resume_event) + goto error;
list_init(&session->completed_handlers); list_init(&session->result_handlers);
+ InitializeCriticalSection(&session->cs); + session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": recognition_session.cs"); + if (FAILED(hr = vector_inspectable_create(&constraints_iids, (IVector_IInspectable**)&session->constraints))) goto error;
@@ -835,6 +970,9 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface
error: if (session->constraints) IVector_ISpeechRecognitionConstraint_Release(session->constraints); + CloseHandle(session->session_resume_event); + CloseHandle(session->session_paused_event); + DeleteCriticalSection(&session->cs); free(session); free(impl);
diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index ca1f464c1be..d211ffda0f2 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1741,6 +1741,11 @@ static void test_Recognition(void)
await_async_void(action, &action_handler);
+ action2 = (void *)0xdeadbeef; + hr = ISpeechContinuousRecognitionSession_StartAsync(session, &action2); + ok(hr == 0x80131509, "ISpeechContinuousRecognitionSession_StartAsync failed, hr %#lx.\n", hr); + ok(action2 == NULL, "action2 was %p.\n", action2); + hr = IAsyncAction_QueryInterface(action, &IID_IAsyncInfo, (void **)&info); ok(hr == S_OK, "IAsyncAction_QueryInterface failed, hr %#lx.\n", hr); check_async_info((IInspectable *)action, 1, Completed, S_OK); @@ -1785,7 +1790,7 @@ static void test_Recognition(void) broken(recog_state == SpeechRecognizerState_Capturing) , "recog_state was %u.\n", recog_state);
hr = ISpeechContinuousRecognitionSession_Resume(session); - todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr);
recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state);