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 /// Event to be invoked when TTS state changes.
245 /// <since_tizen> 3 </since_tizen>
246 public event EventHandler<StateChangedEventArgs> StateChanged
252 _stateDelegate = (IntPtr handle, State previous, State current, IntPtr userData) =>
254 StateChangedEventArgs args = new StateChangedEventArgs(previous, current);
255 _stateChanged?.Invoke(this, args);
257 TtsError error = TtsSetStateChangedCB(_handle, _stateDelegate, IntPtr.Zero);
258 if (error != TtsError.None)
260 Log.Error(LogTag, "Add StateChanged Failed with error " + error);
264 _stateChanged += value;
274 TtsError error = TtsUnsetStateChangedCB(_handle);
275 if (error != TtsError.None)
277 Log.Error(LogTag, "Remove StateChanged Failed with error " + error);
280 _stateChanged -= value;
287 /// Event to be invoked when the utterance starts.
289 /// <since_tizen> 3 </since_tizen>
290 public event EventHandler<UtteranceEventArgs> UtteranceStarted
296 _utteranceStartedResultDelegate = (IntPtr handle, int uttId, IntPtr userData) =>
298 UtteranceEventArgs args = new UtteranceEventArgs(uttId);
299 _utteranceStarted?.Invoke(this, args);
301 TtsError error = TtsSetUtteranceStartedCB(_handle, _utteranceStartedResultDelegate, IntPtr.Zero);
302 if (error != TtsError.None)
304 Log.Error(LogTag, "Add UtteranceStarted Failed with error " + error);
308 _utteranceStarted += value;
317 TtsError error = TtsUnsetUtteranceStartedCB(_handle);
318 if (error != TtsError.None)
320 Log.Error(LogTag, "Remove UtteranceStarted Failed with error " + error);
323 _utteranceStarted -= value;
329 /// Event to be invoked when the utterance completes.
331 /// <since_tizen> 3 </since_tizen>
332 public event EventHandler<UtteranceEventArgs> UtteranceCompleted
338 _utteranceCompletedResultDelegate = (IntPtr handle, int uttId, IntPtr userData) =>
340 UtteranceEventArgs args = new UtteranceEventArgs(uttId);
341 _utteranceCompleted?.Invoke(this, args);
343 TtsError error = TtsSetUtteranceCompletedCB(_handle, _utteranceCompletedResultDelegate, IntPtr.Zero);
344 if (error != TtsError.None)
346 Log.Error(LogTag, "Add UtteranceCompleted Failed with error " + error);
350 _utteranceCompleted += value;
359 TtsError error = TtsUnsetUtteranceCompletedCB(_handle);
360 if (error != TtsError.None)
362 Log.Error(LogTag, "Remove UtteranceCompleted Failed with error " + error);
365 _utteranceCompleted -= value;
371 /// Event to be invoked when an error occurs.
373 /// <since_tizen> 3 </since_tizen>
374 public event EventHandler<ErrorOccurredEventArgs> ErrorOccurred
380 _errorDelegate = (IntPtr handle, int uttId, TtsError reason, IntPtr userData) =>
382 ErrorOccurredEventArgs args = new ErrorOccurredEventArgs(handle, uttId, reason);
383 _errorOccurred?.Invoke(this, args);
385 TtsError error = TtsSetErrorCB(_handle, _errorDelegate, IntPtr.Zero);
386 if (error != TtsError.None)
388 Log.Error(LogTag, "Add ErrorOccurred Failed with error " + error);
393 _errorOccurred += value;
402 TtsError error = TtsUnsetErrorCB(_handle);
403 if (error != TtsError.None)
405 Log.Error(LogTag, "Remove ErrorOccurred Failed with error " + error);
408 _errorOccurred -= value;
414 /// Event to be invoked when an error occurs.
416 /// <since_tizen> 3 </since_tizen>
417 public event EventHandler<DefaultVoiceChangedEventArgs> DefaultVoiceChanged
423 _voiceChangedDelegate = (IntPtr handle, IntPtr previousLanguage, int previousVoiceType, IntPtr currentLanguage, int currentVoiceType, IntPtr userData) =>
425 string previousLanguageString = Marshal.PtrToStringAnsi(previousLanguage);
426 string currentLanguageString = Marshal.PtrToStringAnsi(currentLanguage);
427 DefaultVoiceChangedEventArgs args = new DefaultVoiceChangedEventArgs(previousLanguageString, previousVoiceType, currentLanguageString, currentVoiceType);
428 _defaultVoiceChanged?.Invoke(this, args);
430 TtsError error = TtsSetDefaultVoiceChangedCB(_handle, _voiceChangedDelegate, IntPtr.Zero);
431 if (error != TtsError.None)
433 Log.Error(LogTag, "Add DefaultVoiceChanged Failed with error " + error);
438 _defaultVoiceChanged += value;
448 TtsError error = TtsUnsetDefaultVoiceChangedCB(_handle);
449 if (error != TtsError.None)
451 Log.Error(LogTag, "Remove DefaultVoiceChanged Failed with error " + error);
454 _defaultVoiceChanged -= value;
460 /// Event to be invoked to detect engine change.
462 /// <since_tizen> 3 </since_tizen>
463 public event EventHandler<EngineChangedEventArgs> EngineChanged
469 _engineDelegate = (IntPtr handle, IntPtr engineId, IntPtr language, int voiceType, bool needCredential, IntPtr userData) =>
471 string engineIdString = Marshal.PtrToStringAnsi(engineId);
472 string languageString = Marshal.PtrToStringAnsi(language);
473 EngineChangedEventArgs args = new EngineChangedEventArgs(engineIdString, languageString, voiceType, needCredential);
474 _engineChanged?.Invoke(this, args);
476 TtsError error = TtsSetEngineChangedCB(_handle, _engineDelegate, IntPtr.Zero);
477 if (error != TtsError.None)
479 Log.Error(LogTag, "Add EngineChanged Failed with error " + error);
483 _engineChanged += value;
492 TtsError error = TtsUnsetEngineChangedCB(_handle);
493 if (error != TtsError.None)
495 Log.Error(LogTag, "Remove EngineChanged Failed with error " + error);
498 _engineChanged -= value;
504 /// Gets the default voice set by the user.
506 /// <since_tizen> 3 </since_tizen>
508 /// The default voice in TTS.
511 /// The default voice SupportedVoice value.
513 public SupportedVoice DefaultVoice
521 TtsError error = TtsGetDefaultVoice(_handle, out language, out voiceType);
522 if (error != TtsError.None)
524 Log.Error(LogTag, "DefaultVoice Failed with error " + error);
525 return new SupportedVoice();
528 return new SupportedVoice(language, voiceType);
534 /// Gets the maximum byte size for text.
536 /// <since_tizen> 3 </since_tizen>
538 /// The Maximum byte size for text.
541 /// The Default Voice SupportedVoice value, 0 if unable to get the value.
544 /// The State should be ready.
546 public uint MaxTextSize
553 TtsError error = TtsGetMaxTextSize(_handle, out maxTextSize);
554 if (error != TtsError.None)
556 Log.Error(LogTag, "MaxTextSize Failed with error " + error);
568 /// Gets the current TTS state.
570 /// <since_tizen> 3 </since_tizen>
572 /// The current state of TTS.
575 /// Current TTS State value.
577 public State CurrentState
584 TtsError error = TtsGetState(_handle, out state);
585 if (error != TtsError.None)
587 Log.Error(LogTag, "CurrentState Failed with error " + error);
588 return State.Unavailable;
599 /// The TTS Mode can be set using this property.
601 /// <since_tizen> 3 </since_tizen>
603 /// The current TTS mode (default, screen-reader, notification).
608 /// <exception cref="InvalidOperationException">
609 /// This exception can be due to the following reasons while setting the value:
610 /// 1. Operation Failed
611 /// 2. Engine Not Found
613 /// <exception cref="OutOfMemoryException">This exception can be due to out Of memory.</exception>
614 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
616 /// The State should be created.
618 public Mode CurrentMode
622 Mode mode = Mode.Default;
625 TtsError error = TtsGetMode(_handle, out mode);
626 if (error != TtsError.None)
628 Log.Error(LogTag, "Get Mode Failed with error " + error);
640 error = TtsSetMode(_handle, value);
643 if (error != TtsError.None)
645 Log.Error(LogTag, "Set Mode Failed with error " + error);
646 throw ExceptionFactory.CreateException(error);
652 /// Sets the application credential.
654 /// <since_tizen> 3 </since_tizen>
655 /// <param name="credential">.
656 /// The credential string.
659 /// http://tizen.org/feature/speech.synthesis
661 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
662 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
663 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
665 /// The State should be created or ready.
667 public void SetCredential(string credential)
671 TtsError error = TtsSetCredential(_handle, credential);
672 if (error != TtsError.None)
674 Tizen.Log.Error(LogTag, "SetCredential Failed with error " + error);
675 throw ExceptionFactory.CreateException(error);
681 /// Connects to the TTS service asynchronously.
683 /// <since_tizen> 3 </since_tizen>
685 /// http://tizen.org/feature/speech.synthesis
687 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
688 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
690 /// The State must be Created.
693 /// If this function is successful, the TTS state will be ready.
694 /// If this function is unsuccessful, ErrorOccurred event will be invoked.
696 public void Prepare()
700 TtsError error = TtsPrepare(_handle);
701 if (error != TtsError.None)
703 Log.Error(LogTag, "Prepare Failed with error " + error);
704 throw ExceptionFactory.CreateException(error);
710 /// Disconnects from the STT service.
712 /// <since_tizen> 3 </since_tizen>
714 /// http://tizen.org/feature/speech.synthesis
716 /// <exception cref="InvalidOperationException">This exception can be due to an invalid state.</exception>
717 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
719 /// The state must be ready.
722 /// If this function is successful, the TTS state will be created.
724 public void Unprepare()
728 TtsError error = TtsUnprepare(_handle);
729 if (error != TtsError.None)
731 Log.Error(LogTag, "Unprepare Failed with error " + error);
732 throw ExceptionFactory.CreateException(error);
738 /// Retrieves all supported voices of the current engine.
740 /// <since_tizen> 3 </since_tizen>
742 /// The list of SupportedVoice.
745 /// http://tizen.org/feature/speech.synthesis
747 /// <exception cref="InvalidOperationException">
748 /// This exception can be due to the following reasons:
749 /// 1. Engine Not Found
750 /// 2. Operation Failed
752 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
753 public IEnumerable<SupportedVoice> GetSupportedVoices()
755 List<SupportedVoice> voicesList = new List<SupportedVoice>();
758 _supportedvoiceDelegate = (IntPtr handle, IntPtr language, int voiceType, IntPtr userData) =>
760 string lang = Marshal.PtrToStringAnsi(language);
761 SupportedVoice voice = new SupportedVoice(lang, voiceType);
762 voicesList.Add(voice);
765 TtsError error = TtsForeachSupportedVoices(_handle, _supportedvoiceDelegate, IntPtr.Zero);
766 if (error != TtsError.None)
768 Log.Error(LogTag, "GetSupportedVoices Failed with error " + error);
769 throw ExceptionFactory.CreateException(error);
778 /// Gets the private data from TTS engine.
780 /// <since_tizen> 3 </since_tizen>
781 /// <param name="key">
785 /// The data corresponding to the provided key.
788 /// http://tizen.org/feature/speech.synthesis
790 /// <exception cref="InvalidOperationException">
791 /// This exception can be due to the following reasons:
793 /// 2. Engine Not found
794 /// 3. Operation Failure
796 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
798 /// The state must be ready.
800 public string GetPrivateData(string key)
805 TtsError error = TtsGetPrivateData(_handle, key, out data);
806 if (error != TtsError.None)
808 Log.Error(LogTag, "GetPrivateData Failed with error " + error);
809 throw ExceptionFactory.CreateException(error);
818 /// Sets the private data to tts engine.
820 /// <since_tizen> 3 </since_tizen>
821 /// <param name="key">
824 /// <param name="data">
828 /// http://tizen.org/feature/speech.synthesis
830 /// <exception cref="InvalidOperationException">
831 /// This exception can be due to the following reasons:
833 /// 2. Engine Not found
834 /// 3. Operation Failure
836 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
837 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
839 /// The state must be ready.
841 public void SetPrivateData(string key, string data)
845 TtsError error = TtsSetPrivateData(_handle, key, data);
846 if (error != TtsError.None)
848 Log.Error(LogTag, "SetPrivateData Failed with error " + error);
849 throw ExceptionFactory.CreateException(error);
855 /// Gets the speed range.
857 /// <since_tizen> 3 </since_tizen>
859 /// The SpeedRange value.
862 /// http://tizen.org/feature/speech.synthesis
864 /// <exception cref="InvalidOperationException">
865 /// This exception can be due to the following reasons:
867 /// 2. Operation Failure
869 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
871 /// The state must be created.
873 public SpeedRange GetSpeedRange()
875 int min = 0, max = 0, normal = 0;
878 TtsError error = TtsGetSpeedRange(_handle, out min, out normal, out max);
879 if (error != TtsError.None)
881 Log.Error(LogTag, "GetSpeedRange Failed with error " + error);
882 throw ExceptionFactory.CreateException(error);
887 return new SpeedRange(min, normal, max);
891 /// Adds a text to the queue.
893 /// <since_tizen> 3 </since_tizen>
895 /// Locale MUST be set for UTF-8 text validation check.
897 /// <param name="text">
898 /// An input text based UTF-8.
900 /// <param name="language">
901 /// The language selected from the SupportedVoice.Language Property obtained from GetSupportedVoices()(e.g. 'NULL'(Automatic),'en_US').
903 /// <param name="voiceType">
904 /// The voice type selected from the SupportedVoice.VoiceType Property obtained from GetSupportedVoices().
906 /// <param name="speed">
907 /// A speaking speed (e.g.0 for Auto or the value from SpeedRange Property).
910 /// The utterance ID.
913 /// http://tizen.org/feature/speech.synthesis
915 /// <exception cref="InvalidOperationException">
916 /// This exception can be due to the following reasons:
918 /// 2. Operation Failure
921 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
922 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
923 /// <exception cref="ArgumentException">This exception can be due to improper value provided while setting the value.</exception>
925 /// The state must be ready or playing or paused.
927 public int AddText(string text, string language, int voiceType, int speed)
932 TtsError error = TtsAddText(_handle, text, language, voiceType, speed, out id);
933 if (error != TtsError.None)
935 Log.Error(LogTag, "AddText Failed with error " + error);
936 throw ExceptionFactory.CreateException(error);
945 /// Starts synthesizing voice from the text and plays the synthesized audio data.
947 /// <since_tizen> 3 </since_tizen>
949 /// http://tizen.org/feature/speech.synthesis
951 /// <exception cref="InvalidOperationException">
952 /// This exception can be due to the following reasons:
954 /// 2. Operation Failure
955 /// 3. Out of Network
957 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
958 /// <exception cref="UnauthorizedAccessException">This exception can be due to permission denied.</exception>
960 /// The state must be ready or paused.
963 /// If this function succeeds, the TTS state will be playing.
969 TtsError error = TtsPlay(_handle);
970 if (error != TtsError.None)
972 Log.Error(LogTag, "Play Failed with error " + error);
973 throw ExceptionFactory.CreateException(error);
979 /// Stops playing the utterance and clears the queue.
981 /// <since_tizen> 3 </since_tizen>
983 /// http://tizen.org/feature/speech.synthesis
985 /// <exception cref="InvalidOperationException">
986 /// This exception can be due to the following reasons:
988 /// 2. Operation Failure
990 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
992 /// The state must be ready or playing or paused.
995 /// If this function succeeds, the TTS state will be ready.
996 /// This function will remove all text added via AddText() and synthesized sound data.
1002 TtsError error = TtsStop(_handle);
1003 if (error != TtsError.None)
1005 Log.Error(LogTag, "Stop Failed with error " + error);
1006 throw ExceptionFactory.CreateException(error);
1012 /// Pauses the currently playing utterance.
1014 /// <since_tizen> 3 </since_tizen>
1016 /// http://tizen.org/feature/speech.synthesis
1018 /// <exception cref="InvalidOperationException">
1019 /// This exception can be due to the following reasons:
1020 /// 1. Invalid State
1021 /// 2. Operation Failure
1023 /// <exception cref="NotSupportedException">This exception can be due to TTS not supported.</exception>
1025 /// The state must be playing.
1028 /// If this function succeeds, the TTS state will be Paused.
1034 TtsError error = TtsPause(_handle);
1035 if (error != TtsError.None)
1037 Log.Error(LogTag, "Pause Failed with error " + error);
1038 throw ExceptionFactory.CreateException(error);
1044 /// Method to release resources.
1046 /// <since_tizen> 3 </since_tizen>
1047 public void Dispose()
1052 protected virtual void Dispose(bool disposing)
1058 TtsError error = TtsDestroy(_handle);
1059 if (error != TtsError.None)
1061 Log.Error(LogTag, "Destroy Failed with error " + error);
1065 disposedValue = true;