Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / tizen-wayland / tts-player-impl-tizen.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.h>
20
21 // EXTERNAL INCLUDES
22 #include <tts.h>
23
24 #include <dali/public-api/object/type-registry.h>
25
26 namespace Dali
27 {
28 namespace Internal
29 {
30 namespace Adaptor
31 {
32 namespace // unnamed namespace
33 {
34 /**
35  * Helper function to convert Tizen-specific TTS state to external state.
36  * @param state The Tizen TTS state.
37  * @return The external TTS state.
38  */
39 Dali::TtsPlayer::State InternalToExternalState(tts_state_e state)
40 {
41   switch(state)
42   {
43     case TTS_STATE_CREATED:
44     {
45       return Dali::TtsPlayer::UNAVAILABLE;
46     }
47     case TTS_STATE_READY:
48     {
49       return Dali::TtsPlayer::READY;
50     }
51     case TTS_STATE_PLAYING:
52     {
53       return Dali::TtsPlayer::PLAYING;
54     }
55     case TTS_STATE_PAUSED:
56     {
57       return Dali::TtsPlayer::PAUSED;
58     }
59   }
60
61   return Dali::TtsPlayer::UNAVAILABLE;
62 }
63
64 } // unnamed namespace
65
66 #if defined(DEBUG_ENABLED)
67 Debug::Filter* TtsPlayerTizen::gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TTS_PLAYER");
68 #endif
69
70 std::unique_ptr<TtsPlayerTizen> TtsPlayerTizen::New(Dali::TtsPlayer::Mode mode)
71 {
72   return std::unique_ptr<TtsPlayerTizen>(new TtsPlayerTizen(mode));
73 }
74
75 TtsPlayerTizen::TtsPlayerTizen(Dali::TtsPlayer::Mode mode)
76 : mInitialized(false),
77   mUnplayedString(""),
78   mTtsHandle(),
79   mUtteranceId(0),
80   mTtsMode(mode)
81 {
82   Initialize();
83 }
84
85 TtsPlayerTizen::~TtsPlayerTizen()
86 {
87   // If it is playing, stop it
88   Stop();
89
90   // Unset the callback funtion for TTS state change
91   int retVal = tts_unset_state_changed_cb(mTtsHandle);
92   if(retVal != TTS_ERROR_NONE)
93   {
94     LogErrorCode(static_cast<tts_error_e>(retVal));
95   }
96
97   // Destroy the TTS handle and disconnects the daemon
98   retVal = tts_destroy(mTtsHandle);
99   if(retVal != TTS_ERROR_NONE)
100   {
101     LogErrorCode(static_cast<tts_error_e>(retVal));
102   }
103 }
104
105 void TtsPlayerTizen::Initialize()
106 {
107   // Create the TTS handle
108   int retVal = tts_create(&mTtsHandle);
109
110   if(retVal != TTS_ERROR_NONE)
111   {
112     LogErrorCode(static_cast<tts_error_e>(retVal));
113   }
114   else
115   {
116     // Set the callback funtion for TTS state change
117     retVal = tts_set_state_changed_cb(mTtsHandle, &StateChangedCallback, this);
118     if(retVal != TTS_ERROR_NONE)
119     {
120       LogErrorCode(static_cast<tts_error_e>(retVal));
121     }
122
123     // Check tts mode
124     tts_mode_e ttsMode = TTS_MODE_DEFAULT;
125     switch(mTtsMode)
126     {
127       case Dali::TtsPlayer::DEFAULT:
128         ttsMode = TTS_MODE_DEFAULT;
129         break;
130       case Dali::TtsPlayer::NOTIFICATION:
131         ttsMode = TTS_MODE_NOTIFICATION;
132         break;
133       case Dali::TtsPlayer::SCREEN_READER:
134         ttsMode = TTS_MODE_SCREEN_READER;
135         break;
136       default:
137         break;
138     }
139
140     // Set mode
141     retVal = tts_set_mode(mTtsHandle, ttsMode);
142     if(retVal != TTS_ERROR_NONE)
143     {
144       LogErrorCode(static_cast<tts_error_e>(retVal));
145     }
146
147     // Connect the TTS daemon asynchronously
148     retVal = tts_prepare(mTtsHandle);
149     if(retVal != TTS_ERROR_NONE)
150     {
151       LogErrorCode(static_cast<tts_error_e>(retVal));
152     }
153   }
154 }
155
156 void TtsPlayerTizen::Play(const std::string& text)
157 {
158   if(mInitialized)
159   {
160     Stop();
161
162     // Add text to the queue, and use normal speed, default language and default voice set by the user
163     int retVal = tts_add_text(mTtsHandle, text.c_str(), NULL, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &mUtteranceId);
164     if(retVal != TTS_ERROR_NONE)
165     {
166       LogErrorCode(static_cast<tts_error_e>(retVal));
167     }
168     else
169     {
170       // Start synthesizing voice from text in the queue and play synthesized audio data
171       retVal = tts_play(mTtsHandle);
172       if(retVal != TTS_ERROR_NONE)
173       {
174         LogErrorCode(static_cast<tts_error_e>(retVal));
175       }
176     }
177   }
178   else
179   {
180     mUnplayedString = text;
181   }
182 }
183
184 void TtsPlayerTizen::Stop()
185 {
186   if(mInitialized)
187   {
188     // Check the current TTS state
189     tts_state_e state;
190     int         retVal = tts_get_state(mTtsHandle, &state);
191     if(retVal != TTS_ERROR_NONE)
192     {
193       LogErrorCode(static_cast<tts_error_e>(retVal));
194     }
195     else if(state == TTS_STATE_PLAYING || state == TTS_STATE_PAUSED)
196     {
197       // If it is playing or paused, stop playing and clear the queue
198       retVal = tts_stop(mTtsHandle);
199       if(retVal != TTS_ERROR_NONE)
200       {
201         LogErrorCode(static_cast<tts_error_e>(retVal));
202       }
203     }
204   }
205 }
206
207 void TtsPlayerTizen::Pause()
208 {
209   if(mInitialized)
210   {
211     // Check the current TTS state
212     tts_state_e state;
213     int         retVal = tts_get_state(mTtsHandle, &state);
214     if(retVal != TTS_ERROR_NONE)
215     {
216       LogErrorCode(static_cast<tts_error_e>(retVal));
217     }
218     else if(state == TTS_STATE_PLAYING)
219     {
220       // If the player is playing, pause it.
221       retVal = tts_pause(mTtsHandle);
222       if(retVal != TTS_ERROR_NONE)
223       {
224         LogErrorCode(static_cast<tts_error_e>(retVal));
225       }
226     }
227   }
228 }
229
230 void TtsPlayerTizen::Resume()
231 {
232   if(mInitialized)
233   {
234     // Check the current TTS state
235     tts_state_e state;
236     int         retVal = tts_get_state(mTtsHandle, &state);
237     if(retVal != TTS_ERROR_NONE)
238     {
239       LogErrorCode(static_cast<tts_error_e>(retVal));
240     }
241     else if(state == TTS_STATE_PAUSED)
242     {
243       // If the player is paused, resume it.
244       retVal = tts_play(mTtsHandle);
245       if(retVal != TTS_ERROR_NONE)
246       {
247         LogErrorCode(static_cast<tts_error_e>(retVal));
248       }
249     }
250   }
251 }
252
253 Dali::TtsPlayer::State TtsPlayerTizen::GetState()
254 {
255   Dali::TtsPlayer::State ttsState = Dali::TtsPlayer::UNAVAILABLE;
256
257   if(mInitialized)
258   {
259     // Check the current TTS state
260     tts_state_e state;
261     int         retVal = tts_get_state(mTtsHandle, &state);
262     if(retVal != TTS_ERROR_NONE)
263     {
264       LogErrorCode(static_cast<tts_error_e>(retVal));
265     }
266     else
267     {
268       ttsState = InternalToExternalState(state);
269     }
270   }
271
272   return ttsState;
273 }
274
275 Dali::TtsPlayer::StateChangedSignalType& TtsPlayerTizen::StateChangedSignal()
276 {
277   return mStateChangedSignal;
278 }
279
280 void TtsPlayerTizen::EmitStateChangedSignal(tts_state_e previous, tts_state_e current)
281 {
282   // Convert the previous and current states to external states and emit them as a signal.
283   if(!mStateChangedSignal.Empty())
284   {
285     mStateChangedSignal.Emit(InternalToExternalState(previous), InternalToExternalState(current));
286   }
287 }
288
289 void TtsPlayerTizen::StateChangedCallback(tts_h tts, tts_state_e previous, tts_state_e current, void* userData)
290 {
291   // Get the implementation (this is a static function).
292   TtsPlayerTizen* obj = static_cast<TtsPlayerTizen*>(userData);
293
294   // Emit the signal.
295   obj->EmitStateChangedSignal(previous, current);
296
297   if(!obj->mInitialized && current == TTS_STATE_READY)
298   {
299     obj->mInitialized = true;
300
301     // if there is queued text before initialization, play it
302     if(obj->mUnplayedString != "")
303     {
304       obj->Play(obj->mUnplayedString);
305       obj->mUnplayedString = "";
306     }
307   }
308 }
309
310 void TtsPlayerTizen::LogErrorCode(tts_error_e reason)
311 {
312   std::string error_string;
313
314   switch(reason)
315   {
316     case TTS_ERROR_NONE:
317     {
318       break;
319     }
320     case TTS_ERROR_OUT_OF_MEMORY:
321     {
322       error_string = "TTS: Out of Memory\n";
323       break;
324     }
325     case TTS_ERROR_IO_ERROR:
326     {
327       error_string = "TTS: I/O error\n";
328       break;
329     }
330     case TTS_ERROR_INVALID_PARAMETER:
331     {
332       error_string = "TTS: Invalid parameter\n";
333       break;
334     }
335     case TTS_ERROR_OUT_OF_NETWORK:
336     {
337       error_string = "TTS: Out of network\n";
338       break;
339     }
340     case TTS_ERROR_INVALID_STATE:
341     {
342       error_string = "TTS: Invalid state\n";
343       break;
344     }
345     case TTS_ERROR_INVALID_VOICE:
346     {
347       error_string = "TTS: Invalid voice\n";
348       break;
349     }
350     case TTS_ERROR_ENGINE_NOT_FOUND:
351     {
352       error_string = "TTS: No available engine\n";
353       break;
354     }
355     case TTS_ERROR_TIMED_OUT:
356     {
357       error_string = "TTS: No answer from the daemon\n";
358       break;
359     }
360     case TTS_ERROR_OPERATION_FAILED:
361     {
362       error_string = "TTS: Operation failed\n";
363       break;
364     }
365     default:
366     {
367       error_string = "Invalid TTS error code\n";
368       break;
369     }
370   }
371
372   if(reason != TTS_ERROR_NONE)
373   {
374     DALI_LOG_WARNING("[%s:%d] tts error : %s\n", __FUNCTION__, __LINE__, error_string.c_str());
375   }
376 }
377
378 } // namespace Adaptor
379
380 } // namespace Internal
381
382 } // namespace Dali