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