[LICENSE] change to Flora-1.1 license
[profile/tv/apps/native/screen-reader.git] / src / screen_reader_tts.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * This file is a modified version of BSD licensed file and
5  * licensed under the Flora License, Version 1.1 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://floralicense.org/license/
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an AS IS BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Please, see the LICENSE file for the original copyright owner and
18  * license.
19  */
20
21 #define _GNU_SOURCE
22
23 #include <Ecore.h>
24 #include "screen_reader_tts.h"
25 #include "screen_reader_vconf.h"
26 #include "logger.h"
27
28 // ---------------------------- DEBUG HELPERS ------------------------------
29
30 #define FLUSH_LIMIT 1
31
32 static int last_utt_id;
33 static Eina_Bool pause_state = EINA_FALSE;
34 static Eina_Bool flush_flag = EINA_FALSE;
35 static Eina_Strbuf *txt_keep_buff = NULL;
36
37 static void(*on_utterance_end)(void);
38
39 static void _text_keep(const char *txt)
40 {
41    if (!txt_keep_buff) return;
42    if (eina_strbuf_length_get(txt_keep_buff) > 0) eina_strbuf_append(txt_keep_buff, ", ");
43    eina_strbuf_append(txt_keep_buff, txt);
44 }
45
46 static char * get_tts_error( int r )
47 {
48    switch( r )
49       {
50       case TTS_ERROR_NONE:
51       {
52          return "no error";
53       }
54       case TTS_ERROR_INVALID_PARAMETER:
55       {
56          return "inv param";
57       }
58       case TTS_ERROR_OUT_OF_MEMORY:
59       {
60          return "out of memory";
61       }
62       case TTS_ERROR_OPERATION_FAILED:
63       {
64          return "oper failed";
65       }
66       case TTS_ERROR_INVALID_STATE:
67       {
68          return "inv state";
69       }
70       default:
71       {
72          return "uknown error";
73       }
74       }
75 }
76
77 static char * get_tts_state( tts_state_e r )
78 {
79    switch( r )
80       {
81       case TTS_STATE_CREATED:
82       {
83          return "created";
84       }
85       case TTS_STATE_READY:
86       {
87          return "ready";
88       }
89       case TTS_STATE_PLAYING:
90       {
91          return "playing";
92       }
93       case TTS_STATE_PAUSED:
94       {
95          return "pause";
96       }
97       default:
98       {
99          return "uknown state";
100       }
101       }
102 }
103
104 //-------------------------------------------------------------------------------------------------
105
106 void set_utterance_cb( void(*uter_cb)(void))
107 {
108    on_utterance_end = uter_cb;
109 }
110
111
112 bool get_supported_voices_cb(tts_h tts, const char* language, int voice_type, void* user_data)
113 {
114    DEBUG("LANG: %s; TYPE: %d", language, voice_type);
115
116    Service_Data *sd = user_data;
117    Voice_Info *vi = calloc(1, sizeof(Voice_Info));
118    if(!vi)
119       {
120          ERROR(MEMORY_ERROR);
121          return  ECORE_CALLBACK_CANCEL;
122       }
123
124    if(asprintf(&vi->language, "%s",language) < 0)
125       {
126          free(vi);
127          ERROR(MEMORY_ERROR);
128          return  ECORE_CALLBACK_CANCEL;
129       }
130
131    vi->voice_type = voice_type;
132
133    sd->available_languages = eina_list_append(sd->available_languages, vi);
134
135    return ECORE_CALLBACK_RENEW;
136 }
137
138 static void __tts_test_utt_started_cb(tts_h tts, int utt_id, void* user_data)
139 {
140    DEBUG("Utterance started : utt id(%d) \n", utt_id);
141    return;
142 }
143
144 static void __tts_test_utt_completed_cb(tts_h tts, int utt_id, void* user_data)
145 {
146    DEBUG("Utterance completed : utt id(%d) \n", utt_id);
147    if(last_utt_id - utt_id > FLUSH_LIMIT)
148       flush_flag = EINA_TRUE;
149    else
150       {
151          if(flush_flag)
152             flush_flag = EINA_FALSE;
153       }
154
155 #ifndef SCREEN_READER_TV
156    if(last_utt_id == utt_id)
157       {
158          DEBUG("LAST UTTERANCE");
159          pause_state = EINA_FALSE;
160          on_utterance_end();
161       }
162 #endif
163
164    return;
165 }
166
167 bool tts_init(void *data)
168 {
169    DEBUG( "--------------------- TTS_init START ---------------------");
170    Service_Data *sd = data;
171
172    int r = tts_create( &sd->tts );
173    DEBUG( "Create tts %d (%s)", r, get_tts_error( r ) );
174
175    r = tts_set_mode( sd->tts, TTS_MODE_SCREEN_READER );
176    DEBUG( "Set tts mode SR %d (%s)", r, get_tts_error( r ) );
177
178    r = tts_prepare( sd->tts );
179    DEBUG( "Prepare tts %d (%s)", r, get_tts_error( r ) );
180
181    tts_set_state_changed_cb(sd->tts, state_changed_cb, sd);
182
183    tts_set_utterance_started_cb(sd->tts, __tts_test_utt_started_cb, sd);
184    tts_set_utterance_completed_cb(sd->tts,  __tts_test_utt_completed_cb,  sd);
185
186    DEBUG( "---------------------- TTS_init END ----------------------\n\n");
187    txt_keep_buff = eina_strbuf_new();
188    return true;
189 }
190
191 Eina_Bool tts_pause_get(void)
192 {
193    DEBUG( "PAUSE STATE: %d", pause_state);
194    return pause_state;
195 }
196
197 void tts_stop_set(void)
198 {
199    Service_Data *sd = get_pointer_to_service_data_struct();
200    tts_stop(sd->tts);
201 }
202
203 Eina_Bool tts_pause_set(Eina_Bool pause_switch)
204 {
205    Service_Data *sd = get_pointer_to_service_data_struct();
206    if(!sd)
207       return EINA_FALSE;
208
209    if(pause_switch)
210       {
211          pause_state = EINA_TRUE;
212
213          if(tts_pause(sd->tts))
214             {
215                pause_state = EINA_FALSE;
216                return EINA_FALSE;
217             }
218       }
219    else if(!pause_switch)
220       {
221          pause_state = EINA_FALSE;
222
223          if(tts_play(sd->tts))
224             {
225                pause_state = EINA_TRUE;
226                return EINA_FALSE;
227             }
228       }
229    return EINA_TRUE;
230 }
231
232 void tts_speak(char *text_to_speak, Eina_Bool flush_switch)
233 {
234    int ret = 0;
235    Service_Data *sd = get_pointer_to_service_data_struct();
236    int speak_id;
237
238    if(!sd)
239       return;
240    tts_state_e state;
241    tts_get_state(sd->tts, &state);
242
243    if (state != TTS_STATE_PLAYING &&
244          state != TTS_STATE_PAUSED &&
245          state != TTS_STATE_READY)
246       {
247          if (text_to_speak) _text_keep(text_to_speak);
248          return;
249       }
250
251    if (flush_flag || flush_switch)
252       {
253          if (state == TTS_STATE_PLAYING ||
254                state == TTS_STATE_PAUSED)
255             {
256                ret = tts_stop(sd->tts);
257                if (TTS_ERROR_NONE != ret)
258                   {
259                      DEBUG("Fail to stop TTS: resultl(%d)", ret);
260                   }
261             }
262       }
263
264    DEBUG( "tts_speak\n");
265    DEBUG( "text to say:%s\n", text_to_speak);
266    if ( !text_to_speak ) return;
267    if ( !text_to_speak[0] ) return;
268
269    if((ret = tts_add_text( sd->tts, text_to_speak, NULL, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &speak_id)))
270       {
271          switch(ret)
272             {
273             case TTS_ERROR_INVALID_PARAMETER:
274                DEBUG("FAILED tts_add_text: error: TTS_ERROR_INVALID_PARAMETER");
275                break;
276             case TTS_ERROR_INVALID_STATE:
277                DEBUG("FAILED tts_add_text: error: TTS_ERROR_INVALID_STATE, tts_state: %d", state);
278                break;
279             case TTS_ERROR_INVALID_VOICE:
280                DEBUG("FAILED tts_add_text: error: TTS_ERROR_INVALID_VOICE");
281                break;
282             case TTS_ERROR_OPERATION_FAILED:
283                DEBUG("FAILED tts_add_text: error: TTS_ERROR_OPERATION_FAILED");
284                break;
285             case TTS_ERROR_NOT_SUPPORTED:
286                DEBUG("FAILED tts_add_text: error: TTS_ERROR_NOT_SUPPORTED");
287                break;
288             default:
289                DEBUG("FAILED tts_add_text: error: not recognized");
290             }
291          return;
292       }
293
294    DEBUG("added id to:%d\n", speak_id);
295    last_utt_id = speak_id;
296 }
297
298 Eina_Bool update_supported_voices(void *data)
299 {
300    DEBUG("START");
301    tts_state_e state;
302
303    Service_Data *sd = data;
304
305    int res = tts_get_state(sd->tts, &state);
306
307    if(res != TTS_ERROR_NONE)
308       {
309          DEBUG("CANNOT RETRIVE STATE");
310          return EINA_FALSE;
311       }
312
313    if(state == TTS_STATE_READY)
314       {
315          tts_foreach_supported_voices(sd->tts, get_supported_voices_cb, sd);
316       }
317    else
318       {
319          sd->update_language_list = EINA_TRUE;
320       }
321
322    DEBUG("END")
323    return EINA_TRUE;
324 }
325
326 void state_changed_cb(tts_h tts, tts_state_e previous, tts_state_e current, void* user_data)
327 {
328    if(pause_state)
329       {
330          DEBUG("TTS is currently paused. Resume to start reading");
331          return;
332       }
333
334    DEBUG("++++++++++++++++state_changed_cb\n++++++++++++++++++");
335    DEBUG("current state:%s and previous state:%s\n", get_tts_state(current), get_tts_state(previous));
336    Service_Data *sd = user_data;
337
338    if (TTS_STATE_CREATED == previous && TTS_STATE_READY == current)
339       {
340
341          update_supported_voices(sd);
342
343          char *txt;
344
345          if (!txt_keep_buff) return;
346          if (!eina_strbuf_length_get(txt_keep_buff)) return;
347
348          txt = eina_strbuf_string_steal(txt_keep_buff);
349          eina_strbuf_free(txt_keep_buff);
350          txt_keep_buff = NULL;
351
352          tts_speak(txt, EINA_FALSE);
353          tts_play(sd->tts);
354          free(txt);
355       }
356    else if (current == TTS_STATE_READY || current == TTS_STATE_PAUSED)
357       {
358          DEBUG("TTS state == %s!", get_tts_state(current));
359          tts_play(sd->tts);
360       }
361    else
362       {
363          DEBUG("TTS state != ready or paused!\n");
364       }
365 }
366
367 void spi_stop( void *data)
368 {
369    if(!data)
370       {
371          ERROR("Invalid parameter");
372          return;
373       }
374
375    Service_Data *sd = data;
376    sd->update_language_list = false;
377    free((char*)sd->text_from_dbus);
378    free(sd->current_value);
379    sd->text_from_dbus = NULL;
380    sd->current_value = NULL;
381    tts_stop(sd->tts);
382 }