cmd: DIR command outputs free space for the path.
[wine.git] / dlls / windows.media.speech / recognizer.c
blob790d127fc6404e227abb6ce4e50894a3e175b264
1 /* WinRT Windows.Media.SpeechRecognition implementation
3 * Copyright 2022 Bernhard Kölbl
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "private.h"
22 #include "initguid.h"
23 #include "audioclient.h"
24 #include "mmdeviceapi.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(speech);
32 * ISpeechRecognitionCompilationResult
36 struct compilation_result
38 ISpeechRecognitionCompilationResult ISpeechRecognitionCompilationResult_iface;
39 LONG ref;
41 SpeechRecognitionResultStatus status;
44 static inline struct compilation_result *impl_from_ISpeechRecognitionCompilationResult( ISpeechRecognitionCompilationResult *iface )
46 return CONTAINING_RECORD(iface, struct compilation_result, ISpeechRecognitionCompilationResult_iface);
49 static HRESULT WINAPI compilation_result_QueryInterface( ISpeechRecognitionCompilationResult *iface, REFIID iid, void **out )
51 struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(iface);
53 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
55 if (IsEqualGUID(iid, &IID_IUnknown) ||
56 IsEqualGUID(iid, &IID_IInspectable) ||
57 IsEqualGUID(iid, &IID_IAgileObject) ||
58 IsEqualGUID(iid, &IID_ISpeechRecognitionCompilationResult))
60 IInspectable_AddRef((*out = &impl->ISpeechRecognitionCompilationResult_iface));
61 return S_OK;
64 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
65 *out = NULL;
66 return E_NOINTERFACE;
69 static ULONG WINAPI compilation_result_AddRef( ISpeechRecognitionCompilationResult *iface )
71 struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(iface);
72 ULONG ref = InterlockedIncrement(&impl->ref);
73 TRACE("iface %p, ref %lu.\n", iface, ref);
74 return ref;
77 static ULONG WINAPI compilation_result_Release( ISpeechRecognitionCompilationResult *iface )
79 struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(iface);
81 ULONG ref = InterlockedDecrement(&impl->ref);
82 TRACE("iface %p, ref %lu.\n", iface, ref);
84 if (!ref)
85 free(impl);
87 return ref;
90 static HRESULT WINAPI compilation_result_GetIids( ISpeechRecognitionCompilationResult *iface, ULONG *iid_count, IID **iids )
92 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);
93 return E_NOTIMPL;
96 static HRESULT WINAPI compilation_result_GetRuntimeClassName( ISpeechRecognitionCompilationResult *iface, HSTRING *class_name )
98 FIXME("iface %p, class_name %p stub!\n", iface, class_name);
99 return E_NOTIMPL;
102 static HRESULT WINAPI compilation_result_GetTrustLevel( ISpeechRecognitionCompilationResult *iface, TrustLevel *trust_level )
104 FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
105 return E_NOTIMPL;
108 static HRESULT WINAPI compilation_result_get_Status( ISpeechRecognitionCompilationResult *iface, SpeechRecognitionResultStatus *value )
110 struct compilation_result *impl = impl_from_ISpeechRecognitionCompilationResult(iface);
111 TRACE("iface %p, value %p.\n", iface, value);
112 *value = impl->status;
113 return S_OK;
116 static const struct ISpeechRecognitionCompilationResultVtbl compilation_result_vtbl =
118 /* IUnknown methods */
119 compilation_result_QueryInterface,
120 compilation_result_AddRef,
121 compilation_result_Release,
122 /* IInspectable methods */
123 compilation_result_GetIids,
124 compilation_result_GetRuntimeClassName,
125 compilation_result_GetTrustLevel,
126 /* ISpeechRecognitionCompilationResult methods */
127 compilation_result_get_Status
131 static HRESULT compilation_result_create( SpeechRecognitionResultStatus status, ISpeechRecognitionCompilationResult **out )
133 struct compilation_result *impl;
135 TRACE("out %p.\n", out);
137 if (!(impl = calloc(1, sizeof(*impl))))
139 *out = NULL;
140 return E_OUTOFMEMORY;
143 impl->ISpeechRecognitionCompilationResult_iface.lpVtbl = &compilation_result_vtbl;
144 impl->ref = 1;
145 impl->status = status;
147 *out = &impl->ISpeechRecognitionCompilationResult_iface;
148 TRACE("created %p\n", *out);
149 return S_OK;
154 * SpeechContinuousRecognitionSession
158 struct session
160 ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface;
161 LONG ref;
163 IVector_ISpeechRecognitionConstraint *constraints;
165 SpeechRecognizerState recognizer_state;
167 struct list completed_handlers;
168 struct list result_handlers;
170 IAudioClient *audio_client;
171 IAudioCaptureClient *capture_client;
172 WAVEFORMATEX capture_wfx;
174 HANDLE worker_thread, worker_control_event, audio_buf_event;
175 BOOLEAN worker_running, worker_paused;
176 CRITICAL_SECTION cs;
181 * ISpeechContinuousRecognitionSession
185 static inline struct session *impl_from_ISpeechContinuousRecognitionSession( ISpeechContinuousRecognitionSession *iface )
187 return CONTAINING_RECORD(iface, struct session, ISpeechContinuousRecognitionSession_iface);
190 static DWORD CALLBACK session_worker_thread_cb( void *args )
192 ISpeechContinuousRecognitionSession *iface = args;
193 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
194 BOOLEAN running = TRUE, paused = FALSE;
195 UINT32 frame_count, tmp_buf_size;
196 BYTE *audio_buf, *tmp_buf = NULL;
197 DWORD flags, status;
198 HANDLE events[2];
199 HRESULT hr;
201 SetThreadDescription(GetCurrentThread(), L"wine_speech_recognition_session_worker");
203 if (FAILED(hr = IAudioClient_Start(impl->audio_client)))
204 goto error;
206 if (FAILED(hr = IAudioClient_GetBufferSize(impl->audio_client, &frame_count)))
207 goto error;
209 tmp_buf_size = sizeof(*tmp_buf) * frame_count * impl->capture_wfx.nBlockAlign;
210 if (!(tmp_buf = malloc(tmp_buf_size)))
212 ERR("Memory allocation failed.\n");
213 return 1;
216 while (running)
218 BOOLEAN old_paused = paused;
219 UINT32 count = 0;
221 events[count++] = impl->worker_control_event;
222 if (!paused) events[count++] = impl->audio_buf_event;
224 status = WaitForMultipleObjects(count, events, FALSE, INFINITE);
225 if (status == 0) /* worker_control_event signaled */
227 EnterCriticalSection(&impl->cs);
228 paused = impl->worker_paused;
229 running = impl->worker_running;
230 LeaveCriticalSection(&impl->cs);
232 if (old_paused < paused)
234 if (FAILED(hr = IAudioClient_Stop(impl->audio_client))) goto error;
235 if (FAILED(hr = IAudioClient_Reset(impl->audio_client))) goto error;
236 TRACE("session worker paused.\n");
238 else if (old_paused > paused)
240 if (FAILED(hr = IAudioClient_Start(impl->audio_client))) goto error;
241 TRACE("session worker resumed.\n");
244 else if (status == 1) /* audio_buf_event signaled */
246 SIZE_T packet_size = 0, tmp_buf_offset = 0;
247 UINT32 frames_available = 0;
249 while (tmp_buf_offset < tmp_buf_size
250 && IAudioCaptureClient_GetBuffer(impl->capture_client, &audio_buf, &frames_available, &flags, NULL, NULL) == S_OK)
252 packet_size = frames_available * impl->capture_wfx.nBlockAlign;
253 if (tmp_buf_offset + packet_size > tmp_buf_size)
255 /* Defer processing until the next iteration of the worker loop. */
256 IAudioCaptureClient_ReleaseBuffer(impl->capture_client, 0);
257 SetEvent(impl->audio_buf_event);
258 break;
261 memcpy(tmp_buf + tmp_buf_offset, audio_buf, packet_size);
262 tmp_buf_offset += packet_size;
264 IAudioCaptureClient_ReleaseBuffer(impl->capture_client, frames_available);
267 /* TODO: Send mic data to recognizer and handle results. */
269 else
271 ERR("Unexpected state entered. Aborting worker.\n");
272 break;
276 if (FAILED(hr = IAudioClient_Stop(impl->audio_client)))
277 ERR("IAudioClient_Stop failed with %#lx.\n", hr);
279 if (FAILED(hr = IAudioClient_Reset(impl->audio_client)))
280 ERR("IAudioClient_Reset failed with %#lx.\n", hr);
282 free(tmp_buf);
284 return 0;
286 error:
287 ERR("The recognition session worker encountered a serious error and needs to stop. hr: %lx.\n", hr);
288 free(tmp_buf);
289 return 1;
292 static HRESULT WINAPI session_QueryInterface( ISpeechContinuousRecognitionSession *iface, REFIID iid, void **out )
294 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
296 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
298 if (IsEqualGUID(iid, &IID_IUnknown) ||
299 IsEqualGUID(iid, &IID_IInspectable) ||
300 IsEqualGUID(iid, &IID_ISpeechContinuousRecognitionSession))
302 IInspectable_AddRef((*out = &impl->ISpeechContinuousRecognitionSession_iface));
303 return S_OK;
306 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
307 *out = NULL;
308 return E_NOINTERFACE;
311 static ULONG WINAPI session_AddRef( ISpeechContinuousRecognitionSession *iface )
313 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
314 ULONG ref = InterlockedIncrement(&impl->ref);
315 TRACE("iface %p, ref %lu.\n", iface, ref);
316 return ref;
319 static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface )
321 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
322 ULONG ref = InterlockedDecrement(&impl->ref);
323 TRACE("iface %p, ref %lu.\n", iface, ref);
325 if (!ref)
327 HANDLE thread;
329 EnterCriticalSection(&impl->cs);
330 thread = impl->worker_thread;
331 impl->worker_running = FALSE;
332 impl->worker_thread = INVALID_HANDLE_VALUE;
333 LeaveCriticalSection(&impl->cs);
335 SetEvent(impl->worker_control_event);
336 WaitForSingleObject(thread, INFINITE);
337 CloseHandle(thread);
339 typed_event_handlers_clear(&impl->completed_handlers);
340 typed_event_handlers_clear(&impl->result_handlers);
342 IAudioCaptureClient_Release(impl->capture_client);
343 IAudioClient_Release(impl->audio_client);
345 impl->cs.DebugInfo->Spare[0] = 0;
346 DeleteCriticalSection(&impl->cs);
348 IVector_ISpeechRecognitionConstraint_Release(impl->constraints);
349 free(impl);
352 return ref;
355 static HRESULT WINAPI session_GetIids( ISpeechContinuousRecognitionSession *iface, ULONG *iid_count, IID **iids )
357 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);
358 return E_NOTIMPL;
361 static HRESULT WINAPI session_GetRuntimeClassName( ISpeechContinuousRecognitionSession *iface, HSTRING *class_name )
363 FIXME("iface %p, class_name %p stub!\n", iface, class_name);
364 return E_NOTIMPL;
367 static HRESULT WINAPI session_GetTrustLevel( ISpeechContinuousRecognitionSession *iface, TrustLevel *trust_level )
369 FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
370 return E_NOTIMPL;
373 static HRESULT WINAPI session_get_AutoStopSilenceTimeout( ISpeechContinuousRecognitionSession *iface, TimeSpan *value )
375 FIXME("iface %p, value %p stub!\n", iface, value);
376 return E_NOTIMPL;
379 static HRESULT WINAPI session_set_AutoStopSilenceTimeout( ISpeechContinuousRecognitionSession *iface, TimeSpan value )
381 FIXME("iface %p, value %#I64x stub!\n", iface, value.Duration);
382 return E_NOTIMPL;
385 static HRESULT session_start_async( IInspectable *invoker )
387 return S_OK;
390 static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action )
392 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
393 HRESULT hr;
395 TRACE("iface %p, action %p.\n", iface, action);
397 if (FAILED(hr = async_action_create(NULL, session_start_async, action)))
398 return hr;
400 EnterCriticalSection(&impl->cs);
401 if (impl->worker_running || impl->worker_thread)
403 hr = COR_E_INVALIDOPERATION;
405 else if (!(impl->worker_thread = CreateThread(NULL, 0, session_worker_thread_cb, impl, 0, NULL)))
407 hr = HRESULT_FROM_WIN32(GetLastError());
408 impl->worker_running = FALSE;
410 else
412 impl->worker_running = TRUE;
413 impl->recognizer_state = SpeechRecognizerState_Capturing;
415 LeaveCriticalSection(&impl->cs);
417 if (FAILED(hr))
419 IAsyncAction_Release(*action);
420 *action = NULL;
423 return hr;
426 static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSession *iface,
427 SpeechContinuousRecognitionMode mode,
428 IAsyncAction **action )
430 FIXME("iface %p, mode %u, action %p stub!\n", iface, mode, action);
431 return E_NOTIMPL;
434 static HRESULT session_stop_async( IInspectable *invoker )
436 return S_OK;
439 static HRESULT WINAPI session_StopAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action )
441 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
442 HANDLE thread;
443 HRESULT hr;
445 TRACE("iface %p, action %p.\n", iface, action);
447 if (FAILED(hr = async_action_create(NULL, session_stop_async, action)))
448 return hr;
450 EnterCriticalSection(&impl->cs);
451 if (impl->worker_running && impl->worker_thread)
453 thread = impl->worker_thread;
454 impl->worker_thread = INVALID_HANDLE_VALUE;
455 impl->worker_running = FALSE;
456 impl->worker_paused = FALSE;
457 impl->recognizer_state = SpeechRecognizerState_Idle;
459 else
461 hr = COR_E_INVALIDOPERATION;
463 LeaveCriticalSection(&impl->cs);
465 if (SUCCEEDED(hr))
467 SetEvent(impl->worker_control_event);
468 WaitForSingleObject(thread, INFINITE);
469 CloseHandle(thread);
471 EnterCriticalSection(&impl->cs);
472 impl->worker_thread = NULL;
473 LeaveCriticalSection(&impl->cs);
475 else
477 IAsyncAction_Release(*action);
478 *action = NULL;
481 return hr;
484 static HRESULT WINAPI session_CancelAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action )
486 FIXME("iface %p, action %p stub!\n", iface, action);
487 return E_NOTIMPL;
490 static HRESULT session_pause_async( IInspectable *invoker )
492 return S_OK;
495 static HRESULT WINAPI session_PauseAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action )
497 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
498 HRESULT hr = S_OK;
500 TRACE("iface %p, action %p.\n", iface, action);
502 *action = NULL;
504 if (FAILED(hr = async_action_create(NULL, session_pause_async, action)))
505 return hr;
507 EnterCriticalSection(&impl->cs);
508 if (impl->worker_running)
510 impl->worker_paused = TRUE;
511 impl->recognizer_state = SpeechRecognizerState_Paused;
513 LeaveCriticalSection(&impl->cs);
515 SetEvent(impl->worker_control_event);
517 return hr;
520 static HRESULT WINAPI session_Resume( ISpeechContinuousRecognitionSession *iface )
522 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
524 TRACE("iface %p.\n", iface);
526 EnterCriticalSection(&impl->cs);
527 if (impl->worker_running)
529 impl->worker_paused = FALSE;
530 impl->recognizer_state = SpeechRecognizerState_Capturing;
532 LeaveCriticalSection(&impl->cs);
534 SetEvent(impl->worker_control_event);
536 return S_OK;
539 static HRESULT WINAPI session_add_Completed( ISpeechContinuousRecognitionSession *iface,
540 ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionCompletedEventArgs *handler,
541 EventRegistrationToken *token )
543 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
544 TRACE("iface %p, handler %p, token %p.\n", iface, handler, token);
545 if (!handler) return E_INVALIDARG;
546 return typed_event_handlers_append(&impl->completed_handlers, (ITypedEventHandler_IInspectable_IInspectable *)handler, token);
549 static HRESULT WINAPI session_remove_Completed( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token )
551 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
552 TRACE("iface %p, token.value %#I64x.\n", iface, token.value);
553 return typed_event_handlers_remove(&impl->completed_handlers, &token);
556 static HRESULT WINAPI session_add_ResultGenerated( ISpeechContinuousRecognitionSession *iface,
557 ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs *handler,
558 EventRegistrationToken *token)
560 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
561 TRACE("iface %p, handler %p, token %p.\n", iface, handler, token);
562 if (!handler) return E_INVALIDARG;
563 return typed_event_handlers_append(&impl->result_handlers, (ITypedEventHandler_IInspectable_IInspectable *)handler, token);
566 static HRESULT WINAPI session_remove_ResultGenerated( ISpeechContinuousRecognitionSession *iface, EventRegistrationToken token )
568 struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface);
569 TRACE("iface %p, token.value %#I64x.\n", iface, token.value);
570 return typed_event_handlers_remove(&impl->result_handlers, &token);
573 static const struct ISpeechContinuousRecognitionSessionVtbl session_vtbl =
575 /* IUnknown methods */
576 session_QueryInterface,
577 session_AddRef,
578 session_Release,
579 /* IInspectable methods */
580 session_GetIids,
581 session_GetRuntimeClassName,
582 session_GetTrustLevel,
583 /* ISpeechContinuousRecognitionSession methods */
584 session_get_AutoStopSilenceTimeout,
585 session_set_AutoStopSilenceTimeout,
586 session_StartAsync,
587 session_StartWithModeAsync,
588 session_StopAsync,
589 session_CancelAsync,
590 session_PauseAsync,
591 session_Resume,
592 session_add_Completed,
593 session_remove_Completed,
594 session_add_ResultGenerated,
595 session_remove_ResultGenerated
600 * SpeechRecognizer
604 struct recognizer
606 ISpeechRecognizer ISpeechRecognizer_iface;
607 IClosable IClosable_iface;
608 ISpeechRecognizer2 ISpeechRecognizer2_iface;
609 LONG ref;
611 ISpeechContinuousRecognitionSession *session;
616 * ISpeechRecognizer
620 static inline struct recognizer *impl_from_ISpeechRecognizer( ISpeechRecognizer *iface )
622 return CONTAINING_RECORD(iface, struct recognizer, ISpeechRecognizer_iface);
625 static HRESULT WINAPI recognizer_QueryInterface( ISpeechRecognizer *iface, REFIID iid, void **out )
627 struct recognizer *impl = impl_from_ISpeechRecognizer(iface);
629 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
631 if (IsEqualGUID(iid, &IID_IUnknown) ||
632 IsEqualGUID(iid, &IID_IInspectable) ||
633 IsEqualGUID(iid, &IID_IAgileObject) ||
634 IsEqualGUID(iid, &IID_ISpeechRecognizer))
636 IInspectable_AddRef((*out = &impl->ISpeechRecognizer_iface));
637 return S_OK;
640 if (IsEqualGUID(iid, &IID_IClosable))
642 IInspectable_AddRef((*out = &impl->IClosable_iface));
643 return S_OK;
646 if (IsEqualGUID(iid, &IID_ISpeechRecognizer2))
648 IInspectable_AddRef((*out = &impl->ISpeechRecognizer2_iface));
649 return S_OK;
652 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
653 *out = NULL;
654 return E_NOINTERFACE;
657 static ULONG WINAPI recognizer_AddRef( ISpeechRecognizer *iface )
659 struct recognizer *impl = impl_from_ISpeechRecognizer(iface);
660 ULONG ref = InterlockedIncrement(&impl->ref);
661 TRACE("iface %p, ref %lu.\n", iface, ref);
662 return ref;
665 static ULONG WINAPI recognizer_Release( ISpeechRecognizer *iface )
667 struct recognizer *impl = impl_from_ISpeechRecognizer(iface);
669 ULONG ref = InterlockedDecrement(&impl->ref);
670 TRACE("iface %p, ref %lu.\n", iface, ref);
672 if (!ref)
674 ISpeechContinuousRecognitionSession_Release(impl->session);
675 free(impl);
678 return ref;
681 static HRESULT WINAPI recognizer_GetIids( ISpeechRecognizer *iface, ULONG *iid_count, IID **iids )
683 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);
684 return E_NOTIMPL;
687 static HRESULT WINAPI recognizer_GetRuntimeClassName( ISpeechRecognizer *iface, HSTRING *class_name )
689 FIXME("iface %p, class_name %p stub!\n", iface, class_name);
690 return E_NOTIMPL;
693 static HRESULT WINAPI recognizer_GetTrustLevel( ISpeechRecognizer *iface, TrustLevel *trust_level )
695 FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
696 return E_NOTIMPL;
699 static HRESULT WINAPI recognizer_get_Constraints( ISpeechRecognizer *iface, IVector_ISpeechRecognitionConstraint **vector )
701 struct recognizer *impl = impl_from_ISpeechRecognizer(iface);
702 struct session *session = impl_from_ISpeechContinuousRecognitionSession(impl->session);
704 TRACE("iface %p, operation %p.\n", iface, vector);
706 IVector_ISpeechRecognitionConstraint_AddRef((*vector = session->constraints));
707 return S_OK;
710 static HRESULT WINAPI recognizer_get_CurrentLanguage( ISpeechRecognizer *iface, ILanguage **language )
712 FIXME("iface %p, operation %p stub!\n", iface, language);
713 return E_NOTIMPL;
716 static HRESULT WINAPI recognizer_get_Timeouts( ISpeechRecognizer *iface, ISpeechRecognizerTimeouts **timeouts )
718 FIXME("iface %p, operation %p stub!\n", iface, timeouts);
719 return E_NOTIMPL;
722 static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeechRecognizerUIOptions **options )
724 FIXME("iface %p, operation %p stub!\n", iface, options);
725 return E_NOTIMPL;
728 static HRESULT recognizer_compile_constraints_async( IInspectable *invoker, IInspectable **result )
730 return compilation_result_create(SpeechRecognitionResultStatus_Success, (ISpeechRecognitionCompilationResult **) result);
733 static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *iface,
734 IAsyncOperation_SpeechRecognitionCompilationResult **operation )
736 IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation;
737 FIXME("iface %p, operation %p semi-stub!\n", iface, operation);
738 return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, NULL, recognizer_compile_constraints_async, value);
741 static HRESULT WINAPI recognizer_RecognizeAsync( ISpeechRecognizer *iface,
742 IAsyncOperation_SpeechRecognitionResult **operation )
744 FIXME("iface %p, operation %p stub!\n", iface, operation);
745 return E_NOTIMPL;
748 static HRESULT WINAPI recognizer_RecognizeWithUIAsync( ISpeechRecognizer *iface,
749 IAsyncOperation_SpeechRecognitionResult **operation )
751 FIXME("iface %p, operation %p stub!\n", iface, operation);
752 return E_NOTIMPL;
755 static HRESULT WINAPI recognizer_add_RecognitionQualityDegrading( ISpeechRecognizer *iface,
756 ITypedEventHandler_SpeechRecognizer_SpeechRecognitionQualityDegradingEventArgs *handler,
757 EventRegistrationToken *token )
759 FIXME("iface %p, operation %p, token %p, stub!\n", iface, handler, token);
760 return E_NOTIMPL;
763 static HRESULT WINAPI recognizer_remove_RecognitionQualityDegrading( ISpeechRecognizer *iface, EventRegistrationToken token )
765 FIXME("iface %p, token.value %#I64x, stub!\n", iface, token.value);
766 return E_NOTIMPL;
769 static HRESULT WINAPI recognizer_add_StateChanged( ISpeechRecognizer *iface,
770 ITypedEventHandler_SpeechRecognizer_SpeechRecognizerStateChangedEventArgs *handler,
771 EventRegistrationToken *token )
773 FIXME("iface %p, operation %p, token %p, stub!\n", iface, handler, token);
774 return E_NOTIMPL;
777 static HRESULT WINAPI recognizer_remove_StateChanged( ISpeechRecognizer *iface, EventRegistrationToken token )
779 FIXME("iface %p, token.value %#I64x, stub!\n", iface, token.value);
780 return E_NOTIMPL;
783 static const struct ISpeechRecognizerVtbl speech_recognizer_vtbl =
785 /* IUnknown methods */
786 recognizer_QueryInterface,
787 recognizer_AddRef,
788 recognizer_Release,
789 /* IInspectable methods */
790 recognizer_GetIids,
791 recognizer_GetRuntimeClassName,
792 recognizer_GetTrustLevel,
793 /* ISpeechRecognizer methods */
794 recognizer_get_CurrentLanguage,
795 recognizer_get_Constraints,
796 recognizer_get_Timeouts,
797 recognizer_get_UIOptions,
798 recognizer_CompileConstraintsAsync,
799 recognizer_RecognizeAsync,
800 recognizer_RecognizeWithUIAsync,
801 recognizer_add_RecognitionQualityDegrading,
802 recognizer_remove_RecognitionQualityDegrading,
803 recognizer_add_StateChanged,
804 recognizer_remove_StateChanged,
809 * IClosable
813 DEFINE_IINSPECTABLE(closable, IClosable, struct recognizer, ISpeechRecognizer_iface)
815 static HRESULT WINAPI closable_Close( IClosable *iface )
817 FIXME("iface %p stub.\n", iface);
818 return E_NOTIMPL;
821 static const struct IClosableVtbl closable_vtbl =
823 /* IUnknown methods */
824 closable_QueryInterface,
825 closable_AddRef,
826 closable_Release,
827 /* IInspectable methods */
828 closable_GetIids,
829 closable_GetRuntimeClassName,
830 closable_GetTrustLevel,
831 /* IClosable methods */
832 closable_Close,
837 * ISpeechRecognizer2
841 DEFINE_IINSPECTABLE(recognizer2, ISpeechRecognizer2, struct recognizer, ISpeechRecognizer_iface)
843 static HRESULT WINAPI recognizer2_get_ContinuousRecognitionSession( ISpeechRecognizer2 *iface,
844 ISpeechContinuousRecognitionSession **session )
846 struct recognizer *impl = impl_from_ISpeechRecognizer2(iface);
847 TRACE("iface %p, session %p.\n", iface, session);
848 ISpeechContinuousRecognitionSession_QueryInterface(impl->session, &IID_ISpeechContinuousRecognitionSession, (void **)session);
849 return S_OK;
852 static HRESULT WINAPI recognizer2_get_State( ISpeechRecognizer2 *iface, SpeechRecognizerState *state )
854 struct recognizer *impl = impl_from_ISpeechRecognizer2(iface);
855 struct session *session = impl_from_ISpeechContinuousRecognitionSession(impl->session);
857 FIXME("iface %p, state %p not all states are supported, yet.\n", iface, state);
859 if (!state)
860 return E_POINTER;
862 EnterCriticalSection(&session->cs);
863 *state = session->recognizer_state;
864 LeaveCriticalSection(&session->cs);
866 return S_OK;
869 static HRESULT WINAPI recognizer2_StopRecognitionAsync( ISpeechRecognizer2 *iface, IAsyncAction **action )
871 FIXME("iface %p, action %p stub!\n", iface, action);
872 return E_NOTIMPL;
875 static HRESULT WINAPI recognizer2_add_HypothesisGenerated( ISpeechRecognizer2 *iface,
876 ITypedEventHandler_SpeechRecognizer_SpeechRecognitionHypothesisGeneratedEventArgs *handler,
877 EventRegistrationToken *token )
879 FIXME("iface %p, operation %p, token %p, stub!\n", iface, handler, token);
880 return E_NOTIMPL;
883 static HRESULT WINAPI recognizer2_remove_HypothesisGenerated( ISpeechRecognizer2 *iface, EventRegistrationToken token )
885 FIXME("iface %p, token.value %#I64x, stub!\n", iface, token.value);
886 return E_NOTIMPL;
889 static const struct ISpeechRecognizer2Vtbl speech_recognizer2_vtbl =
891 /* IUnknown methods */
892 recognizer2_QueryInterface,
893 recognizer2_AddRef,
894 recognizer2_Release,
895 /* IInspectable methods */
896 recognizer2_GetIids,
897 recognizer2_GetRuntimeClassName,
898 recognizer2_GetTrustLevel,
899 /* ISpeechRecognizer2 methods */
900 recognizer2_get_ContinuousRecognitionSession,
901 recognizer2_get_State,
902 recognizer2_StopRecognitionAsync,
903 recognizer2_add_HypothesisGenerated,
904 recognizer2_remove_HypothesisGenerated,
909 * Statics for SpeechRecognizer
913 struct recognizer_statics
915 IActivationFactory IActivationFactory_iface;
916 ISpeechRecognizerFactory ISpeechRecognizerFactory_iface;
917 ISpeechRecognizerStatics ISpeechRecognizerStatics_iface;
918 ISpeechRecognizerStatics2 ISpeechRecognizerStatics2_iface;
919 LONG ref;
924 * IActivationFactory
928 static inline struct recognizer_statics *impl_from_IActivationFactory( IActivationFactory *iface )
930 return CONTAINING_RECORD(iface, struct recognizer_statics, IActivationFactory_iface);
933 static HRESULT WINAPI activation_factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
935 struct recognizer_statics *impl = impl_from_IActivationFactory(iface);
937 TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out);
939 if (IsEqualGUID(iid, &IID_IUnknown) ||
940 IsEqualGUID(iid, &IID_IInspectable) ||
941 IsEqualGUID(iid, &IID_IAgileObject) ||
942 IsEqualGUID(iid, &IID_IActivationFactory))
944 IInspectable_AddRef((*out = &impl->IActivationFactory_iface));
945 return S_OK;
948 if (IsEqualGUID(iid, &IID_ISpeechRecognizerFactory))
950 IInspectable_AddRef((*out = &impl->ISpeechRecognizerFactory_iface));
951 return S_OK;
954 if (IsEqualGUID(iid, &IID_ISpeechRecognizerStatics))
956 IInspectable_AddRef((*out = &impl->ISpeechRecognizerStatics_iface));
957 return S_OK;
960 if (IsEqualGUID(iid, &IID_ISpeechRecognizerStatics2))
962 IInspectable_AddRef((*out = &impl->ISpeechRecognizerStatics2_iface));
963 return S_OK;
966 FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
967 *out = NULL;
968 return E_NOINTERFACE;
971 static ULONG WINAPI activation_factory_AddRef( IActivationFactory *iface )
973 struct recognizer_statics *impl = impl_from_IActivationFactory(iface);
974 ULONG ref = InterlockedIncrement(&impl->ref);
975 TRACE("iface %p, ref %lu.\n", iface, ref);
976 return ref;
979 static ULONG WINAPI activation_factory_Release( IActivationFactory *iface )
981 struct recognizer_statics *impl = impl_from_IActivationFactory(iface);
982 ULONG ref = InterlockedDecrement(&impl->ref);
983 TRACE("iface %p, ref %lu.\n", iface, ref);
984 return ref;
987 static HRESULT WINAPI activation_factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids )
989 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);
990 return E_NOTIMPL;
993 static HRESULT WINAPI activation_factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
995 FIXME("iface %p, class_name %p stub!\n", iface, class_name);
996 return E_NOTIMPL;
999 static HRESULT WINAPI activation_factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
1001 FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
1002 return E_NOTIMPL;
1005 static HRESULT WINAPI activation_factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
1007 struct recognizer_statics *impl = impl_from_IActivationFactory(iface);
1008 TRACE("iface %p, instance %p.\n", iface, instance);
1009 return ISpeechRecognizerFactory_Create(&impl->ISpeechRecognizerFactory_iface, NULL, (ISpeechRecognizer **)instance);
1012 static const struct IActivationFactoryVtbl activation_factory_vtbl =
1014 /* IUnknown methods */
1015 activation_factory_QueryInterface,
1016 activation_factory_AddRef,
1017 activation_factory_Release,
1018 /* IInspectable methods */
1019 activation_factory_GetIids,
1020 activation_factory_GetRuntimeClassName,
1021 activation_factory_GetTrustLevel,
1022 /* IActivationFactory methods */
1023 activation_factory_ActivateInstance,
1028 * ISpeechRecognizerFactory
1032 DEFINE_IINSPECTABLE(recognizer_factory, ISpeechRecognizerFactory, struct recognizer_statics, IActivationFactory_iface)
1034 static HRESULT recognizer_factory_create_audio_capture(struct session *session)
1036 const REFERENCE_TIME buffer_duration = 5000000; /* 0.5 second */
1037 IMMDeviceEnumerator *mm_enum = NULL;
1038 IMMDevice *mm_device = NULL;
1039 WAVEFORMATEX wfx = { 0 };
1040 WCHAR *str = NULL;
1041 HRESULT hr = S_OK;
1043 if (!(session->audio_buf_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
1044 return HRESULT_FROM_WIN32(GetLastError());
1046 if (FAILED(hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void **)&mm_enum)))
1047 goto cleanup;
1049 if (FAILED(hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mm_enum, eCapture, eMultimedia, &mm_device)))
1050 goto cleanup;
1052 if (FAILED(hr = IMMDevice_Activate(mm_device, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&session->audio_client)))
1053 goto cleanup;
1055 hr = IMMDevice_GetId(mm_device, &str);
1056 TRACE("selected capture device ID: %s, hr %#lx\n", debugstr_w(str), hr);
1058 wfx.wFormatTag = WAVE_FORMAT_PCM;
1059 wfx.nSamplesPerSec = 16000;
1060 wfx.nChannels = 1;
1061 wfx.wBitsPerSample = 16;
1062 wfx.nBlockAlign = (wfx.wBitsPerSample + 7) / 8 * wfx.nChannels;
1063 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
1064 TRACE("wfx tag %u, channels %u, samples %lu, bits %u, align %u.\n", wfx.wFormatTag, wfx.nChannels, wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nBlockAlign);
1066 if (FAILED(hr = IAudioClient_Initialize(session->audio_client, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buffer_duration, 0, &wfx, NULL)))
1067 goto cleanup;
1069 if (FAILED(hr = IAudioClient_SetEventHandle(session->audio_client, session->audio_buf_event)))
1070 goto cleanup;
1072 hr = IAudioClient_GetService(session->audio_client, &IID_IAudioCaptureClient, (void **)&session->capture_client);
1074 session->capture_wfx = wfx;
1076 cleanup:
1077 if (mm_device) IMMDevice_Release(mm_device);
1078 if (mm_enum) IMMDeviceEnumerator_Release(mm_enum);
1079 CoTaskMemFree(str);
1080 return hr;
1083 static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface, ILanguage *language, ISpeechRecognizer **speechrecognizer )
1085 struct recognizer *impl;
1086 struct session *session;
1087 struct vector_iids constraints_iids =
1089 .iterable = &IID_IIterable_ISpeechRecognitionConstraint,
1090 .iterator = &IID_IIterator_ISpeechRecognitionConstraint,
1091 .vector = &IID_IVector_ISpeechRecognitionConstraint,
1092 .view = &IID_IVectorView_ISpeechRecognitionConstraint,
1094 HRESULT hr;
1096 TRACE("iface %p, language %p, speechrecognizer %p.\n", iface, language, speechrecognizer);
1098 *speechrecognizer = NULL;
1100 if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY;
1101 if (!(session = calloc(1, sizeof(*session))))
1103 hr = E_OUTOFMEMORY;
1104 goto error;
1107 if (language)
1108 FIXME("language parameter unused. Stub!\n");
1110 /* Init ISpeechContinuousRecognitionSession */
1111 session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl;
1112 session->ref = 1;
1114 list_init(&session->completed_handlers);
1115 list_init(&session->result_handlers);
1117 if (!(session->worker_control_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
1119 hr = HRESULT_FROM_WIN32(GetLastError());
1120 goto error;
1123 if (FAILED(hr = vector_inspectable_create(&constraints_iids, (IVector_IInspectable**)&session->constraints)))
1124 goto error;
1126 if (FAILED(hr = recognizer_factory_create_audio_capture(session)))
1127 goto error;
1129 InitializeCriticalSection(&session->cs);
1130 session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": recognition_session.cs");
1132 /* Init ISpeechRecognizer */
1133 impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl;
1134 impl->IClosable_iface.lpVtbl = &closable_vtbl;
1135 impl->ISpeechRecognizer2_iface.lpVtbl = &speech_recognizer2_vtbl;
1136 impl->session = &session->ISpeechContinuousRecognitionSession_iface;
1137 impl->ref = 1;
1139 *speechrecognizer = &impl->ISpeechRecognizer_iface;
1140 TRACE("created SpeechRecognizer %p.\n", *speechrecognizer);
1141 return S_OK;
1143 error:
1144 if (session->capture_client) IAudioCaptureClient_Release(session->capture_client);
1145 if (session->audio_client) IAudioClient_Release(session->audio_client);
1146 if (session->audio_buf_event) CloseHandle(session->audio_buf_event);
1147 if (session->constraints) IVector_ISpeechRecognitionConstraint_Release(session->constraints);
1148 if (session->worker_control_event) CloseHandle(session->worker_control_event);
1149 free(session);
1150 free(impl);
1152 return hr;
1155 static const struct ISpeechRecognizerFactoryVtbl speech_recognizer_factory_vtbl =
1157 /* IUnknown methods */
1158 recognizer_factory_QueryInterface,
1159 recognizer_factory_AddRef,
1160 recognizer_factory_Release,
1161 /* IInspectable methods */
1162 recognizer_factory_GetIids,
1163 recognizer_factory_GetRuntimeClassName,
1164 recognizer_factory_GetTrustLevel,
1165 /* ISpeechRecognizerFactory methods */
1166 recognizer_factory_Create
1171 * ISpeechRecognizerStatics
1175 DEFINE_IINSPECTABLE(statics, ISpeechRecognizerStatics, struct recognizer_statics, IActivationFactory_iface)
1177 static HRESULT WINAPI statics_get_SystemSpeechLanguage( ISpeechRecognizerStatics *iface, ILanguage **language )
1179 FIXME("iface %p, language %p stub!\n", iface, language);
1180 return E_NOTIMPL;
1183 static HRESULT WINAPI statics_get_SupportedTopicLanguages( ISpeechRecognizerStatics *iface, IVectorView_Language **languages )
1185 FIXME("iface %p, languages %p stub!\n", iface, languages);
1186 return E_NOTIMPL;
1189 static HRESULT WINAPI statics_get_SupportedGrammarLanguages( ISpeechRecognizerStatics *iface, IVectorView_Language **languages )
1191 FIXME("iface %p, languages %p stub!\n", iface, languages);
1192 return E_NOTIMPL;
1195 static const struct ISpeechRecognizerStaticsVtbl speech_recognizer_statics_vtbl =
1197 /* IUnknown methods */
1198 statics_QueryInterface,
1199 statics_AddRef,
1200 statics_Release,
1201 /* IInspectable methods */
1202 statics_GetIids,
1203 statics_GetRuntimeClassName,
1204 statics_GetTrustLevel,
1205 /* ISpeechRecognizerStatics2 methods */
1206 statics_get_SystemSpeechLanguage,
1207 statics_get_SupportedTopicLanguages,
1208 statics_get_SupportedGrammarLanguages
1213 * ISpeechRecognizerStatics2
1217 DEFINE_IINSPECTABLE(statics2, ISpeechRecognizerStatics2, struct recognizer_statics, IActivationFactory_iface)
1219 static HRESULT WINAPI statics2_TrySetSystemSpeechLanguageAsync( ISpeechRecognizerStatics2 *iface,
1220 ILanguage *language,
1221 IAsyncOperation_boolean **operation)
1223 FIXME("iface %p, operation %p stub!\n", iface, operation);
1224 return E_NOTIMPL;
1227 static const struct ISpeechRecognizerStatics2Vtbl speech_recognizer_statics2_vtbl =
1229 /* IUnknown methods */
1230 statics2_QueryInterface,
1231 statics2_AddRef,
1232 statics2_Release,
1233 /* IInspectable methods */
1234 statics2_GetIids,
1235 statics2_GetRuntimeClassName,
1236 statics2_GetTrustLevel,
1237 /* ISpeechRecognizerStatics2 methods */
1238 statics2_TrySetSystemSpeechLanguageAsync,
1241 static struct recognizer_statics recognizer_statics =
1243 .IActivationFactory_iface = {&activation_factory_vtbl},
1244 .ISpeechRecognizerFactory_iface = {&speech_recognizer_factory_vtbl},
1245 .ISpeechRecognizerStatics_iface = {&speech_recognizer_statics_vtbl},
1246 .ISpeechRecognizerStatics2_iface = {&speech_recognizer_statics2_vtbl},
1247 .ref = 1
1250 IActivationFactory *recognizer_factory = &recognizer_statics.IActivationFactory_iface;