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 _stateDelegate = (IntPtr handle, State previous, State current, IntPtr userData) =>
262 StateChangedEventArgs args = new StateChangedEventArgs(previous, current);
263 _stateChanged?.Invoke(this, args);
265 TtsError error = TtsSetStateChangedCB(_handle, _stateDelegate, IntPtr.Zero);
266 if (error != TtsError.None)
268 Log.Error(LogTag, "Add StateChanged Failed with error " + error);
272 _stateChanged += value;
282 TtsError error = TtsUnsetStateChangedCB(_handle);
283 if (error != TtsError.None)
285 Log.Error(LogTag, "Remove StateChanged Failed with error " + error);
288 _stateChanged -= value;
295 /// Event to be invoked when the utterance starts.
297 /// <since_tizen> 3 </since_tizen>
298 public event EventHandler<UtteranceEventArgs> UtteranceStarted
304 _utteranceStartedResultDelegate = (IntPtr handle, int uttId, IntPtr userData) =>
306 UtteranceEventArgs args = new UtteranceEventArgs(uttId);
307 _utteranceStarted?.Invoke(this, args);
309 TtsError error = TtsSetUtteranceStartedCB(_handle, _utteranceStartedResultDelegate, IntPtr.Zero);
310 if (error != TtsError.None)
312 Log.Error(LogTag, "Add UtteranceStarted Failed with error " + error);
316 _utteranceStarted += value;
325 TtsError error = TtsUnsetUtteranceStartedCB(_handle);
326 if (error != TtsError.None)
328 Log.Error(LogTag, "Remove UtteranceStarted Failed with error " + error);
331 _utteranceStarted -= value;
337 /// Event to be invoked when the utterance completes.
339 /// <since_tizen> 3 </since_tizen>
340 public event EventHandler<UtteranceEventArgs> UtteranceCompleted
346 _utteranceCompletedResultDelegate = (IntPtr handle, int uttId, IntPtr userData) =>
348 UtteranceEventArgs args = new UtteranceEventArgs(uttId);
349 _utteranceCompleted?.Invoke(this, args);
351 TtsError error = TtsSetUtteranceCompletedCB(_handle, _utteranceCompletedResultDelegate, IntPtr.Zero);
352 if (error != TtsError.None)
354 Log.Error(LogTag, "Add UtteranceCompleted Failed with error " + error);
358 _utteranceCompleted += value;
367 TtsError error = TtsUnsetUtteranceCompletedCB(_handle);
368 if (error != TtsError.None)
370 Log.Error(LogTag, "Remove UtteranceCompleted Failed with error " + error);
373 _utteranceCompleted -= value;
379 /// Event to be invoked when an error occurs.
381 /// <since_tizen> 4 </since_tizen>
382 public event EventHandler<ErrorOccurredEventArgs> ErrorOccurred
388 _errorDelegate = (IntPtr handle, int uttId, TtsError reason, IntPtr userData) =>
390 ErrorOccurredEventArgs args = new ErrorOccurredEventArgs(handle, uttId, reason);
391 _errorOccurred?.Invoke(this, args);
393 TtsError error = TtsSetErrorCB(_handle, _errorDelegate, IntPtr.Zero);
394 if (error != TtsError.None)
396 Log.Error(LogTag, "Add ErrorOccurred Failed with error " + error);
401 _errorOccurred += value;
410 TtsError error = TtsUnsetErrorCB(_handle);
411 if (error != TtsError.None)
413 Log.Error(LogTag, "Remove ErrorOccurred Failed with error " + error);
416 _errorOccurred -= value;
422 /// Event to be invoked when an error occurs.
424 /// <since_tizen> 3 </since_tizen>
425 public event EventHandler<DefaultVoiceChangedEventArgs> DefaultVoiceChanged
431 _voiceChangedDelegate = (IntPtr handle, IntPtr previousLanguage, int previousVoiceType, IntPtr currentLanguage, int currentVoiceType, IntPtr userData) =>
433 string previousLanguageString = Marshal.PtrToStringAnsi(previousLanguage);
434 string currentLanguageString = Marshal.PtrToStringAnsi(currentLanguage);
435 DefaultVoiceChangedEventArgs args = new DefaultVoiceChangedEventArgs(previousLanguageString, previousVoiceType, currentLanguageString, currentVoiceType);
436 _defaultVoiceChanged?.Invoke(this, args);
438 TtsError error = TtsSetDefaultVoiceChangedCB(_handle, _voiceChangedDelegate, IntPtr.Zero);
439 if (error != TtsError.None)
441 Log.Error(LogTag, "Add DefaultVoiceChanged Failed with error " + error);
446 _defaultVoiceChanged += value;
456 TtsError error = TtsUnsetDefaultVoiceChangedCB(_handle);
457 if (error != TtsError.None)
459 Log.Error(LogTag, "Remove DefaultVoiceChanged Failed with error " + error);
462 _defaultVoiceChanged -= value;
468 /// Event to be invoked to detect engine change.
470 /// <since_tizen> 3 </since_tizen>
471 public event EventHandler<EngineChangedEventArgs> EngineChanged
477 _engineDelegate = (IntPtr handle, IntPtr engineId, IntPtr language, int voiceType, bool needCredential, IntPtr userData) =>
479 string engineIdString = Marshal.PtrToStringAnsi(engineId);
480 string languageString = Marshal.PtrToStringAnsi(language);
481 EngineChangedEventArgs args = new EngineChangedEventArgs(engineIdString, languageString, voiceType, needCredential);
482 _engineChanged?.Invoke(this, args);
484 TtsError error = TtsSetEngineChangedCB(_handle, _engineDelegate, IntPtr.Zero);
485 if (error != TtsError.None)
487 Log.Error(LogTag, "Add EngineChanged Failed with error " + error);
491 _engineChanged += value;
500 TtsError error = TtsUnsetEngineChangedCB(_handle);
501 if (error != TtsError.None)
503 Log.Error(LogTag, "Remove EngineChanged Failed with error " + error);
506 _engineChanged -= value;
512 /// Gets the default voice set by the user.
514 /// <since_tizen> 3 </since_tizen>
516 /// The default voice in TTS.
519 /// The default voice SupportedVoice value.
521 public SupportedVoice DefaultVoice
529 TtsError error = TtsGetDefaultVoice(_handle, out language, out voiceType);
530 if (error != TtsError.None)
532 Log.Error(LogTag, "DefaultVoice Failed with error " + error);
533 return new SupportedVoice();
536 return new SupportedVoice(language, voiceType);
542 /// Gets the maximum byte size for text.
544 /// <since_tizen> 3 </since_tizen>
546 /// The Maximum byte size for text.
549 /// The Default Voice SupportedVoice value, 0 if unable to get the value.
552 /// The State should be ready.
554 public uint MaxTextSize
561 TtsError error = TtsGetMaxTextSize(_handle, out maxTextSize);
562 if (error != TtsError.None)
564 Log.Error(LogTag, "MaxTextSize Failed with error " + error);
575 /// Gets the current TTS state.
577 /// <since_tizen> 3 </since_tizen>
579 /// The current state of TTS.
582 /// Current TTS State value.
584 public State CurrentState
591 TtsError error = TtsGetState(_handle, out state);
592 if (error != TtsError.None)
594 Log.Error(LogTag, "CurrentState Failed with error " + error);
595 return State.Unavailable;
605 /// The TTS Mode can be set using this property.
607 /// <since_tizen> 3 </since_tizen>
609 /// The current TTS mode (default, screen-reader, notification).
614 /// <exception cref="InvalidOperationException">
615 /// This exception can be due to the following reasons while setting the value:
616 /// 1. Operation Failed
617 /// 2. Engine Not Found
619 /// <exception cref="OutOfMemoryException">This exception can be due to out Of memory.</exception>
620 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
622 /// The State should be created.
624 public Mode CurrentMode
628 Mode mode = Mode.Default;
631 TtsError error = TtsGetMode(_handle, out mode);
632 if (error != TtsError.None)
634 Log.Error(LogTag, "Get Mode Failed with error " + error);
646 error = TtsSetMode(_handle, value);
649 if (error != TtsError.None)
651 Log.Error(LogTag, "Set Mode Failed with error " + error);
652 throw ExceptionFactory.CreateException(error);
658 /// Sets the application credential.
660 /// <since_tizen> 3 </since_tizen>
661 /// <param name="credential">.
662 /// The credential string.
665 /// http://tizen.org/feature/speech.synthesis
667 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
668 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
669 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
671 /// The State should be created or ready.
673 public void SetCredential(string credential)
677 TtsError error = TtsSetCredential(_handle, credential);
678 if (error != TtsError.None)
680 Tizen.Log.Error(LogTag, "SetCredential Failed with error " + error);
681 throw ExceptionFactory.CreateException(error);
687 /// Connects to the TTS service asynchronously.
689 /// <since_tizen> 3 </since_tizen>
691 /// http://tizen.org/feature/speech.synthesis
693 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
694 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
696 /// The State must be Created.
699 /// If this function is successful, the TTS state will be ready.
700 /// If this function is unsuccessful, ErrorOccurred event will be invoked.
702 public void Prepare()
706 TtsError error = TtsPrepare(_handle);
707 if (error != TtsError.None)
709 Log.Error(LogTag, "Prepare Failed with error " + error);
710 throw ExceptionFactory.CreateException(error);
716 /// Disconnects from the STT service.
718 /// <since_tizen> 3 </since_tizen>
720 /// http://tizen.org/feature/speech.synthesis
722 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
723 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
725 /// The state must be ready.
728 /// If this function is successful, the TTS state will be created.
730 public void Unprepare()
734 TtsError error = TtsUnprepare(_handle);
735 if (error != TtsError.None)
737 Log.Error(LogTag, "Unprepare Failed with error " + error);
738 throw ExceptionFactory.CreateException(error);
744 /// Retrieves all supported voices of the current engine.
746 /// <since_tizen> 3 </since_tizen>
748 /// The list of SupportedVoice.
751 /// http://tizen.org/feature/speech.synthesis
753 /// <exception cref="InvalidOperationException">
754 /// This exception can be due to the following reasons:
755 /// 1. Engine Not Found
756 /// 2. Operation Failed
758 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
759 public IEnumerable<SupportedVoice> GetSupportedVoices()
761 List<SupportedVoice> voicesList = new List<SupportedVoice>();
764 _supportedvoiceDelegate = (IntPtr handle, IntPtr language, int voiceType, IntPtr userData) =>
766 string lang = Marshal.PtrToStringAnsi(language);
767 SupportedVoice voice = new SupportedVoice(lang, voiceType);
768 voicesList.Add(voice);
771 TtsError error = TtsForeachSupportedVoices(_handle, _supportedvoiceDelegate, IntPtr.Zero);
772 if (error != TtsError.None)
774 Log.Error(LogTag, "GetSupportedVoices Failed with error " + error);
775 throw ExceptionFactory.CreateException(error);
783 /// Gets the private data from TTS engine.
785 /// <since_tizen> 3 </since_tizen>
786 /// <param name="key">
790 /// The data corresponding to the provided key.
793 /// http://tizen.org/feature/speech.synthesis
795 /// <exception cref="InvalidOperationException">
796 /// This exception can be due to the following reasons:
798 /// 2. Engine Not found
799 /// 3. Operation Failure
801 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
803 /// The state must be ready.
805 public string GetPrivateData(string key)
810 TtsError error = TtsGetPrivateData(_handle, key, out data);
811 if (error != TtsError.None)
813 Log.Error(LogTag, "GetPrivateData Failed with error " + error);
814 throw ExceptionFactory.CreateException(error);
822 /// Sets the private data to tts engine.
824 /// <since_tizen> 3 </since_tizen>
825 /// <param name="key">
828 /// <param name="data">
832 /// http://tizen.org/feature/speech.synthesis
834 /// <exception cref="InvalidOperationException">
835 /// This exception can be due to the following reasons:
837 /// 2. Engine Not found
838 /// 3. Operation Failure
840 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
841 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
843 /// The state must be ready.
845 public void SetPrivateData(string key, string data)
849 TtsError error = TtsSetPrivateData(_handle, key, data);
850 if (error != TtsError.None)
852 Log.Error(LogTag, "SetPrivateData Failed with error " + error);
853 throw ExceptionFactory.CreateException(error);
859 /// Gets the speed range.
861 /// <since_tizen> 3 </since_tizen>
863 /// The SpeedRange value.
866 /// http://tizen.org/feature/speech.synthesis
868 /// <exception cref="InvalidOperationException">
869 /// This exception can be due to the following reasons:
871 /// 2. Operation Failure
873 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
875 /// The state must be created.
877 public SpeedRange GetSpeedRange()
879 int min = 0, max = 0, normal = 0;
882 TtsError error = TtsGetSpeedRange(_handle, out min, out normal, out max);
883 if (error != TtsError.None)
885 Log.Error(LogTag, "GetSpeedRange Failed with error " + error);
886 throw ExceptionFactory.CreateException(error);
890 return new SpeedRange(min, normal, max);
894 /// Adds a text to the queue.
896 /// <since_tizen> 3 </since_tizen>
898 /// Locale MUST be set for UTF-8 text validation check.
900 /// <param name="text">
901 /// An input text based UTF-8.
903 /// <param name="language">
904 /// The language selected from the SupportedVoice.Language Property obtained from GetSupportedVoices()(e.g. 'NULL'(Automatic),'en_US').
906 /// <param name="voiceType">
907 /// The voice type selected from the SupportedVoice.VoiceType Property obtained from GetSupportedVoices().
909 /// <param name="speed">
910 /// A speaking speed (e.g.0 for Auto or the value from SpeedRange Property).
913 /// The utterance ID.
916 /// http://tizen.org/feature/speech.synthesis
918 /// <exception cref="InvalidOperationException">
919 /// This exception can be due to the following reasons:
921 /// 2. Operation Failure
924 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
925 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
926 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
928 /// The state must be ready or playing or paused.
930 public int AddText(string text, string language, int voiceType, int speed)
935 TtsError error = TtsAddText(_handle, text, language, voiceType, speed, out id);
936 if (error != TtsError.None)
938 Log.Error(LogTag, "AddText Failed with error " + error);
939 throw ExceptionFactory.CreateException(error);
947 /// Starts synthesizing voice from the text and plays the synthesized audio data.
949 /// <since_tizen> 3 </since_tizen>
951 /// http://tizen.org/feature/speech.synthesis
953 /// <exception cref="InvalidOperationException">
954 /// This exception can be due to the following reasons:
956 /// 2. Operation Failure
957 /// 3. Out of Network
959 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
960 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
962 /// The state must be ready or paused.
965 /// If this function succeeds, the TTS state will be playing.
971 TtsError error = TtsPlay(_handle);
972 if (error != TtsError.None)
974 Log.Error(LogTag, "Play Failed with error " + error);
975 throw ExceptionFactory.CreateException(error);
981 /// Stops playing the utterance and clears the queue.
983 /// <since_tizen> 3 </since_tizen>
985 /// http://tizen.org/feature/speech.synthesis
987 /// <exception cref="InvalidOperationException">
988 /// This exception can be due to the following reasons:
990 /// 2. Operation Failure
992 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
994 /// The state must be ready or playing or paused.
997 /// If this function succeeds, the TTS state will be ready.
998 /// This function will remove all text added via AddText() and synthesized sound data.
1004 TtsError error = TtsStop(_handle);
1005 if (error != TtsError.None)
1007 Log.Error(LogTag, "Stop Failed with error " + error);
1008 throw ExceptionFactory.CreateException(error);
1014 /// Pauses the currently playing utterance.
1016 /// <since_tizen> 3 </since_tizen>
1018 /// http://tizen.org/feature/speech.synthesis
1020 /// <exception cref="InvalidOperationException">
1021 /// This exception can be due to the following reasons:
1022 /// 1. Invalid State
1023 /// 2. Operation Failure
1025 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
1027 /// The state must be playing.
1030 /// If this function succeeds, the TTS state will be Paused.
1036 TtsError error = TtsPause(_handle);
1037 if (error != TtsError.None)
1039 Log.Error(LogTag, "Pause Failed with error " + error);
1040 throw ExceptionFactory.CreateException(error);
1046 /// Method to release resources.
1048 /// <since_tizen> 3 </since_tizen>
1049 public void Dispose()
1052 GC.SuppressFinalize(this);
1056 /// Method to release resources.
1058 /// <since_tizen> 3 </since_tizen>
1059 /// <param name="disposing">
1060 /// The boolean value for destoying tts handle.
1062 protected virtual void Dispose(bool disposing)
1068 if (_handle != IntPtr.Zero)
1070 TtsError error = TtsDestroy(_handle);
1071 if (error != TtsError.None)
1073 Log.Error(LogTag, "Destroy Failed with error " + error);
1075 _handle = IntPtr.Zero;
1079 disposedValue = true;