363292352c26421990eceacf004556118735c857
[platform/core/uifw/inputdelegator.git] / src / SttManager.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 #include <assert.h>
18 #include <vconf.h>
19 #include <vconf-keys.h>
20 #include <sound_manager.h>
21
22 #include "Debug.h"
23 #include "SttManager.h"
24
25 using namespace is::stt;
26
27 enum {
28         READY = 0x0001,
29         RECORDING = 0x0010,
30         PROCESSING = 0x0100,
31         CREATE = 0x1000
32 };
33
34 static sound_stream_info_h g_stream_info_h = NULL;
35
36 static inline const char *stt_state_str(stt_state_e cur) {
37         if (cur == STT_STATE_CREATED)
38                 return (const char *) "STT_STATE_CREATED";
39
40         else if (cur == STT_STATE_READY)
41                 return (const char *) "STT_STATE_READY";
42
43         else if (cur == STT_STATE_RECORDING)
44                 return (const char *) "STT_STATE_RECORDING";
45
46         else if (cur == STT_STATE_PROCESSING)
47                 return (const char *) "STT_STATE_PROCESSING";
48
49         else
50                 return (const char *) "ABNORMAL CASE";
51 }
52
53 static void player_focus_state_cb(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state,
54                                   sound_stream_focus_change_reason_e reason_for_change, int sound_behavior, const char *extra_info, void *user_data)
55 {
56 }
57
58 SttManager::SttManager(ISttFeedback& feedback)
59 : ifeedback(feedback),
60   iscancelled(false)
61 {
62         try {
63                 /**
64                 * Create stt handle.
65                 *
66                 */
67                 int ret = stt_create(&handle);
68
69                 if(ret != STT_ERROR_NONE)
70                         throw SttException(ret, ErrorString((stt_error_e)ret));
71
72                 ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_VOICE_RECOGNITION, player_focus_state_cb, NULL, &g_stream_info_h);
73                 if (SOUND_MANAGER_ERROR_NONE != ret) {
74                         LOGW("Fail to create stream info. ret : %d", ret);
75                 }
76
77                 /**
78                 * Set default properties
79                 *
80                 */
81                 EnableFeedback();
82         }
83         catch(SttException &e) {
84                 PRINTFUNC(DLOG_ERROR, "reason : %s", e.what());
85                 assert(0);
86         }
87 }
88
89 SttManager::~SttManager() {
90         try {
91                 EnableFeedback(false);
92
93                 Cancel();
94                 UnPrepare();
95         }
96         catch(SttException &e) {
97                 PRINTFUNC(DLOG_ERROR, "reason : %s", e.what());
98                 stt_destroy(handle);
99         }
100
101         ReleaseSoundFocus();
102
103         sound_manager_destroy_stream_information(g_stream_info_h);
104 }
105
106 void SttManager::Prepare() {
107         /**
108         * Prepare stt service.
109         *
110         */
111         int ret = stt_prepare(handle);
112
113         if(ret != STT_ERROR_NONE)
114                 throw SttException(ret, ErrorString((stt_error_e)ret));
115 }
116
117 void SttManager::UnPrepare() {
118    /**
119     * UnPrepare stt service.
120     *
121     */
122    int ret = stt_unprepare(handle);
123
124    if (ret != STT_ERROR_NONE)
125            throw SttException(ret, ErrorString((stt_error_e)ret));
126 }
127
128 void SttManager::Start() {
129         if(!Validate((int) READY)) {
130             throw SttException((int) STT_ERROR_INVALID_STATE, "INVALID STATE - !STT_STATE_READY");
131         }
132
133         PRINTFUNC(DLOG_DEBUG, "HERE");
134
135         iscancelled = false;
136
137         /**
138         * Start stt service.
139         *
140         */
141         asrtype = STT_RECOGNITION_TYPE_FREE_PARTIAL;
142         int ret;
143
144         ret = sound_manager_acquire_focus(g_stream_info_h, (sound_stream_focus_mask_e)(SOUND_STREAM_FOCUS_FOR_PLAYBACK | SOUND_STREAM_FOCUS_FOR_RECORDING), SOUND_BEHAVIOR_NONE, NULL);
145         if (SOUND_MANAGER_ERROR_NONE != ret) {
146                 LOGW("Fail to acquire playback or recording focus. ret : %d, stream handle : %p", ret, g_stream_info_h);
147         }
148
149         ret = stt_start(handle, language.c_str(), asrtype.c_str());
150
151         if(ret != STT_ERROR_NONE)
152                 throw SttException(ret, ErrorString((stt_error_e)ret));
153 }
154
155 void SttManager::Stop() {
156         if(!Validate((int) RECORDING)) {
157                 throw SttException((int) STT_ERROR_INVALID_STATE, "INVALID STATE - !STT_STATE_RECORDING");
158         }
159
160         /**
161         * Stop stt service.
162         *
163         */
164         int ret = stt_stop(handle);
165
166         if(ret != STT_ERROR_NONE)
167                 throw SttException(ret, ErrorString((stt_error_e)ret));
168 }
169
170 void SttManager::Cancel() {
171         if(iscancelled) {
172                 PRINTFUNC(DLOG_WARN, "iscancelled (%d)", iscancelled);
173                 return;
174         }
175
176         if(!Validate((int) (RECORDING|PROCESSING))) {
177                 throw SttException((int) STT_ERROR_INVALID_STATE, "INVALID STATE - !(STT_STATE_RECORDING or STT_STATE_PROCESSING)");
178         }
179
180         /**
181         * Cancel stt service (recording, processing)
182         *
183         */
184         int ret = stt_cancel(handle);
185
186         if(ret != STT_ERROR_NONE)
187                 throw SttException(ret, ErrorString((stt_error_e)ret));
188
189         iscancelled = true;
190         PRINTFUNC(DLOG_INFO, "iscancelled (%d)", iscancelled);
191
192         ifeedback.SttIdle();
193 }
194
195
196 bool SttManager::Validate(int state) {
197         stt_state_e cur;
198
199         int ret = stt_get_state(handle, &cur);
200         if (ret != STT_ERROR_NONE) {
201                 return false;
202         }
203
204         PRINTFUNC(DLOG_DEBUG, "validate state - %d", state);
205         PRINTFUNC(DLOG_DEBUG, "stt deamon state - %s",
206                 cur == STT_STATE_CREATED ? "STT_STATE_CREATED" :
207                 cur == STT_STATE_READY ? "STT_STATE_READY" :
208                 cur == STT_STATE_RECORDING ? "STT_STATE_RECORDING" :
209                 cur == STT_STATE_PROCESSING ? "STT_STATE_PROCESSING" : "ABNORMAL");
210
211         switch(cur) {
212                 case STT_STATE_CREATED :
213                         if (state & CREATE) return true;
214                         break;
215                 case STT_STATE_READY :
216                         if (state & READY) return true;
217                         break;
218                 case STT_STATE_RECORDING :
219                         if (state & RECORDING) return true;
220                         break;
221                 case STT_STATE_PROCESSING :
222                         if (state & PROCESSING) return true;
223                         break;
224                 default :
225                         break;
226         }
227
228         return false;
229 }
230
231 void SttManager::Initialize() {
232    /** Todo. add routine to intialize */
233 }
234
235 void SttManager::PrintResultState(stt_result_event_e result_type)
236 {
237         std::string result;
238
239         switch (result_type) {
240                 case STT_RESULT_EVENT_FINAL_RESULT :
241                         result = "STT_RESULT_EVENT_FINAL_RESULT";
242                         break;
243                 case STT_RESULT_EVENT_PARTIAL_RESULT :
244                         result = "STT_RESULT_EVENT_PARTIAL_RESULT";
245                         break;
246                 case STT_RESULT_EVENT_ERROR :
247                         result = "STT_RESULT_EVENT_ERROR";
248                         break;
249                 default :
250                         result = "UNKNOWN";
251                         break;
252         }
253         PRINTFUNC(DLOG_INFO, "result type : %s", result.c_str());
254 }
255
256 void SttManager::on_result(
257    stt_h handle,
258    stt_result_event_e event,
259    const char** data,
260    int size,
261    const char* msg,
262    void *user_data) {
263    PrintResultState(event);
264
265    if (!user_data) {
266                 PRINTFUNC(DLOG_ERROR, "user_data null");
267                 throw SttException((int)STT_ERROR_INVALID_PARAMETER, "invalid self reference");
268    }
269
270    SttManager& manager = *((SttManager *) user_data);
271
272    std::vector<std::string> results;
273
274    PRINTFUNC(DLOG_INFO, "result size : %d, msg : %s", size, msg);
275
276    for (size_t i = 0; i < (size_t) size; i++) {
277         if (data[i]) {
278                 results.push_back(std::string(data[i]));
279         }
280
281         if (msg)
282            manager.ifeedback.OnResult(manager.asrtype, event, results, std::string(msg));
283         else
284            manager.ifeedback.OnResult(manager.asrtype, event, results, std::string(""));
285    }
286 }
287
288 void SttManager::PrintState(stt_state_e previous, stt_state_e current)
289 {
290         std::string prev;
291         std::string curr;
292
293         switch (previous) {
294                 case STT_STATE_READY :
295                         prev = "STT_STATE_READY";
296                         break;
297                 case STT_STATE_CREATED :
298                         prev = "STT_STATE_CREATED";
299                         break;
300                 case STT_STATE_RECORDING :
301                         prev = "STT_STATE_RECORDING";
302                         break;
303                 case STT_STATE_PROCESSING :
304                         prev = "STT_STATE_PROCESSING";
305                         break;
306                 default :
307                         prev = "UNKNOWN";
308                         break;
309         }
310
311         switch (current) {
312                 case STT_STATE_READY :
313                         curr = "STT_STATE_READY";
314                         break;
315                 case STT_STATE_CREATED :
316                         curr = "STT_STATE_CREATED";
317                         break;
318                 case STT_STATE_RECORDING :
319                         curr = "STT_STATE_RECORDING";
320                         break;
321                 case STT_STATE_PROCESSING :
322                         curr = "STT_STATE_PROCESSING";
323                         break;
324                 default :
325                         curr = "UNKNOWN";
326                         break;
327         }
328         PRINTFUNC(DLOG_INFO, "previous: %s(%d), current: %s(%d)", prev.c_str(), previous, curr.c_str(), current);
329 }
330
331 void SttManager::on_state_changed(
332         stt_h handle,
333         stt_state_e previous,
334         stt_state_e current,
335         void *user_data) {
336         PrintState(previous, current);
337
338         if (!user_data)
339                 throw SttException((int)STT_ERROR_INVALID_PARAMETER, "invalid self reference");
340
341         SttManager& manager = *((SttManager *) user_data);
342
343         if (current== STT_STATE_READY) {
344                 if (previous == STT_STATE_RECORDING ||
345                         previous == STT_STATE_PROCESSING) {
346                         ReleaseSoundFocus();
347                 }
348
349                 if (previous == STT_STATE_CREATED) {
350                         manager.EnableSilenceDetection();
351                         manager.ifeedback.AutoStart();
352                 } else if (previous == STT_STATE_RECORDING) {
353                         std::string msg;
354                         std::vector<std::string> results;
355                         manager.ifeedback.OnResult(manager.asrtype, STT_RESULT_EVENT_ERROR, results, msg);
356                 } else {
357                         manager.ifeedback.SttIdle();
358                 }
359         } else if (current == STT_STATE_RECORDING) {
360                         manager.ifeedback.SttRecording();
361         } else if (current == STT_STATE_PROCESSING) {
362                 if (!manager.iscancelled) {
363                         PRINTFUNC(DLOG_INFO, "iscancelled (%d)", manager.iscancelled);
364                         manager.ifeedback.SttProcessing();
365                 } else {
366                         manager.iscancelled = false;
367                         PRINTFUNC(DLOG_INFO, "iscancelled (%d)", manager.iscancelled);
368                 }
369         }
370 }
371
372 void SttManager::PrintErrorState(stt_error_e reason)
373 {
374         std::string res;
375
376         switch (reason) {
377                 case STT_ERROR_OUT_OF_MEMORY :
378                         res = "STT_ERROR_OUT_OF_MEMORY";
379                         break;
380                 case STT_ERROR_IO_ERROR :
381                         res = "STT_ERROR_IO_ERROR";
382                         break;
383                 case STT_ERROR_INVALID_PARAMETER :
384                         res = "STT_ERROR_INVALID_PARAMETER";
385                         break;
386                 case STT_ERROR_TIMED_OUT :
387                         res = "STT_ERROR_TIMED_OUT";
388                         break;
389                 case STT_ERROR_RECORDER_BUSY :
390                         res = "STT_ERROR_RECORDER_BUSY";
391                         break;
392                 case STT_ERROR_OUT_OF_NETWORK :
393                         res = "STT_ERROR_OUT_OF_NETWORK";
394                         break;
395                 case STT_ERROR_PERMISSION_DENIED :
396                         res = "STT_ERROR_PERMISSION_DENIED";
397                         break;
398                 case STT_ERROR_NOT_SUPPORTED :
399                         res = "STT_ERROR_NOT_SUPPORTED";
400                         break;
401                 case STT_ERROR_INVALID_STATE :
402                         res = "STT_ERROR_INVALID_STATE";
403                         break;
404                 case STT_ERROR_INVALID_LANGUAGE :
405                         res = "STT_ERROR_INVALID_LANGUAGE";
406                         break;
407                 case STT_ERROR_ENGINE_NOT_FOUND :
408                         res = "STT_ERROR_ENGINE_NOT_FOUND";
409                         break;
410                 case STT_ERROR_OPERATION_FAILED :
411                         res = "STT_ERROR_OPERATION_FAILED";
412                         break;
413                 case STT_ERROR_NOT_SUPPORTED_FEATURE :
414                         res = "STT_ERROR_NOT_SUPPORTED_FEATURE";
415                         break;
416                 default :
417                         res = "UNKNOWN ERROR REASON";
418                         break;
419         }
420         PRINTFUNC(DLOG_INFO, "Error reason %s(%d)", res.c_str(), reason);
421 }
422
423 void SttManager::on_error(
424    stt_h handle,
425    stt_error_e reason,
426    void *user_data) {
427    PRINTFUNC(DLOG_INFO, "stt-daemon error (%d)", reason);
428
429    if (!user_data)
430                 throw SttException((int)STT_ERROR_INVALID_PARAMETER, "invalid self reference");
431
432    SttManager& manager = *((SttManager *) user_data);
433    manager.ifeedback.OnError(reason);
434 }
435
436 void SttManager::SetLanguage(std::string language) {
437    this->language = language;
438 }
439
440 void SttManager::EnableFeedback(bool enabled) {
441    int ret = STT_ERROR_NONE;
442
443    void *udata = static_cast<void *>(this);
444
445    if (enabled) {
446       ret = stt_set_recognition_result_cb(handle, on_result, udata);
447       if (STT_ERROR_NONE != ret)
448                 throw SttException(ret, ErrorString((stt_error_e)ret));
449
450       ret = stt_set_error_cb(handle, on_error, udata);
451       if (STT_ERROR_NONE != ret)
452                 throw SttException(ret, ErrorString((stt_error_e)ret));
453
454       ret = stt_set_state_changed_cb(handle, on_state_changed, udata);
455       if (STT_ERROR_NONE != ret)
456                 throw SttException(ret, ErrorString((stt_error_e)ret));
457    } else {
458       ret = stt_unset_error_cb(handle);
459       if (STT_ERROR_NONE != ret)
460                 throw SttException(ret, ErrorString((stt_error_e)ret));
461
462       ret = stt_unset_state_changed_cb(handle);
463       if (STT_ERROR_NONE != ret)
464                 throw SttException(ret, ErrorString((stt_error_e)ret));
465
466       ret = stt_unset_recognition_result_cb(handle);
467       if (STT_ERROR_NONE != ret)
468                 throw SttException(ret, ErrorString((stt_error_e)ret));
469    }
470 }
471
472 const char* SttManager::ErrorString(int ecode) {
473    const char *str = NULL;
474
475    switch (ecode) {
476       case STT_ERROR_OUT_OF_MEMORY:
477          str = (const char *) "STT_ERROR_OUT_OF_MEMORY";
478          break;
479       case STT_ERROR_IO_ERROR:
480          str = (const char *) "STT_ERROR_IO_ERROR";
481          break;
482       case STT_ERROR_INVALID_PARAMETER:
483          str = (const char *) "STT_ERROR_INVALID_PARAMETER";
484          break;
485       case STT_ERROR_TIMED_OUT:
486          str = (const char *) "STT_ERROR_TIMED_OUT";
487          break;
488       case STT_ERROR_RECORDER_BUSY:
489          str = (const char *) "STT_ERROR_RECORDER_BUSY";
490          break;
491       case STT_ERROR_OUT_OF_NETWORK:
492          str = (const char *) "STT_ERROR_OUT_OF_NETWORK";
493          break;
494       case STT_ERROR_INVALID_STATE:
495          str = (const char *) " STT_ERROR_INVALID_STATE";
496          break;
497       case STT_ERROR_INVALID_LANGUAGE:
498          str = (const char *) "STT_ERROR_INVALID_LANGUAGE";
499          break;
500       case STT_ERROR_ENGINE_NOT_FOUND:
501          str = (const char *) "STT_ERROR_ENGINE_NOT_FOUND";
502          break;
503       case STT_ERROR_OPERATION_FAILED:
504          str = (const char *) "STT_ERROR_OPERATION_FAILED";
505          break;
506       case STT_ERROR_NOT_SUPPORTED_FEATURE:
507          str = (const char *) "STT_ERROR_NOT_SUPPORTED_FEATURE";
508          break;
509    }
510    return str;
511 }
512
513 void SttManager::SoundFeedback() {
514    int is_sound = 0;
515    int is_sound_vibe = 0;
516
517    if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &is_sound)) {
518       PRINTFUNC(DLOG_ERROR, "get sound status failed.");
519    }
520
521    if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &is_sound_vibe)) {
522       PRINTFUNC(DLOG_ERROR, "get vibe status failed.");
523    }
524
525    if (is_sound || is_sound_vibe) {
526       stt_set_start_sound(handle, "/usr/share/ise-voice-input/audio/voice_start.wav");
527       stt_set_stop_sound(handle, "/usr/share/ise-voice-input/audio/voice_stop.wav");
528    } else {
529       stt_unset_start_sound(handle);
530       stt_unset_stop_sound(handle);
531    }
532 }
533
534
535
536 void SttManager::EnableSilenceDetection(bool enabled) {
537         stt_option_silence_detection_e s_option;
538
539         if (enabled)
540                 s_option = STT_OPTION_SILENCE_DETECTION_TRUE;
541         else
542                 s_option = STT_OPTION_SILENCE_DETECTION_FALSE;
543
544         int ret = stt_set_silence_detection(handle, s_option);
545         if (STT_ERROR_NONE != ret) {
546                 PRINTFUNC(
547                         DLOG_ERROR,
548                         "error(%d) = %s",
549                         ret,
550                         ErrorString((stt_error_e) ret));
551         } else {
552                 PRINTFUNC(NO_PRINT, "stt_set_silence_detection Successful");
553         }
554 }
555
556 void SttManager::ReleaseSoundFocus()
557 {
558         int ret = sound_manager_release_focus(g_stream_info_h, (sound_stream_focus_mask_e)(SOUND_STREAM_FOCUS_FOR_PLAYBACK | SOUND_STREAM_FOCUS_FOR_RECORDING), SOUND_BEHAVIOR_NONE, NULL);
559         if (SOUND_MANAGER_ERROR_NONE != ret) {
560                 LOGW("Fail to release playback or recording focus. ret : %d", ret);
561         }
562 }