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