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
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
;
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
));
64 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
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
);
96 static HRESULT WINAPI
compilation_result_GetRuntimeClassName( ISpeechRecognitionCompilationResult
*iface
, HSTRING
*class_name
)
98 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
102 static HRESULT WINAPI
compilation_result_GetTrustLevel( ISpeechRecognitionCompilationResult
*iface
, TrustLevel
*trust_level
)
104 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
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
;
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
))))
140 return E_OUTOFMEMORY
;
143 impl
->ISpeechRecognitionCompilationResult_iface
.lpVtbl
= &compilation_result_vtbl
;
145 impl
->status
= status
;
147 *out
= &impl
->ISpeechRecognitionCompilationResult_iface
;
148 TRACE("created %p\n", *out
);
154 * SpeechContinuousRecognitionSession
160 ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface
;
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
;
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
;
201 SetThreadDescription(GetCurrentThread(), L
"wine_speech_recognition_session_worker");
203 if (FAILED(hr
= IAudioClient_Start(impl
->audio_client
)))
206 if (FAILED(hr
= IAudioClient_GetBufferSize(impl
->audio_client
, &frame_count
)))
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");
218 BOOLEAN old_paused
= paused
;
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
);
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. */
271 ERR("Unexpected state entered. Aborting worker.\n");
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
);
287 ERR("The recognition session worker encountered a serious error and needs to stop. hr: %lx.\n", hr
);
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
));
306 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
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
);
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
);
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
);
361 static HRESULT WINAPI
session_GetRuntimeClassName( ISpeechContinuousRecognitionSession
*iface
, HSTRING
*class_name
)
363 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
367 static HRESULT WINAPI
session_GetTrustLevel( ISpeechContinuousRecognitionSession
*iface
, TrustLevel
*trust_level
)
369 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
373 static HRESULT WINAPI
session_get_AutoStopSilenceTimeout( ISpeechContinuousRecognitionSession
*iface
, TimeSpan
*value
)
375 FIXME("iface %p, value %p stub!\n", iface
, value
);
379 static HRESULT WINAPI
session_set_AutoStopSilenceTimeout( ISpeechContinuousRecognitionSession
*iface
, TimeSpan value
)
381 FIXME("iface %p, value %#I64x stub!\n", iface
, value
.Duration
);
385 static HRESULT
session_start_async( IInspectable
*invoker
)
390 static HRESULT WINAPI
session_StartAsync( ISpeechContinuousRecognitionSession
*iface
, IAsyncAction
**action
)
392 struct session
*impl
= impl_from_ISpeechContinuousRecognitionSession(iface
);
395 TRACE("iface %p, action %p.\n", iface
, action
);
397 if (FAILED(hr
= async_action_create(NULL
, session_start_async
, action
)))
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
;
412 impl
->worker_running
= TRUE
;
413 impl
->recognizer_state
= SpeechRecognizerState_Capturing
;
415 LeaveCriticalSection(&impl
->cs
);
419 IAsyncAction_Release(*action
);
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
);
434 static HRESULT
session_stop_async( IInspectable
*invoker
)
439 static HRESULT WINAPI
session_StopAsync( ISpeechContinuousRecognitionSession
*iface
, IAsyncAction
**action
)
441 struct session
*impl
= impl_from_ISpeechContinuousRecognitionSession(iface
);
445 TRACE("iface %p, action %p.\n", iface
, action
);
447 if (FAILED(hr
= async_action_create(NULL
, session_stop_async
, action
)))
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
;
461 hr
= COR_E_INVALIDOPERATION
;
463 LeaveCriticalSection(&impl
->cs
);
467 SetEvent(impl
->worker_control_event
);
468 WaitForSingleObject(thread
, INFINITE
);
471 EnterCriticalSection(&impl
->cs
);
472 impl
->worker_thread
= NULL
;
473 LeaveCriticalSection(&impl
->cs
);
477 IAsyncAction_Release(*action
);
484 static HRESULT WINAPI
session_CancelAsync( ISpeechContinuousRecognitionSession
*iface
, IAsyncAction
**action
)
486 FIXME("iface %p, action %p stub!\n", iface
, action
);
490 static HRESULT
session_pause_async( IInspectable
*invoker
)
495 static HRESULT WINAPI
session_PauseAsync( ISpeechContinuousRecognitionSession
*iface
, IAsyncAction
**action
)
497 struct session
*impl
= impl_from_ISpeechContinuousRecognitionSession(iface
);
500 TRACE("iface %p, action %p.\n", iface
, action
);
504 if (FAILED(hr
= async_action_create(NULL
, session_pause_async
, action
)))
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
);
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
);
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
,
579 /* IInspectable methods */
581 session_GetRuntimeClassName
,
582 session_GetTrustLevel
,
583 /* ISpeechContinuousRecognitionSession methods */
584 session_get_AutoStopSilenceTimeout
,
585 session_set_AutoStopSilenceTimeout
,
587 session_StartWithModeAsync
,
592 session_add_Completed
,
593 session_remove_Completed
,
594 session_add_ResultGenerated
,
595 session_remove_ResultGenerated
606 ISpeechRecognizer ISpeechRecognizer_iface
;
607 IClosable IClosable_iface
;
608 ISpeechRecognizer2 ISpeechRecognizer2_iface
;
611 ISpeechContinuousRecognitionSession
*session
;
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
));
640 if (IsEqualGUID(iid
, &IID_IClosable
))
642 IInspectable_AddRef((*out
= &impl
->IClosable_iface
));
646 if (IsEqualGUID(iid
, &IID_ISpeechRecognizer2
))
648 IInspectable_AddRef((*out
= &impl
->ISpeechRecognizer2_iface
));
652 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
674 ISpeechContinuousRecognitionSession_Release(impl
->session
);
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
);
687 static HRESULT WINAPI
recognizer_GetRuntimeClassName( ISpeechRecognizer
*iface
, HSTRING
*class_name
)
689 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
693 static HRESULT WINAPI
recognizer_GetTrustLevel( ISpeechRecognizer
*iface
, TrustLevel
*trust_level
)
695 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
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
));
710 static HRESULT WINAPI
recognizer_get_CurrentLanguage( ISpeechRecognizer
*iface
, ILanguage
**language
)
712 FIXME("iface %p, operation %p stub!\n", iface
, language
);
716 static HRESULT WINAPI
recognizer_get_Timeouts( ISpeechRecognizer
*iface
, ISpeechRecognizerTimeouts
**timeouts
)
718 FIXME("iface %p, operation %p stub!\n", iface
, timeouts
);
722 static HRESULT WINAPI
recognizer_get_UIOptions( ISpeechRecognizer
*iface
, ISpeechRecognizerUIOptions
**options
)
724 FIXME("iface %p, operation %p stub!\n", iface
, options
);
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
);
748 static HRESULT WINAPI
recognizer_RecognizeWithUIAsync( ISpeechRecognizer
*iface
,
749 IAsyncOperation_SpeechRecognitionResult
**operation
)
751 FIXME("iface %p, operation %p stub!\n", iface
, operation
);
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
);
763 static HRESULT WINAPI
recognizer_remove_RecognitionQualityDegrading( ISpeechRecognizer
*iface
, EventRegistrationToken token
)
765 FIXME("iface %p, token.value %#I64x, stub!\n", iface
, token
.value
);
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
);
777 static HRESULT WINAPI
recognizer_remove_StateChanged( ISpeechRecognizer
*iface
, EventRegistrationToken token
)
779 FIXME("iface %p, token.value %#I64x, stub!\n", iface
, token
.value
);
783 static const struct ISpeechRecognizerVtbl speech_recognizer_vtbl
=
785 /* IUnknown methods */
786 recognizer_QueryInterface
,
789 /* IInspectable methods */
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
,
813 DEFINE_IINSPECTABLE(closable
, IClosable
, struct recognizer
, ISpeechRecognizer_iface
)
815 static HRESULT WINAPI
closable_Close( IClosable
*iface
)
817 FIXME("iface %p stub.\n", iface
);
821 static const struct IClosableVtbl closable_vtbl
=
823 /* IUnknown methods */
824 closable_QueryInterface
,
827 /* IInspectable methods */
829 closable_GetRuntimeClassName
,
830 closable_GetTrustLevel
,
831 /* IClosable methods */
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
);
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
);
862 EnterCriticalSection(&session
->cs
);
863 *state
= session
->recognizer_state
;
864 LeaveCriticalSection(&session
->cs
);
869 static HRESULT WINAPI
recognizer2_StopRecognitionAsync( ISpeechRecognizer2
*iface
, IAsyncAction
**action
)
871 FIXME("iface %p, action %p stub!\n", iface
, action
);
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
);
883 static HRESULT WINAPI
recognizer2_remove_HypothesisGenerated( ISpeechRecognizer2
*iface
, EventRegistrationToken token
)
885 FIXME("iface %p, token.value %#I64x, stub!\n", iface
, token
.value
);
889 static const struct ISpeechRecognizer2Vtbl speech_recognizer2_vtbl
=
891 /* IUnknown methods */
892 recognizer2_QueryInterface
,
895 /* IInspectable methods */
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
;
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
));
948 if (IsEqualGUID(iid
, &IID_ISpeechRecognizerFactory
))
950 IInspectable_AddRef((*out
= &impl
->ISpeechRecognizerFactory_iface
));
954 if (IsEqualGUID(iid
, &IID_ISpeechRecognizerStatics
))
956 IInspectable_AddRef((*out
= &impl
->ISpeechRecognizerStatics_iface
));
960 if (IsEqualGUID(iid
, &IID_ISpeechRecognizerStatics2
))
962 IInspectable_AddRef((*out
= &impl
->ISpeechRecognizerStatics2_iface
));
966 FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
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
);
993 static HRESULT WINAPI
activation_factory_GetRuntimeClassName( IActivationFactory
*iface
, HSTRING
*class_name
)
995 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
999 static HRESULT WINAPI
activation_factory_GetTrustLevel( IActivationFactory
*iface
, TrustLevel
*trust_level
)
1001 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
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 };
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
)))
1049 if (FAILED(hr
= IMMDeviceEnumerator_GetDefaultAudioEndpoint(mm_enum
, eCapture
, eMultimedia
, &mm_device
)))
1052 if (FAILED(hr
= IMMDevice_Activate(mm_device
, &IID_IAudioClient
, CLSCTX_INPROC_SERVER
, NULL
, (void **)&session
->audio_client
)))
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;
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
)))
1069 if (FAILED(hr
= IAudioClient_SetEventHandle(session
->audio_client
, session
->audio_buf_event
)))
1072 hr
= IAudioClient_GetService(session
->audio_client
, &IID_IAudioCaptureClient
, (void **)&session
->capture_client
);
1074 session
->capture_wfx
= wfx
;
1077 if (mm_device
) IMMDevice_Release(mm_device
);
1078 if (mm_enum
) IMMDeviceEnumerator_Release(mm_enum
);
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
,
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
))))
1108 FIXME("language parameter unused. Stub!\n");
1110 /* Init ISpeechContinuousRecognitionSession */
1111 session
->ISpeechContinuousRecognitionSession_iface
.lpVtbl
= &session_vtbl
;
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());
1123 if (FAILED(hr
= vector_inspectable_create(&constraints_iids
, (IVector_IInspectable
**)&session
->constraints
)))
1126 if (FAILED(hr
= recognizer_factory_create_audio_capture(session
)))
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
;
1139 *speechrecognizer
= &impl
->ISpeechRecognizer_iface
;
1140 TRACE("created SpeechRecognizer %p.\n", *speechrecognizer
);
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
);
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
);
1183 static HRESULT WINAPI
statics_get_SupportedTopicLanguages( ISpeechRecognizerStatics
*iface
, IVectorView_Language
**languages
)
1185 FIXME("iface %p, languages %p stub!\n", iface
, languages
);
1189 static HRESULT WINAPI
statics_get_SupportedGrammarLanguages( ISpeechRecognizerStatics
*iface
, IVectorView_Language
**languages
)
1191 FIXME("iface %p, languages %p stub!\n", iface
, languages
);
1195 static const struct ISpeechRecognizerStaticsVtbl speech_recognizer_statics_vtbl
=
1197 /* IUnknown methods */
1198 statics_QueryInterface
,
1201 /* IInspectable methods */
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
);
1227 static const struct ISpeechRecognizerStatics2Vtbl speech_recognizer_statics2_vtbl
=
1229 /* IUnknown methods */
1230 statics2_QueryInterface
,
1233 /* IInspectable methods */
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
},
1250 IActivationFactory
*recognizer_factory
= &recognizer_statics
.IActivationFactory_iface
;