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.
19 using System.Collections.Generic;
20 using System.Runtime.InteropServices;
21 using static Interop.Tts;
23 namespace Tizen.Uix.Tts
26 /// Enumeration for the states.
28 /// <since_tizen> 3 </since_tizen>
34 /// <since_tizen> 3 </since_tizen>
40 /// <since_tizen> 3 </since_tizen>
46 /// <since_tizen> 3 </since_tizen>
52 /// <since_tizen> 3 </since_tizen>
56 /// Unavailable state.
58 /// <since_tizen> 3 </since_tizen>
63 /// Enumeration for TTS mode.
65 /// <since_tizen> 3 </since_tizen>
69 /// Default mode for normal application.
71 /// <since_tizen> 3 </since_tizen>
75 /// Notification mode.
77 /// <since_tizen> 3 </since_tizen>
81 /// Accessibility mode.
83 /// <since_tizen> 3 </since_tizen>
88 /// Enumeration for error values that can occur.
90 /// <since_tizen> 3 </since_tizen>
94 /// Successful, no error.
96 /// <since_tizen> 3 </since_tizen>
101 /// <since_tizen> 3 </since_tizen>
106 /// <since_tizen> 3 </since_tizen>
109 /// Invalid parameter.
111 /// <since_tizen> 3 </since_tizen>
114 /// No answer from the STT service.
116 /// <since_tizen> 3 </since_tizen>
121 /// <since_tizen> 3 </since_tizen>
124 /// Permission denied.
126 /// <since_tizen> 3 </since_tizen>
129 /// STT not supported.
131 /// <since_tizen> 3 </since_tizen>
136 /// <since_tizen> 3 </since_tizen>
141 /// <since_tizen> 3 </since_tizen>
144 /// No available engine.
146 /// <since_tizen> 3 </since_tizen>
149 /// Operation failed.
151 /// <since_tizen> 3 </since_tizen>
154 /// Audio policy blocked.
156 /// <since_tizen> 3 </since_tizen>
161 /// Enumeration for the voice types.
163 /// <since_tizen> 3 </since_tizen>
167 /// The automatic voice type.
169 /// <since_tizen> 3 </since_tizen>
173 /// The male voice type.
175 /// <since_tizen> 3 </since_tizen>
179 /// The female voice type.
181 /// <since_tizen> 3 </since_tizen>
185 /// The child voice type.
187 /// <since_tizen> 3 </since_tizen>
192 /// You can use Text-To-Speech (TTS) API's to read sound data transformed by the engine from input texts.
193 /// Applications can add input-text to queue for reading continuously and control the player that can play, pause, and stop sound data synthesized from text.
195 /// <since_tizen> 3 </since_tizen>
196 public class TtsClient : IDisposable
198 private IntPtr _handle;
199 private event EventHandler<StateChangedEventArgs> _stateChanged;
200 private event EventHandler<UtteranceEventArgs> _utteranceStarted;
201 private event EventHandler<UtteranceEventArgs> _utteranceCompleted;
202 private event EventHandler<ErrorOccurredEventArgs> _errorOccurred;
203 private event EventHandler<DefaultVoiceChangedEventArgs> _defaultVoiceChanged;
204 private event EventHandler<EngineChangedEventArgs> _engineChanged;
205 private bool disposedValue = false;
206 private Object thisLock = new Object();
207 private TtsStateChangedCB _stateDelegate;
208 private TtsUtteranceStartedCB _utteranceStartedResultDelegate;
209 private TtsUtteranceCompletedCB _utteranceCompletedResultDelegate;
210 private TtsErrorCB _errorDelegate;
211 private TtsDefaultVoiceChangedCB _voiceChangedDelegate;
212 private TtsEngineChangedCB _engineDelegate;
213 private TtsSupportedVoiceCB _supportedvoiceDelegate;
216 /// Constructor to create a TTS instance.
218 /// <since_tizen> 3 </since_tizen>
220 /// http://tizen.org/feature/speech.synthesis
222 /// <exception cref="InvalidOperationException">
223 /// This exception can be due to the following reasons:
224 /// 1. Operation Failed
225 /// 2. Engine Not Found
227 /// <exception cref="OutOfMemoryException">This exception can be due to out Of memory.</exception>
228 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
232 TtsError error = TtsCreate(out handle);
233 if (error != TtsError.None)
235 Log.Error(LogTag, "Create Failed with error " + error);
236 throw ExceptionFactory.CreateException(error);
243 /// Destructor to destroy TtsClient handle.
251 /// Event to be invoked when TTS state changes.
253 /// <since_tizen> 3 </since_tizen>
254 public event EventHandler<StateChangedEventArgs> StateChanged
260 if (_stateChanged == null)
262 _stateDelegate = (IntPtr handle, State previous, State current, IntPtr userData) =>
264 StateChangedEventArgs args = new StateChangedEventArgs(previous, current);
265 _stateChanged?.Invoke(this, args);
268 TtsError error = TtsSetStateChangedCB(_handle, _stateDelegate, IntPtr.Zero);
269 if (error != TtsError.None)
271 Log.Error(LogTag, "Add StateChanged Failed with error " + error);
274 _stateChanged += value;
283 _stateChanged -= value;
284 if (_stateChanged == null)
286 TtsError error = TtsUnsetStateChangedCB(_handle);
287 if (error != TtsError.None)
289 Log.Error(LogTag, "Remove StateChanged Failed with error " + error);
298 /// Event to be invoked when the utterance starts.
300 /// <since_tizen> 3 </since_tizen>
301 public event EventHandler<UtteranceEventArgs> UtteranceStarted
307 if (_utteranceStarted == null)
309 _utteranceStartedResultDelegate = (IntPtr handle, int uttId, IntPtr userData) =>
311 UtteranceEventArgs args = new UtteranceEventArgs(uttId);
312 _utteranceStarted?.Invoke(this, args);
315 TtsError error = TtsSetUtteranceStartedCB(_handle, _utteranceStartedResultDelegate, IntPtr.Zero);
316 if (error != TtsError.None)
318 Log.Error(LogTag, "Add UtteranceStarted Failed with error " + error);
321 _utteranceStarted += value;
329 _utteranceStarted -= value;
330 if (_utteranceStarted == null)
332 TtsError error = TtsUnsetUtteranceStartedCB(_handle);
333 if (error != TtsError.None)
335 Log.Error(LogTag, "Remove UtteranceStarted Failed with error " + error);
343 /// Event to be invoked when the utterance completes.
345 /// <since_tizen> 3 </since_tizen>
346 public event EventHandler<UtteranceEventArgs> UtteranceCompleted
352 if (_utteranceCompleted == null)
354 _utteranceCompletedResultDelegate = (IntPtr handle, int uttId, IntPtr userData) =>
356 UtteranceEventArgs args = new UtteranceEventArgs(uttId);
357 _utteranceCompleted?.Invoke(this, args);
360 TtsError error = TtsSetUtteranceCompletedCB(_handle, _utteranceCompletedResultDelegate, IntPtr.Zero);
361 if (error != TtsError.None)
363 Log.Error(LogTag, "Add UtteranceCompleted Failed with error " + error);
366 _utteranceCompleted += value;
374 _utteranceCompleted -= value;
375 if (_utteranceCompleted == null)
377 TtsError error = TtsUnsetUtteranceCompletedCB(_handle);
378 if (error != TtsError.None)
380 Log.Error(LogTag, "Remove UtteranceCompleted Failed with error " + error);
388 /// Event to be invoked when an error occurs.
390 /// <since_tizen> 4 </since_tizen>
391 public event EventHandler<ErrorOccurredEventArgs> ErrorOccurred
397 if (_errorOccurred == null)
399 _errorDelegate = (IntPtr handle, int uttId, TtsError reason, IntPtr userData) =>
401 ErrorOccurredEventArgs args = new ErrorOccurredEventArgs(handle, uttId, reason);
402 _errorOccurred?.Invoke(this, args);
405 TtsError error = TtsSetErrorCB(_handle, _errorDelegate, IntPtr.Zero);
406 if (error != TtsError.None)
408 Log.Error(LogTag, "Add ErrorOccurred Failed with error " + error);
411 _errorOccurred += value;
419 _errorOccurred -= value;
420 if (_errorOccurred == null)
422 TtsError error = TtsUnsetErrorCB(_handle);
423 if (error != TtsError.None)
425 Log.Error(LogTag, "Remove ErrorOccurred Failed with error " + error);
433 /// Event to be invoked when an error occurs.
435 /// <since_tizen> 3 </since_tizen>
436 public event EventHandler<DefaultVoiceChangedEventArgs> DefaultVoiceChanged
442 if (_defaultVoiceChanged == null)
444 _voiceChangedDelegate = (IntPtr handle, IntPtr previousLanguage, int previousVoiceType, IntPtr currentLanguage, int currentVoiceType, IntPtr userData) =>
446 string previousLanguageString = Marshal.PtrToStringAnsi(previousLanguage);
447 string currentLanguageString = Marshal.PtrToStringAnsi(currentLanguage);
448 DefaultVoiceChangedEventArgs args = new DefaultVoiceChangedEventArgs(previousLanguageString, previousVoiceType, currentLanguageString, currentVoiceType);
449 _defaultVoiceChanged?.Invoke(this, args);
452 TtsError error = TtsSetDefaultVoiceChangedCB(_handle, _voiceChangedDelegate, IntPtr.Zero);
453 if (error != TtsError.None)
455 Log.Error(LogTag, "Add DefaultVoiceChanged Failed with error " + error);
458 _defaultVoiceChanged += value;
467 _defaultVoiceChanged -= value;
468 if (_defaultVoiceChanged == null)
470 TtsError error = TtsUnsetDefaultVoiceChangedCB(_handle);
471 if (error != TtsError.None)
473 Log.Error(LogTag, "Remove DefaultVoiceChanged Failed with error " + error);
481 /// Event to be invoked to detect engine change.
483 /// <since_tizen> 3 </since_tizen>
484 public event EventHandler<EngineChangedEventArgs> EngineChanged
490 if (_engineChanged == null)
492 _engineDelegate = (IntPtr handle, IntPtr engineId, IntPtr language, int voiceType, bool needCredential, IntPtr userData) =>
494 string engineIdString = Marshal.PtrToStringAnsi(engineId);
495 string languageString = Marshal.PtrToStringAnsi(language);
496 EngineChangedEventArgs args = new EngineChangedEventArgs(engineIdString, languageString, voiceType, needCredential);
497 _engineChanged?.Invoke(this, args);
499 TtsError error = TtsSetEngineChangedCB(_handle, _engineDelegate, IntPtr.Zero);
500 if (error != TtsError.None)
502 Log.Error(LogTag, "Add EngineChanged Failed with error " + error);
505 _engineChanged += value;
513 _engineChanged -= value;
514 if (_engineChanged == null)
516 TtsError error = TtsUnsetEngineChangedCB(_handle);
517 if (error != TtsError.None)
519 Log.Error(LogTag, "Remove EngineChanged Failed with error " + error);
527 /// Gets the default voice set by the user.
529 /// <since_tizen> 3 </since_tizen>
531 /// The default voice in TTS.
534 /// The default voice SupportedVoice value.
536 public SupportedVoice DefaultVoice
544 TtsError error = TtsGetDefaultVoice(_handle, out language, out voiceType);
545 if (error != TtsError.None)
547 Log.Error(LogTag, "DefaultVoice Failed with error " + error);
548 return new SupportedVoice();
551 return new SupportedVoice(language, voiceType);
557 /// Gets the maximum byte size for text.
559 /// <since_tizen> 3 </since_tizen>
561 /// The Maximum byte size for text.
564 /// The Default Voice SupportedVoice value, 0 if unable to get the value.
567 /// The State should be ready.
569 public uint MaxTextSize
576 TtsError error = TtsGetMaxTextSize(_handle, out maxTextSize);
577 if (error != TtsError.None)
579 Log.Error(LogTag, "MaxTextSize Failed with error " + error);
590 /// Gets the current TTS state.
592 /// <since_tizen> 3 </since_tizen>
594 /// The current state of TTS.
597 /// Current TTS State value.
599 public State CurrentState
606 TtsError error = TtsGetState(_handle, out state);
607 if (error != TtsError.None)
609 Log.Error(LogTag, "CurrentState Failed with error " + error);
610 return State.Unavailable;
620 /// The TTS Mode can be set using this property.
622 /// <since_tizen> 3 </since_tizen>
624 /// The current TTS mode (default, screen-reader, notification).
629 /// <exception cref="InvalidOperationException">
630 /// This exception can be due to the following reasons while setting the value:
631 /// 1. Operation Failed
632 /// 2. Engine Not Found
634 /// <exception cref="OutOfMemoryException">This exception can be due to out Of memory.</exception>
635 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
637 /// The State should be created.
639 public Mode CurrentMode
643 Mode mode = Mode.Default;
646 TtsError error = TtsGetMode(_handle, out mode);
647 if (error != TtsError.None)
649 Log.Error(LogTag, "Get Mode Failed with error " + error);
661 error = TtsSetMode(_handle, value);
664 if (error != TtsError.None)
666 Log.Error(LogTag, "Set Mode Failed with error " + error);
667 throw ExceptionFactory.CreateException(error);
673 /// Sets the application credential.
675 /// <since_tizen> 3 </since_tizen>
676 /// <param name="credential">.
677 /// The credential string.
680 /// http://tizen.org/feature/speech.synthesis
682 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
683 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
684 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
686 /// The State should be created or ready.
688 public void SetCredential(string credential)
692 TtsError error = TtsSetCredential(_handle, credential);
693 if (error != TtsError.None)
695 Tizen.Log.Error(LogTag, "SetCredential Failed with error " + error);
696 throw ExceptionFactory.CreateException(error);
702 /// Connects to the TTS service asynchronously.
704 /// <since_tizen> 3 </since_tizen>
706 /// http://tizen.org/feature/speech.synthesis
708 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
709 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
711 /// The State must be Created.
714 /// If this function is successful, the TTS state will be ready.
715 /// If this function is unsuccessful, ErrorOccurred event will be invoked.
717 public void Prepare()
721 TtsError error = TtsPrepare(_handle);
722 if (error != TtsError.None)
724 Log.Error(LogTag, "Prepare Failed with error " + error);
725 throw ExceptionFactory.CreateException(error);
731 /// Disconnects from the STT service.
733 /// <since_tizen> 3 </since_tizen>
735 /// http://tizen.org/feature/speech.synthesis
737 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
738 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
740 /// The state must be ready.
743 /// If this function is successful, the TTS state will be created.
745 public void Unprepare()
749 TtsError error = TtsUnprepare(_handle);
750 if (error != TtsError.None)
752 Log.Error(LogTag, "Unprepare Failed with error " + error);
753 throw ExceptionFactory.CreateException(error);
759 /// Retrieves all supported voices of the current engine.
761 /// <since_tizen> 3 </since_tizen>
763 /// The list of SupportedVoice.
766 /// http://tizen.org/feature/speech.synthesis
768 /// <exception cref="InvalidOperationException">
769 /// This exception can be due to the following reasons:
770 /// 1. Engine Not Found
771 /// 2. Operation Failed
773 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
774 public IEnumerable<SupportedVoice> GetSupportedVoices()
776 List<SupportedVoice> voicesList = new List<SupportedVoice>();
779 _supportedvoiceDelegate = (IntPtr handle, IntPtr language, int voiceType, IntPtr userData) =>
781 string lang = Marshal.PtrToStringAnsi(language);
782 SupportedVoice voice = new SupportedVoice(lang, voiceType);
783 voicesList.Add(voice);
786 TtsError error = TtsForeachSupportedVoices(_handle, _supportedvoiceDelegate, IntPtr.Zero);
787 if (error != TtsError.None)
789 Log.Error(LogTag, "GetSupportedVoices Failed with error " + error);
790 throw ExceptionFactory.CreateException(error);
798 /// Gets the private data from TTS engine.
800 /// <since_tizen> 3 </since_tizen>
801 /// <param name="key">
805 /// The data corresponding to the provided key.
808 /// http://tizen.org/feature/speech.synthesis
810 /// <exception cref="InvalidOperationException">
811 /// This exception can be due to the following reasons:
813 /// 2. Engine Not found
814 /// 3. Operation Failure
816 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
818 /// The state must be ready.
820 public string GetPrivateData(string key)
825 TtsError error = TtsGetPrivateData(_handle, key, out data);
826 if (error != TtsError.None)
828 Log.Error(LogTag, "GetPrivateData Failed with error " + error);
829 throw ExceptionFactory.CreateException(error);
837 /// Sets the private data to tts engine.
839 /// <since_tizen> 3 </since_tizen>
840 /// <param name="key">
843 /// <param name="data">
847 /// http://tizen.org/feature/speech.synthesis
849 /// <exception cref="InvalidOperationException">
850 /// This exception can be due to the following reasons:
852 /// 2. Engine Not found
853 /// 3. Operation Failure
855 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
856 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
858 /// The state must be ready.
860 public void SetPrivateData(string key, string data)
864 TtsError error = TtsSetPrivateData(_handle, key, data);
865 if (error != TtsError.None)
867 Log.Error(LogTag, "SetPrivateData Failed with error " + error);
868 throw ExceptionFactory.CreateException(error);
874 /// Gets the speed range.
876 /// <since_tizen> 3 </since_tizen>
878 /// The SpeedRange value.
881 /// http://tizen.org/feature/speech.synthesis
883 /// <exception cref="InvalidOperationException">
884 /// This exception can be due to the following reasons:
886 /// 2. Operation Failure
888 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
890 /// The state must be created.
892 public SpeedRange GetSpeedRange()
894 int min = 0, max = 0, normal = 0;
897 TtsError error = TtsGetSpeedRange(_handle, out min, out normal, out max);
898 if (error != TtsError.None)
900 Log.Error(LogTag, "GetSpeedRange Failed with error " + error);
901 throw ExceptionFactory.CreateException(error);
905 return new SpeedRange(min, normal, max);
909 /// Adds a text to the queue.
911 /// <since_tizen> 3 </since_tizen>
913 /// Locale MUST be set for UTF-8 text validation check.
915 /// <param name="text">
916 /// An input text based UTF-8.
918 /// <param name="language">
919 /// The language selected from the SupportedVoice.Language Property obtained from GetSupportedVoices()(e.g. 'NULL'(Automatic),'en_US').
921 /// <param name="voiceType">
922 /// The voice type selected from the SupportedVoice.VoiceType Property obtained from GetSupportedVoices().
924 /// <param name="speed">
925 /// A speaking speed (e.g.0 for Auto or the value from SpeedRange Property).
928 /// The utterance ID.
931 /// http://tizen.org/feature/speech.synthesis
933 /// <exception cref="InvalidOperationException">
934 /// This exception can be due to the following reasons:
936 /// 2. Operation Failure
939 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
940 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
941 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
943 /// The state must be ready or playing or paused.
945 public int AddText(string text, string language, int voiceType, int speed)
950 TtsError error = TtsAddText(_handle, text, language, voiceType, speed, out id);
951 if (error != TtsError.None)
953 Log.Error(LogTag, "AddText Failed with error " + error);
954 throw ExceptionFactory.CreateException(error);
962 /// Starts synthesizing voice from the text and plays the synthesized audio data.
964 /// <since_tizen> 3 </since_tizen>
966 /// http://tizen.org/feature/speech.synthesis
968 /// <exception cref="InvalidOperationException">
969 /// This exception can be due to the following reasons:
971 /// 2. Operation Failure
972 /// 3. Out of Network
974 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
975 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
977 /// The state must be ready or paused.
980 /// If this function succeeds, the TTS state will be playing.
986 TtsError error = TtsPlay(_handle);
987 if (error != TtsError.None)
989 Log.Error(LogTag, "Play Failed with error " + error);
990 throw ExceptionFactory.CreateException(error);
996 /// Stops playing the utterance and clears the queue.
998 /// <since_tizen> 3 </since_tizen>
1000 /// http://tizen.org/feature/speech.synthesis
1002 /// <exception cref="InvalidOperationException">
1003 /// This exception can be due to the following reasons:
1005 /// 2. Operation Failure
1007 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
1009 /// The state must be ready or playing or paused.
1012 /// If this function succeeds, the TTS state will be ready.
1013 /// This function will remove all text added via AddText() and synthesized sound data.
1019 TtsError error = TtsStop(_handle);
1020 if (error != TtsError.None)
1022 Log.Error(LogTag, "Stop Failed with error " + error);
1023 throw ExceptionFactory.CreateException(error);
1029 /// Pauses the currently playing utterance.
1031 /// <since_tizen> 3 </since_tizen>
1033 /// http://tizen.org/feature/speech.synthesis
1035 /// <exception cref="InvalidOperationException">
1036 /// This exception can be due to the following reasons:
1037 /// 1. Invalid State
1038 /// 2. Operation Failure
1040 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
1042 /// The state must be playing.
1045 /// If this function succeeds, the TTS state will be Paused.
1051 TtsError error = TtsPause(_handle);
1052 if (error != TtsError.None)
1054 Log.Error(LogTag, "Pause Failed with error " + error);
1055 throw ExceptionFactory.CreateException(error);
1061 /// Method to release resources.
1063 /// <since_tizen> 3 </since_tizen>
1064 public void Dispose()
1067 GC.SuppressFinalize(this);
1071 /// Method to release resources.
1073 /// <since_tizen> 3 </since_tizen>
1074 /// <param name="disposing">
1075 /// The boolean value for destoying tts handle.
1077 protected virtual void Dispose(bool disposing)
1083 if (_handle != IntPtr.Zero)
1085 TtsError error = TtsDestroy(_handle);
1086 if (error != TtsError.None)
1088 Log.Error(LogTag, "Destroy Failed with error " + error);
1090 _handle = IntPtr.Zero;
1094 disposedValue = true;