2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using static Interop.VoiceControl;
21 using static Interop.VoiceControlCommand;
23 namespace Tizen.Uix.VoiceControl
26 /// Enumeration for the error values that can occur.
28 /// <since_tizen> 3 </since_tizen>
32 /// Successful, no error.
44 /// Invalid parameter.
48 /// No answer from the STT service.
52 /// Device or resource busy.
56 /// Permission denied.
72 /// No available engine.
80 /// Operation rejected.
96 /// Progress to ready is not finished.
100 /// Progress to recording is not finished.
102 InProgressToRecording,
104 /// Progress to processing is not finished.
106 InProgressToProcessing
110 /// Enumeration for the client state.
112 /// <since_tizen> 3 </since_tizen>
120 /// 'Initialized' state.
128 /// The state cannot be determined.
134 /// Enumeration for the service state.
136 /// <since_tizen> 3 </since_tizen>
137 public enum ServiceState
148 /// 'Recording' state.
152 /// 'Processing' state.
156 /// The state cannot be determined.
162 /// Enumeration for the result event.
164 /// <since_tizen> 3 </since_tizen>
165 public enum ResultEvent
178 /// Enumeration for the command type.
180 /// <since_tizen> 3 </since_tizen>
181 public enum CommandType
184 /// Foreground command by the client.
188 /// Background command by the client.
192 /// The undefined command.
198 /// A main function of the voice control API registers the command and gets a notification for the recognition result.
199 /// Applications can add their own commands and provide results when their command is recognized by the user voice input.
201 /// <since_tizen> 3 </since_tizen>
202 public static class VoiceControlClient
204 private static event EventHandler<RecognitionResultEventArgs> _recognitionResult;
205 private static event EventHandler<StateChangedEventArgs> _stateChanged;
206 private static event EventHandler<ServiceStateChangedEventArgs> _serviceStateChanged;
207 private static event EventHandler<ErrorOccuredEventArgs> _errorOccured;
208 private static event EventHandler<CurrentLanguageChangedEventArgs> _currentLanguageChanged;
209 private static VcResultCb s_resultDelegate;
210 private static VcStateChangedCb s_stateDelegate;
211 private static VcServiceStateChangedCb s_serviceStateDelegate;
212 private static VcErrorCb s_errorDelegate;
213 private static VcCurrentLanguageChangedCb s_languageDelegate;
214 private static List<string> s_supportedLanguages;
215 private static VcSupportedLanguageCb s_supportedLanguagesCb;
216 private static VcResultCb s_resultCb;
217 private static RecognitionResult s_recognitionResult;
220 /// Gets the current language.
221 /// A language is specified as an ISO 3166 alpha-2 two letter country-code
222 /// followed by ISO 639-1 for the two-letter language code.
223 /// For example, "ko_KR" for Korean, "en_US" for American English.
224 /// An empty string is returned in case of some internal error.
226 /// <since_tizen> 3 </since_tizen>
228 /// The current language in voice control.
231 /// http://tizen.org/privilege/recorder
234 /// The state must be initialized or ready.
236 public static string CurrentLanguage
240 string currentLanguage;
242 ErrorCode error = VcGetCurrentLanguage(out currentLanguage);
243 if (error != ErrorCode.None)
245 Log.Error(LogTag, "CurrentLanguage Failed with error " + error);
249 return currentLanguage;
254 /// Gets the current state of the voice control client.
256 /// <since_tizen> 3 </since_tizen>
258 /// The current state of the voice control client.
261 /// http://tizen.org/privilege/recorder
264 /// The state must be initialized or ready.
266 public static State State
272 ErrorCode error = VcGetState(out state);
273 if (error != ErrorCode.None)
275 Log.Error(LogTag, "State Failed with error " + error);
276 return State.Unavailable;
284 /// Gets the current state of the voice control service.
286 /// <since_tizen> 3 </since_tizen>
288 /// The current state of the voice control service.
291 /// http://tizen.org/privilege/recorder
294 /// The state must be ready.
296 public static ServiceState ServiceState
302 ErrorCode error = VcGetServiceState(out state);
303 if (error != ErrorCode.None)
305 Log.Error(LogTag, "ServiceState Failed with error " + error);
306 return ServiceState.Unavailable;
314 /// Sets the invocation name.
316 /// <since_tizen> 3 </since_tizen>
318 /// http://tizen.org/privilege/recorder
324 /// http://tizen.org/feature/speech.control
325 /// http://tizen.org/feature/microphone
328 /// The invocation name is used to activate background commands. The invocation name can be same as the application name or any other phrase.
329 /// For example, an application "Tizen Sample" has a background command, "Play music", and the invocation name of the application is set to "Tizen Sample".
330 /// In order to activate the background command, users can say "Tizen Sample, Play music". The invocation name is dependent on the current language.
331 /// For example, if the current language is "en_US"(English), the invocation name is also "en_US".
332 /// If the current language is "ja_JP"(Japanese) and the invocation name is "en_US", the invocation name will not be recognized.
333 /// This function should be called before the SetCommandList().
335 /// <param name="name">Invocation name to be invoked by an application.</param>
336 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
337 /// <exception cref="ArgumentException">This exception can be due to an invalid parameter.</exception>
338 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
339 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
341 /// The state must be ready.
343 public static void SetInvocationName(string name)
345 ErrorCode error = VcSetInvocationName(name);
346 if (error != ErrorCode.None)
348 Log.Error(LogTag, "SetInvocationName Failed with error " + error);
349 throw ExceptionFactory.CreateException(error);
354 /// Initializes the voice control.
356 /// <since_tizen> 3 </since_tizen>
358 /// http://tizen.org/privilege/recorder
364 /// http://tizen.org/feature/speech.control
365 /// http://tizen.org/feature/microphone
367 /// <exception cref="InvalidOperationException">This exception can be due to operation failed.</exception>
368 /// <exception cref="OutOfMemoryException">This exception can be due to out Of memory.</exception>
369 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
370 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
372 /// The state will be initialized.
374 public static void Initialize()
376 ErrorCode error = VcInitialize();
377 if (error != ErrorCode.None)
379 Log.Error(LogTag, "Initialize Failed with error " + error);
380 throw ExceptionFactory.CreateException(error);
385 /// Deinitializes the voice control.
387 /// <since_tizen> 3 </since_tizen>
389 /// http://tizen.org/privilege/recorder
395 /// http://tizen.org/feature/speech.control
396 /// http://tizen.org/feature/microphone
398 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
399 /// <exception cref="InvalidOperationException">This exception can be due to operation failed.</exception>
400 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
401 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
402 public static void Deinitialize()
404 ErrorCode error = VcDeinitialize();
405 if (error != ErrorCode.None)
407 Log.Error(LogTag, "Deinitialize Failed with error " + error);
408 throw ExceptionFactory.CreateException(error);
413 /// Connects the voice control service.
415 /// <since_tizen> 3 </since_tizen>
417 /// http://tizen.org/privilege/recorder
423 /// http://tizen.org/feature/speech.control
424 /// http://tizen.org/feature/microphone
426 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
427 /// <exception cref="InvalidOperationException">This exception can be due to operation failed.</exception>
428 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
429 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
431 /// The state must be initialized.
434 /// The state must be ready.
436 public static void Prepare()
438 ErrorCode error = VcPrepare();
439 if (error != ErrorCode.None)
441 Log.Error(LogTag, "Prepare Failed with error " + error);
442 throw ExceptionFactory.CreateException(error);
447 /// Disconnects the voice control service.
449 /// <since_tizen> 3 </since_tizen>
451 /// http://tizen.org/privilege/recorder
457 /// http://tizen.org/feature/speech.control
458 /// http://tizen.org/feature/microphone
460 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
461 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
462 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
464 /// The state must be ready.
467 /// The state must be initialized.
469 public static void Unprepare()
471 ErrorCode error = VcUnprepare();
472 if (error != ErrorCode.None)
474 Log.Error(LogTag, "Unprepare Failed with error " + error);
475 throw ExceptionFactory.CreateException(error);
480 /// Retrieves all the supported languages.
481 /// A language is specified as an ISO 3166 alpha-2 two letter country-code
482 /// followed by ISO 639-1 for the two-letter language code.
483 /// For example, "ko_KR" for Korean, "en_US" for American English.
485 /// <since_tizen> 3 </since_tizen>
487 /// http://tizen.org/privilege/recorder
493 /// http://tizen.org/feature/speech.control
494 /// http://tizen.org/feature/microphone
496 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
497 /// <exception cref="InvalidOperationException">This exception can be due to operation failed.</exception>
498 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
499 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
501 /// The state must be ready or initialized.
503 public static IEnumerable<string> GetSupportedLanguages()
505 s_supportedLanguages = new List<string>();
506 s_supportedLanguagesCb = (IntPtr language, IntPtr userData) =>
508 string languageStr = Marshal.PtrToStringAnsi(language);
509 s_supportedLanguages.Add(languageStr);
512 ErrorCode error = VcForeachSupportedLanguages(s_supportedLanguagesCb, IntPtr.Zero);
513 if (error != ErrorCode.None)
515 Log.Error(LogTag, "GetSupportedLanguages Failed with error " + error);
516 throw ExceptionFactory.CreateException(error);
519 return s_supportedLanguages;
523 /// Gets the system command list.
525 /// <since_tizen> 3 </since_tizen>
527 /// The command list, else null in case of no system commands.
530 /// http://tizen.org/privilege/recorder
536 /// http://tizen.org/feature/speech.control
537 /// http://tizen.org/feature/microphone
540 /// In the system command list, there are system commands predefined by product manufacturers.
541 /// Those commands have the highest priority. Therefore, the user cannot set any commands similar to system commands.
543 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
544 /// <exception cref="InvalidOperationException">This exception can be due to operation failed.</exception>
545 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
546 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
548 /// The state must be ready.
550 public static VoiceCommandList GetSystemCommandList()
552 IntPtr handle = IntPtr.Zero;
553 ErrorCode error = VcGetSystemCommandList(out handle);
554 if (error != ErrorCode.None)
556 Log.Error(LogTag, "GetSystemCommandList Failed with error " + error);
557 throw ExceptionFactory.CreateException(error);
560 if (handle == IntPtr.Zero)
562 Log.Error(LogTag, "GetSystemCommandList handle is null");
566 SafeCommandListHandle list = new SafeCommandListHandle(handle);
567 return new VoiceCommandList(list);
571 /// Requests to start the dialogue.
572 /// By using this function, the developer can start requesting the dialogue to the framework.
573 /// When the developer requests the dialogue, two types of texts, dispText and uttText can be sent by this function. dispText is a text for displaying and uttText is that for uttering.
574 /// For example, if dispText is "October 10th" and uttText is "Today is October 10th.", "October 10th" will be displayed on the screen and "Today is October 10th." will be spoken.
575 /// Also, the developer can set whether the dialogue starts automatically or not, using autoStart.
576 /// If the developer sets autoStart as True, the framework will start to record the next speech and continue the dialogue.
578 /// <since_tizen> 3 </since_tizen>
580 /// http://tizen.org/privilege/recorder
586 /// http://tizen.org/feature/speech.control
587 /// http://tizen.org/feature/microphone
590 /// If autoStart is True, the recognition will start again. In this case, it can be restarted up to 4 times.
592 /// <param name="dispText">Text to be displayed on the screen.</param>
593 /// <param name="uttText">Text to be spoken.</param>
594 /// <param name="autoStart">A variable for setting whether the dialog session will be restarted automatically or not.</param>
595 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
596 /// <exception cref="ArgumentException">This exception can be due to an invalid parameter.</exception>
597 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
598 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
600 /// The state must be ready.
602 public static void RequestDialog(string dispText, string uttText, bool autoStart)
604 ErrorCode error = VcRequestDialog(dispText, uttText, autoStart);
605 if (error != ErrorCode.None)
607 Log.Error(LogTag, "RequestDialog Failed with error " + error);
608 throw ExceptionFactory.CreateException(error);
613 /// Sets the command list.
615 /// <since_tizen> 3 </since_tizen>
617 /// http://tizen.org/privilege/recorder
623 /// http://tizen.org/feature/speech.control
624 /// http://tizen.org/feature/microphone
627 /// The command type is valid for CommandType 'Foreground' or 'Background'.
628 /// The matched commands of the command list should be set and they should include type and command text at least.
630 /// <param name="list">Command list</param>
631 /// <param name="type">Command type</param>
632 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
633 /// <exception cref="ArgumentException">This exception can be due to an invalid parameter.</exception>
634 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
635 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
637 /// The state must be ready.
639 public static void SetCommandList(VoiceCommandList list, CommandType type)
641 if ((type == CommandType.Foreground) || (type == CommandType.Background))
643 ErrorCode error = VcSetCommandList(list._handle, (VoiceCommandType)type);
644 if (error != ErrorCode.None)
646 Log.Error(LogTag, "SetCommandList Failed with error " + error);
647 throw ExceptionFactory.CreateException(error);
653 throw ExceptionFactory.CreateException(ErrorCode.InvalidParameter);
658 /// Unsets the command list.
660 /// <since_tizen> 3 </since_tizen>
662 /// http://tizen.org/privilege/recorder
668 /// http://tizen.org/feature/speech.control
669 /// http://tizen.org/feature/microphone
671 /// <param name="type">Command type</param>
672 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
673 /// <exception cref="ArgumentException">This exception can be due to an invalid parameter.</exception>
674 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
675 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
677 /// The state should be ready.
679 public static void UnsetCommandList(CommandType type)
681 if ((type == CommandType.Foreground) || (type == CommandType.Background))
683 VoiceCommandType commandType = VoiceCommandType.Foreground;
684 if (type == CommandType.Background)
685 commandType = VoiceCommandType.BackGround;
686 ErrorCode error = VcUnsetCommandList(commandType);
687 if (error != ErrorCode.None)
689 Log.Error(LogTag, "UnsetCommandList Failed with error " + error);
690 throw ExceptionFactory.CreateException(error);
696 throw ExceptionFactory.CreateException(ErrorCode.InvalidParameter);
701 /// Gets the recognition result.
703 /// <since_tizen> 3 </since_tizen>
705 /// http://tizen.org/privilege/recorder
711 /// http://tizen.org/feature/speech.control
712 /// http://tizen.org/feature/microphone
714 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
715 /// <exception cref="ArgumentException">This exception can be due to an invalid parameter.</exception>
716 /// <exception cref="NotSupportedException">This exception can be due to not supported.</exception>
717 /// <returns>The recognition result if possible, else a null object.</returns>
719 /// The state must be ready.
721 public static RecognitionResult GetResult()
723 s_recognitionResult = null;
724 s_resultCb = (ResultEvent evt, IntPtr cmdList, IntPtr result, IntPtr userData) =>
726 if (IntPtr.Zero != cmdList && IntPtr.Zero != result)
728 s_recognitionResult = new RecognitionResult(evt, cmdList, result);
732 Log.Info(LogTag, "cmdList or result is null");
735 ErrorCode error = VcGetResult(s_resultCb, IntPtr.Zero);
736 if (error != ErrorCode.None)
738 Log.Error(LogTag, "GetResult Failed with error " + error);
739 throw ExceptionFactory.CreateException(error);
742 return s_recognitionResult;
746 /// Event to be invoked when the recognition is done.
748 /// <since_tizen> 3 </since_tizen>
750 /// The state must be initialized.
752 public static event EventHandler<RecognitionResultEventArgs> RecognitionResult
756 s_resultDelegate = (ResultEvent evt, IntPtr cmdList, IntPtr result, IntPtr userData) =>
758 Log.Info(LogTag, "Recognition Result Event Triggered");
759 if (IntPtr.Zero != cmdList && IntPtr.Zero != result)
761 RecognitionResultEventArgs args = new RecognitionResultEventArgs(new RecognitionResult(evt, cmdList, result));
762 _recognitionResult?.Invoke(null, args);
766 Log.Info(LogTag, "Recognition Result Event null received");
769 ErrorCode error = VcSetResultCb(s_resultDelegate, IntPtr.Zero);
770 if (error != ErrorCode.None)
772 Log.Error(LogTag, "Add RecognitionResult Failed with error " + error);
776 _recognitionResult += value;
782 ErrorCode error = VcUnsetResultCb();
783 if (error != ErrorCode.None)
785 Log.Error(LogTag, "Remove RecognitionResult Failed with error " + error);
788 _recognitionResult -= value;
793 /// Event to be invoked when the VoiceControl service state changes.
795 /// <since_tizen> 3 </since_tizen>
797 /// The state must be initialized.
799 public static event EventHandler<ServiceStateChangedEventArgs> ServiceStateChanged
803 s_serviceStateDelegate = (ServiceState previous, ServiceState current, IntPtr userData) =>
805 ServiceStateChangedEventArgs args = new ServiceStateChangedEventArgs(previous, current);
806 _serviceStateChanged?.Invoke(null, args);
808 ErrorCode error = VcSetServiceStateChangedCb(s_serviceStateDelegate, IntPtr.Zero);
809 if (error != ErrorCode.None)
811 Log.Error(LogTag, "Add ServiceStateChanged Failed with error " + error);
815 _serviceStateChanged += value;
821 ErrorCode error = VcUnsetServiceStateChangedCb();
822 if (error != ErrorCode.None)
824 Log.Error(LogTag, "Remove ServiceStateChanged Failed with error " + error);
827 _serviceStateChanged -= value;
832 /// Event to be invoked when the VoiceControl client state changes.
834 /// <since_tizen> 3 </since_tizen>
836 /// The state must be initialized.
838 public static event EventHandler<StateChangedEventArgs> StateChanged
842 s_stateDelegate = (State previous, State current, IntPtr userData) =>
844 StateChangedEventArgs args = new StateChangedEventArgs(previous, current);
845 _stateChanged?.Invoke(null, args);
847 ErrorCode error = VcSetStateChangedCb(s_stateDelegate, IntPtr.Zero);
848 if (error != ErrorCode.None)
850 Log.Error(LogTag, "Add StateChanged Failed with error " + error);
854 _stateChanged += value;
860 ErrorCode error = VcUnsetStateChangedCb();
861 if (error != ErrorCode.None)
863 Log.Error(LogTag, "Remove StateChanged Failed with error " + error);
866 _stateChanged -= value;
871 /// Event to be invoked when an error occurs.
873 /// <since_tizen> 3 </since_tizen>
875 /// The state must be initialized.
877 public static event EventHandler<ErrorOccuredEventArgs> ErrorOccured
881 s_errorDelegate = (ErrorCode reason, IntPtr userData) =>
883 ErrorOccuredEventArgs args = new ErrorOccuredEventArgs(reason);
884 _errorOccured?.Invoke(null, args);
886 ErrorCode error = VcSetErrorCb(s_errorDelegate, IntPtr.Zero);
887 if (error != ErrorCode.None)
889 Log.Error(LogTag, "Add ErrorOccured Failed with error " + error);
894 _errorOccured += value;
901 ErrorCode error = VcUnsetErrorCb();
902 if (error != ErrorCode.None)
904 Log.Error(LogTag, "Remove ErrorOccured Failed with error " + error);
907 _errorOccured -= value;
912 /// Event to be invoked when the default language changes.
914 /// <since_tizen> 3 </since_tizen>
916 /// The state must be initialized.
918 public static event EventHandler<CurrentLanguageChangedEventArgs> CurrentLanguageChanged
922 s_languageDelegate = (IntPtr previousLanguage, IntPtr currentLanguage, IntPtr userData) =>
924 string previousLanguageString = Marshal.PtrToStringAnsi(previousLanguage);
925 string currentLanguageString = Marshal.PtrToStringAnsi(currentLanguage);
926 CurrentLanguageChangedEventArgs args = new CurrentLanguageChangedEventArgs(previousLanguageString, currentLanguageString);
927 _currentLanguageChanged?.Invoke(null, args);
929 ErrorCode error = VcSetCurrentLanguageChangedCb(s_languageDelegate, IntPtr.Zero);
930 if (error != ErrorCode.None)
932 Log.Error(LogTag, "Add CurrentLanguageChanged Failed with error " + error);
937 _currentLanguageChanged += value;
943 ErrorCode error = VcUnsetCurrentLanguageChangedCb();
944 if (error != ErrorCode.None)
946 Log.Error(LogTag, "Remove CurrentLanguageChanged Failed with error " + error);
949 _currentLanguageChanged -= value;