[dali_2.3.25] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / tizen-wayland / tts-player-impl-tizen.cpp
1 /*
2  * Copyright (c) 2024 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   try
91   {
92     // Unset the callback funtion for TTS state change
93     int retVal = tts_unset_state_changed_cb(mTtsHandle);
94     if(retVal != TTS_ERROR_NONE)
95     {
96       LogErrorCode(static_cast<tts_error_e>(retVal));
97     }
98
99     // Destroy the TTS handle and disconnects the daemon
100     retVal = tts_destroy(mTtsHandle);
101     if(retVal != TTS_ERROR_NONE)
102     {
103       LogErrorCode(static_cast<tts_error_e>(retVal));
104     }
105   }
106   catch(std::bad_weak_ptr const& ex)
107   {
108     DALI_LOG_ERROR("TtsPlayerTizen::~TtsPlayerTizen() - std::bad_weak_ptr caught: %s\n", ex.what());
109   }
110 }
111
112 void TtsPlayerTizen::Initialize()
113 {
114   // Create the TTS handle
115   int retVal = tts_create(&mTtsHandle);
116
117   if(retVal != TTS_ERROR_NONE)
118   {
119     LogErrorCode(static_cast<tts_error_e>(retVal));
120   }
121   else
122   {
123     // Set the callback funtion for TTS state change
124     retVal = tts_set_state_changed_cb(mTtsHandle, &StateChangedCallback, this);
125     if(retVal != TTS_ERROR_NONE)
126     {
127       LogErrorCode(static_cast<tts_error_e>(retVal));
128     }
129
130     // Check tts mode
131     tts_mode_e ttsMode = TTS_MODE_DEFAULT;
132     switch(mTtsMode)
133     {
134       case Dali::TtsPlayer::DEFAULT:
135         ttsMode = TTS_MODE_DEFAULT;
136         break;
137       case Dali::TtsPlayer::NOTIFICATION:
138         ttsMode = TTS_MODE_NOTIFICATION;
139         break;
140       case Dali::TtsPlayer::SCREEN_READER:
141         ttsMode = TTS_MODE_SCREEN_READER;
142         break;
143       default:
144         break;
145     }
146
147     // Set mode
148     retVal = tts_set_mode(mTtsHandle, ttsMode);
149     if(retVal != TTS_ERROR_NONE)
150     {
151       LogErrorCode(static_cast<tts_error_e>(retVal));
152     }
153
154     // Connect the TTS daemon asynchronously
155     retVal = tts_prepare(mTtsHandle);
156     if(retVal != TTS_ERROR_NONE)
157     {
158       LogErrorCode(static_cast<tts_error_e>(retVal));
159     }
160   }
161 }
162
163 void TtsPlayerTizen::Play(const std::string& text)
164 {
165   if(mInitialized)
166   {
167     Stop();
168
169     // Add text to the queue, and use normal speed, default language and default voice set by the user
170     int retVal = tts_add_text(mTtsHandle, text.c_str(), NULL, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &mUtteranceId);
171     if(retVal != TTS_ERROR_NONE)
172     {
173       LogErrorCode(static_cast<tts_error_e>(retVal));
174     }
175     else
176     {
177       // Start synthesizing voice from text in the queue and play synthesized audio data
178       retVal = tts_play(mTtsHandle);
179       if(retVal != TTS_ERROR_NONE)
180       {
181         LogErrorCode(static_cast<tts_error_e>(retVal));
182       }
183     }
184   }
185   else
186   {
187     mUnplayedString = text;
188   }
189 }
190
191 void TtsPlayerTizen::Stop()
192 {
193   if(mInitialized)
194   {
195     // Check the current TTS state
196     tts_state_e state;
197     int         retVal = tts_get_state(mTtsHandle, &state);
198     if(retVal != TTS_ERROR_NONE)
199     {
200       LogErrorCode(static_cast<tts_error_e>(retVal));
201     }
202     else if(state == TTS_STATE_PLAYING || state == TTS_STATE_PAUSED)
203     {
204       // If it is playing or paused, stop playing and clear the queue
205       retVal = tts_stop(mTtsHandle);
206       if(retVal != TTS_ERROR_NONE)
207       {
208         LogErrorCode(static_cast<tts_error_e>(retVal));
209       }
210     }
211   }
212 }
213
214 void TtsPlayerTizen::Pause()
215 {
216   if(mInitialized)
217   {
218     // Check the current TTS state
219     tts_state_e state;
220     int         retVal = tts_get_state(mTtsHandle, &state);
221     if(retVal != TTS_ERROR_NONE)
222     {
223       LogErrorCode(static_cast<tts_error_e>(retVal));
224     }
225     else if(state == TTS_STATE_PLAYING)
226     {
227       // If the player is playing, pause it.
228       retVal = tts_pause(mTtsHandle);
229       if(retVal != TTS_ERROR_NONE)
230       {
231         LogErrorCode(static_cast<tts_error_e>(retVal));
232       }
233     }
234   }
235 }
236
237 void TtsPlayerTizen::Resume()
238 {
239   if(mInitialized)
240   {
241     // Check the current TTS state
242     tts_state_e state;
243     int         retVal = tts_get_state(mTtsHandle, &state);
244     if(retVal != TTS_ERROR_NONE)
245     {
246       LogErrorCode(static_cast<tts_error_e>(retVal));
247     }
248     else if(state == TTS_STATE_PAUSED)
249     {
250       // If the player is paused, resume it.
251       retVal = tts_play(mTtsHandle);
252       if(retVal != TTS_ERROR_NONE)
253       {
254         LogErrorCode(static_cast<tts_error_e>(retVal));
255       }
256     }
257   }
258 }
259
260 Dali::TtsPlayer::State TtsPlayerTizen::GetState()
261 {
262   Dali::TtsPlayer::State ttsState = Dali::TtsPlayer::UNAVAILABLE;
263
264   if(mInitialized)
265   {
266     // Check the current TTS state
267     tts_state_e state;
268     int         retVal = tts_get_state(mTtsHandle, &state);
269     if(retVal != TTS_ERROR_NONE)
270     {
271       LogErrorCode(static_cast<tts_error_e>(retVal));
272     }
273     else
274     {
275       ttsState = InternalToExternalState(state);
276     }
277   }
278
279   return ttsState;
280 }
281
282 Dali::TtsPlayer::StateChangedSignalType& TtsPlayerTizen::StateChangedSignal()
283 {
284   return mStateChangedSignal;
285 }
286
287 void TtsPlayerTizen::EmitStateChangedSignal(tts_state_e previous, tts_state_e current)
288 {
289   // Convert the previous and current states to external states and emit them as a signal.
290   if(!mStateChangedSignal.Empty())
291   {
292     mStateChangedSignal.Emit(InternalToExternalState(previous), InternalToExternalState(current));
293   }
294 }
295
296 void TtsPlayerTizen::StateChangedCallback(tts_h tts, tts_state_e previous, tts_state_e current, void* userData)
297 {
298   // Get the implementation (this is a static function).
299   TtsPlayerTizen* obj = static_cast<TtsPlayerTizen*>(userData);
300
301   // Emit the signal.
302   obj->EmitStateChangedSignal(previous, current);
303
304   if(!obj->mInitialized && current == TTS_STATE_READY)
305   {
306     obj->mInitialized = true;
307
308     // if there is queued text before initialization, play it
309     if(obj->mUnplayedString != "")
310     {
311       obj->Play(obj->mUnplayedString);
312       obj->mUnplayedString = "";
313     }
314   }
315 }
316
317 void TtsPlayerTizen::LogErrorCode(tts_error_e reason)
318 {
319   std::string error_string;
320
321   switch(reason)
322   {
323     case TTS_ERROR_NONE:
324     {
325       break;
326     }
327     case TTS_ERROR_OUT_OF_MEMORY:
328     {
329       error_string = "TTS: Out of Memory\n";
330       break;
331     }
332     case TTS_ERROR_IO_ERROR:
333     {
334       error_string = "TTS: I/O error\n";
335       break;
336     }
337     case TTS_ERROR_INVALID_PARAMETER:
338     {
339       error_string = "TTS: Invalid parameter\n";
340       break;
341     }
342     case TTS_ERROR_OUT_OF_NETWORK:
343     {
344       error_string = "TTS: Out of network\n";
345       break;
346     }
347     case TTS_ERROR_INVALID_STATE:
348     {
349       error_string = "TTS: Invalid state\n";
350       break;
351     }
352     case TTS_ERROR_INVALID_VOICE:
353     {
354       error_string = "TTS: Invalid voice\n";
355       break;
356     }
357     case TTS_ERROR_ENGINE_NOT_FOUND:
358     {
359       error_string = "TTS: No available engine\n";
360       break;
361     }
362     case TTS_ERROR_TIMED_OUT:
363     {
364       error_string = "TTS: No answer from the daemon\n";
365       break;
366     }
367     case TTS_ERROR_OPERATION_FAILED:
368     {
369       error_string = "TTS: Operation failed\n";
370       break;
371     }
372     default:
373     {
374       error_string = "Invalid TTS error code\n";
375       break;
376     }
377   }
378
379   if(reason != TTS_ERROR_NONE)
380   {
381     DALI_LOG_WARNING("[%s:%d] tts error : %s\n", __FUNCTION__, __LINE__, error_string.c_str());
382   }
383 }
384
385 } // namespace Adaptor
386
387 } // namespace Internal
388
389 } // namespace Dali