Merge with Tizen 2.3
[platform/core/uifw/stt.git] / server / sttd_recorder.c
1 /*
2 *  Copyright (c) 2011-2014 Samsung Electronics Co., Ltd All Rights Reserved 
3 *  Licensed under the Apache License, Version 2.0 (the "License");
4 *  you may not use this file except in compliance with the License.
5 *  You may obtain a copy of the License at
6 *  http://www.apache.org/licenses/LICENSE-2.0
7 *  Unless required by applicable law or agreed to in writing, software
8 *  distributed under the License is distributed on an "AS IS" BASIS,
9 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 *  See the License for the specific language governing permissions and
11 *  limitations under the License.
12 */
13
14 #include <audio_io.h>
15 #include <Ecore.h>
16 #include <math.h>
17 #include <sound_manager.h>
18
19 #include "stt_defs.h"
20 #include "sttd_recorder.h"
21 #include "sttd_main.h"
22 #include "sttp.h"
23
24
25 #define FRAME_LENGTH 160
26 #define BUFFER_LENGTH FRAME_LENGTH * 2
27
28 typedef enum {
29         STTD_RECORDER_STATE_NONE = -1,
30         STTD_RECORDER_STATE_READY = 0,  /**< Recorder is ready to start */
31         STTD_RECORDER_STATE_RECORDING   /**< In the middle of recording */
32 } sttd_recorder_state;
33
34 typedef struct {
35         int                     engine_id;
36         audio_in_h              audio_h;
37         sttp_audio_type_e       audio_type;
38 }stt_recorder_s;
39
40 static GSList *g_recorder_list;
41
42 static int g_recording_engine_id;
43
44 static stt_recorder_audio_cb    g_audio_cb;
45
46 static stt_recorder_interrupt_cb        g_interrupt_cb;
47
48 static sttd_recorder_state      g_recorder_state = STTD_RECORDER_STATE_NONE;
49
50 static FILE* g_pFile_vol;
51
52 static int g_buffer_count;
53
54 /* Sound buf save for test */
55 /*
56 #define BUF_SAVE_MODE
57 */
58 #ifdef BUF_SAVE_MODE
59 static char g_temp_file_name[128] = {'\0',};
60
61 static FILE* g_pFile;
62
63 static int g_count = 1;
64 #endif 
65
66 const char* __stt_get_session_interrupt_code(sound_session_interrupted_code_e code)
67 {
68         switch(code) {
69         case SOUND_SESSION_INTERRUPTED_COMPLETED:               return "SOUND_SESSION_INTERRUPTED_COMPLETED";
70         case SOUND_SESSION_INTERRUPTED_BY_MEDIA:                return "SOUND_SESSION_INTERRUPTED_BY_MEDIA";
71         case SOUND_SESSION_INTERRUPTED_BY_CALL:                 return "SOUND_SESSION_INTERRUPTED_BY_CALL";
72         case SOUND_SESSION_INTERRUPTED_BY_EARJACK_UNPLUG:       return "SOUND_SESSION_INTERRUPTED_BY_EARJACK_UNPLUG";
73         case SOUND_SESSION_INTERRUPTED_BY_RESOURCE_CONFLICT:    return "SOUND_SESSION_INTERRUPTED_BY_RESOURCE_CONFLICT";
74         case SOUND_SESSION_INTERRUPTED_BY_ALARM:                return "SOUND_SESSION_INTERRUPTED_BY_ALARM";
75         case SOUND_SESSION_INTERRUPTED_BY_EMERGENCY:            return "SOUND_SESSION_INTERRUPTED_BY_EMERGENCY";
76         case SOUND_SESSION_INTERRUPTED_BY_NOTIFICATION:         return "SOUND_SESSION_INTERRUPTED_BY_NOTIFICATION";
77         default:
78                 return "Undefined error code";
79         }
80 }
81
82 void __sttd_recorder_sound_interrupted_cb(sound_session_interrupted_code_e code, void *user_data)
83 {
84         SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Get the interrupt code from sound mgr : %s", 
85                 __stt_get_session_interrupt_code(code));
86
87         if (SOUND_SESSION_INTERRUPTED_COMPLETED == code || SOUND_SESSION_INTERRUPTED_BY_EARJACK_UNPLUG == code)
88                 return;
89
90         if (NULL != g_interrupt_cb) {
91                 g_interrupt_cb();
92         }
93         return;
94 }
95
96 int sttd_recorder_initialize(stt_recorder_audio_cb audio_cb, stt_recorder_interrupt_cb interrupt_cb)
97 {
98         if (NULL == audio_cb || NULL == interrupt_cb) {
99                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Input param is NOT valid");
100                 return STTD_ERROR_INVALID_PARAMETER;
101         }
102
103         if (STTD_RECORDER_STATE_NONE != g_recorder_state) {
104                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Current state of recorder is recording");
105                 return STTD_ERROR_INVALID_STATE;
106         }
107         
108         g_audio_cb = audio_cb;
109         g_interrupt_cb = interrupt_cb;
110         g_recorder_state = STTD_RECORDER_STATE_NONE;
111         g_recording_engine_id = -1;
112
113         if (0 != sound_manager_set_session_type(SOUND_SESSION_TYPE_MEDIA)) {
114                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to set exclusive session");
115         }
116
117         if (0 != sound_manager_set_session_interrupted_cb(__sttd_recorder_sound_interrupted_cb, NULL)) {
118                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to set sound interrupt callback");
119         }
120
121         return 0;
122 }
123
124 int sttd_recorder_deinitialize()
125 {
126         if (0 != sound_manager_unset_session_interrupted_cb()) {
127                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to unset sound interrupt callback");
128         }
129
130         /* Remove all recorder */
131         GSList *iter = NULL;
132         stt_recorder_s *recorder = NULL;
133
134         iter = g_slist_nth(g_recorder_list, 0);
135
136         while (NULL != iter) {
137                 recorder = iter->data;
138
139                 if (NULL != recorder) {
140                         g_recorder_list = g_slist_remove(g_recorder_list, recorder);
141                         audio_in_destroy(recorder->audio_h);
142
143                         free(recorder);
144                 }
145
146                 iter = g_slist_nth(g_recorder_list, 0);
147         }
148
149         if (0 == access(STT_AUDIO_VOLUME_PATH, R_OK)) {
150                 if (0 != remove(STT_AUDIO_VOLUME_PATH)) {
151                         SLOG(LOG_WARN, TAG_STTD, "[Recorder WARN] Fail to remove volume file"); 
152                 }
153         }
154
155         g_recorder_state = STTD_RECORDER_STATE_NONE;
156
157         return 0;
158 }
159
160 static stt_recorder_s* __get_recorder(int engine_id)
161 {
162         GSList *iter = NULL;
163         stt_recorder_s *recorder = NULL;
164
165         iter = g_slist_nth(g_recorder_list, 0);
166
167         while (NULL != iter) {
168                 recorder = iter->data;
169
170                 if (recorder->engine_id == engine_id) {
171                         return recorder;
172                 }
173
174                 iter = g_slist_next(iter);
175         }
176
177         return NULL;
178 }
179
180 int sttd_recorder_set_audio_session()
181 {
182         return 0;
183 }
184
185 int sttd_recorder_unset_audio_session()
186 {
187         return 0;
188 }
189
190 int sttd_recorder_create(int engine_id, sttp_audio_type_e type, int channel, unsigned int sample_rate)
191 {
192         /* Check engine id is valid */
193         if (NULL != __get_recorder(engine_id)) {
194                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is already registered");
195                 return STTD_ERROR_INVALID_PARAMETER;
196         }
197
198         audio_channel_e audio_ch;
199         audio_sample_type_e audio_type;
200         audio_in_h temp_in_h;
201
202         switch(channel) {
203                 case 1: audio_ch = AUDIO_CHANNEL_MONO;          break;
204                 case 2: audio_ch = AUDIO_CHANNEL_STEREO;        break;
205                 default:
206                         SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Input channel is not supported");
207                         return STTD_ERROR_OPERATION_FAILED;
208                         break;
209         }
210
211         switch (type) {
212                 case STTP_AUDIO_TYPE_PCM_S16_LE:        audio_type = AUDIO_SAMPLE_TYPE_S16_LE;  break;
213                 case STTP_AUDIO_TYPE_PCM_U8:            audio_type = AUDIO_SAMPLE_TYPE_U8;      break;
214                 default:        
215                         SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Invalid Audio Type"); 
216                         return STTD_ERROR_OPERATION_FAILED;
217                         break;
218         }
219
220         int ret;
221         ret = audio_in_create(sample_rate, audio_ch, audio_type, &temp_in_h);
222         if (AUDIO_IO_ERROR_NONE != ret) {
223                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to create audio handle : %d", ret);
224                 return STTD_ERROR_OPERATION_FAILED;
225         }
226
227         stt_recorder_s* recorder;
228         recorder = (stt_recorder_s*)calloc(1, sizeof(stt_recorder_s));
229
230         recorder->engine_id = engine_id;
231         recorder->audio_h = temp_in_h;
232         recorder->audio_type = type;
233         
234         g_recorder_list = g_slist_append(g_recorder_list, recorder);
235
236         g_recorder_state = STTD_RECORDER_STATE_READY;
237
238         return 0;
239 }
240
241 int sttd_recorder_destroy(int engine_id)
242 {
243         /* Check engine id is valid */
244         stt_recorder_s* recorder;
245         recorder = __get_recorder(engine_id);
246         if (NULL == recorder) {
247                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
248                 return STTD_ERROR_INVALID_PARAMETER;
249         }
250
251         int ret;
252         if (STTD_RECORDER_STATE_RECORDING == g_recorder_state) {
253                 ret = audio_in_unprepare(recorder->audio_h);
254                 if (AUDIO_IO_ERROR_NONE != ret) {
255                         SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to unprepare audioin : %d", ret);
256                 }
257
258                 g_recorder_state = STTD_RECORDER_STATE_READY;
259         }
260
261         ret = audio_in_destroy(recorder->audio_h);
262         if (AUDIO_IO_ERROR_NONE != ret) {
263                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to destroy audioin : %d", ret);
264         }
265
266         g_recorder_list = g_slist_remove(g_recorder_list, recorder);
267
268         free(recorder);
269
270         return 0;
271 }
272
273 static float get_volume_decibel(char* data, int size, sttp_audio_type_e type)
274 {
275         #define MAX_AMPLITUDE_MEAN_16 23170.115738161934
276         #define MAX_AMPLITUDE_MEAN_08    89.803909382810
277
278         int i, depthByte;
279         int count = 0;
280
281         float db = 0.0;
282         float rms = 0.0;
283         unsigned long long square_sum = 0;
284
285         if (type == STTP_AUDIO_TYPE_PCM_S16_LE)
286                 depthByte = 2;
287         else
288                 depthByte = 1;
289
290         for (i = 0; i < size; i += (depthByte<<1)) {
291                 if (depthByte == 2) {
292                         short pcm16 = 0;
293                         memcpy(&pcm16, data + i, sizeof(short));
294                         square_sum += pcm16 * pcm16;
295                 } else {
296                         char pcm8 = 0;
297                         memcpy(&pcm8, data + i, sizeof(char));
298                         square_sum += pcm8 * pcm8;
299                 }
300                 count++;
301         }
302
303         if (0 == count)
304                 rms = 0.0;
305         else
306                 rms = sqrt(square_sum/count);
307
308         if (depthByte == 2)
309                 db = 20 * log10(rms/MAX_AMPLITUDE_MEAN_16);
310         else
311                 db = 20 * log10(rms/MAX_AMPLITUDE_MEAN_08);
312
313         return db;
314 }
315
316 Eina_Bool __read_audio_func(void *data)
317 {
318         int read_byte = -1;
319         static char g_buffer[BUFFER_LENGTH];
320
321         /* Check engine id is valid */
322         stt_recorder_s* recorder;
323         recorder = __get_recorder(g_recording_engine_id);
324         if (NULL == recorder) {
325                 return EINA_FALSE;
326         }
327
328         if (STTD_RECORDER_STATE_READY == g_recorder_state) {
329                 SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Exit audio reading func");
330                 return EINA_FALSE;
331         }
332
333         read_byte = audio_in_read(recorder->audio_h, g_buffer, BUFFER_LENGTH);
334         if (0 > read_byte) {
335                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Fail to read audio : %d", read_byte);
336                 g_recorder_state = STTD_RECORDER_STATE_READY;
337                 return EINA_FALSE;
338         }
339
340         if (0 != g_audio_cb(g_buffer, read_byte)) {
341                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Fail audio callback");
342                 sttd_recorder_stop(g_recording_engine_id);
343                 return EINA_FALSE;
344         }
345
346         float vol_db = get_volume_decibel(g_buffer, BUFFER_LENGTH, recorder->audio_type);
347
348         rewind(g_pFile_vol);
349
350         fwrite((void*)(&vol_db), sizeof(vol_db), 1, g_pFile_vol);
351
352         /* Audio read log */
353         if (0 == g_buffer_count % 50) {
354                 SLOG(LOG_DEBUG, TAG_STTD, "[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, read_byte);
355                 
356                 if (100000 == g_buffer_count) {
357                         g_buffer_count = 0;
358                 }
359         }
360
361         g_buffer_count++;
362
363 #ifdef BUF_SAVE_MODE
364         /* write pcm buffer */
365         fwrite(g_buffer, 1, BUFFER_LENGTH, g_pFile);
366 #endif
367
368         return EINA_TRUE;
369 }
370
371 int sttd_recorder_start(int engine_id)
372 {
373         if (STTD_RECORDER_STATE_RECORDING == g_recorder_state)
374                 return 0;
375
376         /* Check engine id is valid */
377         stt_recorder_s* recorder;
378         recorder = __get_recorder(engine_id);
379         if (NULL == recorder) {
380                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
381                 return STTD_ERROR_INVALID_PARAMETER;
382         }
383
384         int ret = -1; 
385         ret = audio_in_prepare(recorder->audio_h);
386         if (AUDIO_IO_ERROR_NONE != ret) {
387                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to start audio : %d", ret);
388                 return STTD_ERROR_RECORDER_BUSY;
389         }
390
391         /* Add ecore timer to read audio data */
392         ecore_timer_add(0, __read_audio_func, NULL);
393
394         g_recorder_state = STTD_RECORDER_STATE_RECORDING;
395         g_recording_engine_id = engine_id;
396
397         g_pFile_vol = fopen(STT_AUDIO_VOLUME_PATH, "wb+");
398         if (!g_pFile_vol) {
399                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to create Volume File");
400                 return -1;
401         }
402
403         g_buffer_count = 0;
404
405 #ifdef BUF_SAVE_MODE
406         g_count++;
407
408         snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/stt_temp_%d_%d", getpid(), g_count);
409         SECURE_SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Temp file name=[%s]", g_temp_file_name);
410
411         /* open test file */
412         g_pFile = fopen(g_temp_file_name, "wb+");
413         if (!g_pFile) {
414                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] File not found!");
415                 return -1;
416         }       
417 #endif
418
419         return 0;
420 }
421
422 int sttd_recorder_stop(int engine_id)
423 {
424         if (STTD_RECORDER_STATE_READY == g_recorder_state)
425                 return 0;
426
427         /* Check engine id is valid */
428         stt_recorder_s* recorder;
429         recorder = __get_recorder(engine_id);
430         if (NULL == recorder) {
431                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
432                 return STTD_ERROR_INVALID_PARAMETER;
433         }
434
435         int ret; 
436         ret = audio_in_unprepare(recorder->audio_h);
437         if (AUDIO_IO_ERROR_NONE != ret) {
438                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to unprepare audioin : %d", ret);
439         }
440
441         g_recorder_state = STTD_RECORDER_STATE_READY;
442         g_recording_engine_id = -1;
443
444         fclose(g_pFile_vol);
445
446 #ifdef BUF_SAVE_MODE
447         fclose(g_pFile);
448 #endif  
449
450         return 0;
451 }
452
453 int sttd_recorder_set_ignore_session(int engine_id)
454 {
455         if (STTD_RECORDER_STATE_READY != g_recorder_state) {
456                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Record is working.");
457                 return -1;
458         }
459
460         /* Check engine id is valid */
461         stt_recorder_s* recorder;
462         recorder = __get_recorder(engine_id);
463         if (NULL == recorder) {
464                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
465                 return STTD_ERROR_INVALID_PARAMETER;
466         }
467
468         int ret = audio_in_ignore_session(recorder->audio_h);
469         if (AUDIO_IO_ERROR_NONE != ret) {
470                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to ignore session : %d", ret);
471                 return STTD_ERROR_OPERATION_FAILED;
472         }
473
474         return 0;
475 }