Update IPC
[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         if (NULL == recorder) {
230                 audio_in_destroy(temp_in_h);
231                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to allocate memory");
232                 return STTD_ERROR_OUT_OF_MEMORY;
233         }
234
235         recorder->engine_id = engine_id;
236         recorder->audio_h = temp_in_h;
237         recorder->audio_type = type;
238         
239         g_recorder_list = g_slist_append(g_recorder_list, recorder);
240
241         g_recorder_state = STTD_RECORDER_STATE_READY;
242
243         return 0;
244 }
245
246 int sttd_recorder_destroy(int engine_id)
247 {
248         /* Check engine id is valid */
249         stt_recorder_s* recorder;
250         recorder = __get_recorder(engine_id);
251         if (NULL == recorder) {
252                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
253                 return STTD_ERROR_INVALID_PARAMETER;
254         }
255
256         int ret;
257         if (STTD_RECORDER_STATE_RECORDING == g_recorder_state) {
258                 ret = audio_in_unprepare(recorder->audio_h);
259                 if (AUDIO_IO_ERROR_NONE != ret) {
260                         SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to unprepare audioin : %d", ret);
261                 }
262
263                 g_recorder_state = STTD_RECORDER_STATE_READY;
264         }
265
266         ret = audio_in_destroy(recorder->audio_h);
267         if (AUDIO_IO_ERROR_NONE != ret) {
268                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to destroy audioin : %d", ret);
269         }
270
271         g_recorder_list = g_slist_remove(g_recorder_list, recorder);
272
273         free(recorder);
274
275         return 0;
276 }
277
278 static float get_volume_decibel(char* data, int size, sttp_audio_type_e type)
279 {
280         #define MAX_AMPLITUDE_MEAN_16   32768
281         #define MAX_AMPLITUDE_MEAN_08   128
282
283         int i, depthByte;
284         int count = 0;
285
286         float db = 0.0;
287         float rms = 0.0;
288         unsigned long long square_sum = 0;
289
290         if (type == STTP_AUDIO_TYPE_PCM_S16_LE)
291                 depthByte = 2;
292         else
293                 depthByte = 1;
294
295         for (i = 0; i < size; i += (depthByte<<1)) {
296                 if (depthByte == 2) {
297                         short pcm16 = 0;
298                         memcpy(&pcm16, data + i, sizeof(short));
299                         square_sum += pcm16 * pcm16;
300                 } else {
301                         char pcm8 = 0;
302                         memcpy(&pcm8, data + i, sizeof(char));
303                         square_sum += pcm8 * pcm8;
304                 }
305                 count++;
306         }
307
308         if (0 == count)
309                 rms = 0.0;
310         else
311                 rms = sqrt(square_sum/count);
312
313         if (depthByte == 2)
314                 db = 20 * log10(rms/MAX_AMPLITUDE_MEAN_16);
315         else
316                 db = 20 * log10(rms/MAX_AMPLITUDE_MEAN_08);
317
318         return db;
319 }
320
321 Eina_Bool __read_audio_func(void *data)
322 {
323         int read_byte = -1;
324         static char g_buffer[BUFFER_LENGTH];
325
326         /* Check engine id is valid */
327         stt_recorder_s* recorder;
328         recorder = __get_recorder(g_recording_engine_id);
329         if (NULL == recorder) {
330                 return EINA_FALSE;
331         }
332
333         if (STTD_RECORDER_STATE_READY == g_recorder_state) {
334                 SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Exit audio reading func");
335                 return EINA_FALSE;
336         }
337
338         read_byte = audio_in_read(recorder->audio_h, g_buffer, BUFFER_LENGTH);
339         if (0 > read_byte) {
340                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Fail to read audio : %d", read_byte);
341                 g_recorder_state = STTD_RECORDER_STATE_READY;
342                 return EINA_FALSE;
343         }
344
345         if (0 != g_audio_cb(g_buffer, read_byte)) {
346                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Fail audio callback");
347                 sttd_recorder_stop(g_recording_engine_id);
348                 return EINA_FALSE;
349         }
350
351         float vol_db = get_volume_decibel(g_buffer, BUFFER_LENGTH, recorder->audio_type);
352
353         rewind(g_pFile_vol);
354
355         fwrite((void*)(&vol_db), sizeof(vol_db), 1, g_pFile_vol);
356
357         /* Audio read log */
358         if (0 == g_buffer_count % 50) {
359                 SLOG(LOG_DEBUG, TAG_STTD, "[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, read_byte);
360                 
361                 if (100000 == g_buffer_count) {
362                         g_buffer_count = 0;
363                 }
364         }
365
366         g_buffer_count++;
367
368 #ifdef BUF_SAVE_MODE
369         /* write pcm buffer */
370         fwrite(g_buffer, 1, BUFFER_LENGTH, g_pFile);
371 #endif
372
373         return EINA_TRUE;
374 }
375
376 int sttd_recorder_start(int engine_id)
377 {
378         if (STTD_RECORDER_STATE_RECORDING == g_recorder_state)
379                 return 0;
380
381         /* Check engine id is valid */
382         stt_recorder_s* recorder;
383         recorder = __get_recorder(engine_id);
384         if (NULL == recorder) {
385                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
386                 return STTD_ERROR_INVALID_PARAMETER;
387         }
388
389         int ret = -1; 
390         ret = audio_in_prepare(recorder->audio_h);
391         if (AUDIO_IO_ERROR_NONE != ret) {
392                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to start audio : %d", ret);
393                 return STTD_ERROR_RECORDER_BUSY;
394         }
395
396         /* Add ecore timer to read audio data */
397         ecore_timer_add(0, __read_audio_func, NULL);
398
399         g_recorder_state = STTD_RECORDER_STATE_RECORDING;
400         g_recording_engine_id = engine_id;
401
402         g_pFile_vol = fopen(STT_AUDIO_VOLUME_PATH, "wb+");
403         if (!g_pFile_vol) {
404                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to create Volume File");
405                 return -1;
406         }
407
408         g_buffer_count = 0;
409
410 #ifdef BUF_SAVE_MODE
411         g_count++;
412
413         snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/stt_temp_%d_%d", getpid(), g_count);
414         SECURE_SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Temp file name=[%s]", g_temp_file_name);
415
416         /* open test file */
417         g_pFile = fopen(g_temp_file_name, "wb+");
418         if (!g_pFile) {
419                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] File not found!");
420                 return -1;
421         }       
422 #endif
423
424         return 0;
425 }
426
427 int sttd_recorder_stop(int engine_id)
428 {
429         if (STTD_RECORDER_STATE_READY == g_recorder_state)
430                 return 0;
431
432         /* Check engine id is valid */
433         stt_recorder_s* recorder;
434         recorder = __get_recorder(engine_id);
435         if (NULL == recorder) {
436                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
437                 return STTD_ERROR_INVALID_PARAMETER;
438         }
439
440         int ret; 
441         ret = audio_in_unprepare(recorder->audio_h);
442         if (AUDIO_IO_ERROR_NONE != ret) {
443                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to unprepare audioin : %d", ret);
444         }
445
446         g_recorder_state = STTD_RECORDER_STATE_READY;
447         g_recording_engine_id = -1;
448
449         fclose(g_pFile_vol);
450
451 #ifdef BUF_SAVE_MODE
452         fclose(g_pFile);
453 #endif  
454
455         return 0;
456 }
457
458 int sttd_recorder_set_ignore_session(int engine_id)
459 {
460         if (STTD_RECORDER_STATE_READY != g_recorder_state) {
461                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Record is working.");
462                 return -1;
463         }
464
465         /* Check engine id is valid */
466         stt_recorder_s* recorder;
467         recorder = __get_recorder(engine_id);
468         if (NULL == recorder) {
469                 SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid");
470                 return STTD_ERROR_INVALID_PARAMETER;
471         }
472
473         int ret = audio_in_ignore_session(recorder->audio_h);
474         if (AUDIO_IO_ERROR_NONE != ret) {
475                 SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to ignore session : %d", ret);
476                 return STTD_ERROR_OPERATION_FAILED;
477         }
478
479         return 0;
480 }