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