2 * Copyright (c) 2011-2017 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <sound_manager.h>
20 #include <sound_manager_internal.h>
22 #include "vcd_client_data.h"
23 #include "vcd_config.h"
25 #include "vcd_engine_agent.h"
26 #include "vcd_recorder.h"
27 #include "dependency_audio_manager.h"
30 #define FRAME_LENGTH 320
31 #define BUFFER_LENGTH FRAME_LENGTH * 2
33 #define FOCUS_SERVER_READY "/tmp/.focus_server_ready"
35 #define VCE_AUDIO_ID_NONE "VC_AUDIO_ID_NONE" /**< None audio id */
36 #define VCE_AUDIO_ID_FFV "VC_FARFIELD_VOICE_VD"
39 static vcd_recorder_state_e g_recorder_state = VCD_RECORDER_STATE_READY;
41 static vcd_recoder_audio_cb g_audio_cb = NULL;
42 static vcd_recorder_interrupt_cb g_interrupt_cb = NULL;
44 static sound_stream_info_h g_stream_info_h = NULL;
45 static sound_stream_info_h g_stream_for_volume_h = NULL;
46 static virtual_sound_stream_h g_virtual_sound_stream_h = NULL;
49 static int g_buffer_count = 0;
50 static int g_device_id = -1;
52 static char* g_pcm_path = NULL;
53 static FILE* g_pcm_fp = NULL;
62 static FILE* g_normal_file = NULL;
63 static int g_count = 1;
67 // TODO: make common function?
68 static float get_volume_decibel(const char* data, const unsigned int size)
70 const int MAX_AMPLITUDE_MEAN_16 = 32768;
77 unsigned long long square_sum = 0;
82 for (i = 0; i < size; i += (depthByte<<1)) {
84 memcpy(&pcm16, data + i, sizeof(short));
85 square_sum += pcm16 * pcm16;
89 if (0 == count || 0 == square_sum) {
90 SLOG(LOG_ERROR, TAG_VCD, "[ERROR] No data");
93 rms = sqrt((float)square_sum/count);
96 db = 20 * log10(rms/MAX_AMPLITUDE_MEAN_16);
100 static const char* __get_focus_changed_reason_code(sound_stream_focus_change_reason_e reason)
103 case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA: return "SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA";
104 case SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM: return "SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM";
105 case SOUND_STREAM_FOCUS_CHANGED_BY_ALARM: return "SOUND_STREAM_FOCUS_CHANGED_BY_ALARM";
106 case SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION: return "SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION";
107 case SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY: return "SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY";
108 case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION: return "SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION";
109 case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION: return "SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION";
110 case SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE: return "SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE";
111 case SOUND_STREAM_FOCUS_CHANGED_BY_VOIP: return "SOUND_STREAM_FOCUS_CHANGED_BY_VOIP";
112 case SOUND_STREAM_FOCUS_CHANGED_BY_CALL: return "SOUND_STREAM_FOCUS_CHANGED_BY_CALL";
113 case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA_EXTERNAL_ONLY: return "SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA_EXTERNAL_ONLY";
114 default: return "Undefined reason code";
118 static void __recorder_focus_state_cb(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state,
119 sound_stream_focus_change_reason_e reason, int sound_behavior, const char *extra_info, void *user_data)
121 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Focus state changed cb");
123 if (stream_info != g_stream_info_h) {
124 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Invalid stream info handle");
128 SLOG(LOG_WARN, TAG_VCD, "[Recorder] focus state changed to (%d) with reason (%s)", (int)focus_state, __get_focus_changed_reason_code(reason));
130 if (VCD_RECORDER_STATE_RECORDING == g_recorder_state && SOUND_STREAM_FOCUS_STATE_RELEASED == focus_state) {
131 SLOG(LOG_WARN, TAG_VCD, "[Recorder] Focus released as interrupt");
132 if (NULL != g_interrupt_cb) {
138 static int __apply_device_for_stream_routing()
140 sound_device_list_h device_list = NULL;
141 sound_device_h device = NULL;
142 sound_device_type_e type;
143 sound_device_io_direction_e io_direction;
145 if (0 != sound_manager_get_device_list(SOUND_DEVICE_IO_DIRECTION_IN_MASK, &device_list)) {
146 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to get current device list");
151 while (0 == sound_manager_get_next_device(device_list, &device)) {
152 if (0 != sound_manager_get_device_type(device, &type)) {
153 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to get device type");
156 if (0 != sound_manager_get_device_io_direction(device, &io_direction)) {
157 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to get device io direction");
160 if (SOUND_DEVICE_USB_AUDIO == type && SOUND_DEVICE_IO_DIRECTION_IN == io_direction) {
161 if (0 != sound_manager_add_device_for_stream_routing(g_stream_info_h, device)) {
162 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to add device");
165 if (0 != sound_manager_apply_stream_routing(g_stream_info_h)) {
166 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to apply stream routing");
174 sound_manager_free_device_list(device_list);
178 SLOG(LOG_WARN, TAG_VCD, "[Recorder] No device");
180 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Apply device for stream routing");
185 static void __device_connection_changed_cb(sound_device_h device, bool is_connected, void *user_data)
187 sound_device_type_e type;
189 if (0 != sound_manager_get_device_type(device, &type)) {
190 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to get device type");
193 if (type == SOUND_DEVICE_USB_AUDIO) {
194 bool is_recording_state = false;
195 if (VCD_RECORDER_STATE_RECORDING == g_recorder_state) {
196 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Stop recorder");
198 is_recording_state = true;
200 if (0 != sound_manager_remove_device_for_stream_routing(g_stream_info_h, device))
201 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to remove device");
203 if (0 != sound_manager_add_device_for_stream_routing(g_stream_info_h, device)) {
204 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to add device");
207 if (0 != sound_manager_apply_stream_routing(g_stream_info_h)) {
208 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR} Fail to apply stream routing");
211 if (true == is_recording_state) {
212 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Start recorder");
213 vcd_recorder_start();
215 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Apply device for stream routing");
221 static int __feed_audio_data_cb(const void* data, const unsigned int length)
223 if (NULL != g_audio_cb) {
224 if (0 != g_audio_cb(data, length)) {
225 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to read audio");
230 if (0 == g_buffer_count % 15) {
231 float vol_db = get_volume_decibel((char*)data, length);
232 if (0 != vcdc_send_set_volume(vcd_client_manager_get_pid(), vol_db)) {
233 SLOG(LOG_ERROR, TAG_VCD, "[Recorder] Fail to send recording volume(%f)", vol_db);
237 if (0 == g_buffer_count % 50) {
238 SLOG(LOG_WARN, TAG_VCD, "[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, length);
240 if (100000 == g_buffer_count) {
248 /* write pcm buffer */
249 fwrite(data, 1, BUFFER_LENGTH, g_normal_file);
252 return VCD_ERROR_NONE;
256 int vcd_recorder_create(vcd_recoder_audio_cb audio_cb, vcd_recorder_interrupt_cb interrupt_cb)
258 if (NULL == audio_cb || NULL == interrupt_cb) {
259 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Input param is NOT valid");
260 return VCD_ERROR_INVALID_PARAMETER;
263 /* check focus server */
266 if (0 == access(FOCUS_SERVER_READY, F_OK)) {
267 SLOG(LOG_ERROR, TAG_VCD, "[Recorder SUCCESS] focus server is available");
271 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] focus server is not available");
276 int ret = sound_manager_add_device_connection_changed_cb(SOUND_DEVICE_IO_DIRECTION_IN_MASK, __device_connection_changed_cb, NULL, &g_device_id);
278 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to add device connection changed callback");
280 if (0 != sound_manager_create_stream_information_internal(SOUND_STREAM_TYPE_VOICE_RECOGNITION_SERVICE, __recorder_focus_state_cb, NULL, &g_stream_info_h)) {
281 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to create stream info");
283 __apply_device_for_stream_routing();
286 if (0 != dependency_audio_manager_initialize(g_stream_info_h, __feed_audio_data_cb)) {
287 SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to initialize dependency audio manager");
288 return VCD_ERROR_OPERATION_FAILED;
291 g_audio_cb = audio_cb;
292 g_interrupt_cb = interrupt_cb;
293 g_recorder_state = VCD_RECORDER_STATE_READY;
298 int vcd_recorder_destroy()
300 if (VCD_RECORDER_STATE_RECORDING == g_recorder_state) {
304 int ret = sound_manager_remove_device_connection_changed_cb(g_device_id);
306 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to remove device connection changed callback, ret(%d)", ret);
310 ret = sound_manager_destroy_stream_information(g_stream_info_h);
312 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to destroy stream info, ret(%d)", ret);
314 g_stream_info_h = NULL;
316 ret = dependency_audio_manager_deinitialize();
318 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to audio in destroy, ret(%d)", ret);
323 if (NULL != g_pcm_path) {
328 if (NULL != g_pcm_fp) {
333 return VCD_ERROR_NONE;
336 int vcd_recorder_set(const char* audio_type, vce_audio_type_e type, int rate, int channel)
338 if (NULL == audio_type) {
339 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] audio_type is NULL");
340 return VCD_ERROR_INVALID_PARAMETER;
343 SLOG(LOG_INFO, TAG_VCD, "[Recorder] set audio type (%s)", audio_type);
344 vcd_engine_set_audio_type(audio_type);
347 ret = dependency_audio_manager_set_audio_info(g_stream_info_h, audio_type, type, rate, channel);
349 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to set audio information");
350 return VCD_ERROR_OPERATION_FAILED;
353 return VCD_ERROR_NONE;
356 int vcd_recorder_get(char** audio_type)
358 if (NULL == audio_type) {
359 return VCD_ERROR_INVALID_PARAMETER;
362 if (0 != dependency_audio_manager_get_audio_source_type(audio_type)) {
363 SLOG(LOG_WARN, TAG_VCD, "[Recorder] Current audio type(%s) is NOT ready", *audio_type);
365 return VCD_ERROR_INVALID_STATE;
368 return VCD_ERROR_NONE;
371 int vcd_recorder_set_audio_streaming_mode(vcd_audio_streaming_mode_e mode)
373 if (0 != dependency_audio_manager_set_streaming_mode((vc_audio_streaming_mode_e)mode)) {
374 SLOG(LOG_WARN, TAG_VCD, "[Recorder] Fail to set audio mode to dependency module(%d)", mode);
375 return VCD_ERROR_OPERATION_FAILED;
378 return VCD_ERROR_NONE;
381 Eina_Bool __read_test_func(void *data)
383 if (VCD_RECORDER_STATE_RECORDING != g_recorder_state) {
384 SLOG(LOG_DEBUG, TAG_VCD, "[Recorder test] Exit audio reading normal func");
388 if (NULL == g_pcm_fp) {
389 g_pcm_fp = fopen(g_pcm_path, "r");
390 if (NULL == g_pcm_fp) {
391 SLOG(LOG_ERROR, TAG_VCD, "[Recorder test ERROR] Cannot open a file : %s", g_pcm_path);
396 char buffer[BUFFER_LENGTH + 10];
397 memset(buffer, '\0', BUFFER_LENGTH + 10);
400 buffer_size = fread(buffer, 1, BUFFER_LENGTH, g_pcm_fp);
401 if (buffer_size != BUFFER_LENGTH)
402 SLOG(LOG_DEBUG, TAG_VCD, "[Recorder test] Get data size(%d)", buffer_size);
404 buffer_size = MIN(buffer_size, BUFFER_LENGTH);
406 if (buffer_size != 0)
407 __feed_audio_data_cb(buffer, buffer_size);
409 float vol_db = get_volume_decibel(buffer, buffer_size);
410 if (0 != vcdc_send_set_volume(vcd_client_manager_get_pid(), vol_db))
411 SLOG(LOG_ERROR, TAG_VCD, "[Recorder test] Fail to send recording volume(%f)", vol_db);
413 if (feof(g_pcm_fp) != 0) {
422 static void __timer_read_test_func(void *data)
424 ecore_timer_add(0, __read_test_func, NULL);
428 int vcd_recorder_start_streaming()
430 SLOG(LOG_INFO, TAG_VCD, "[Recorder] start streaming");
432 vcd_audio_streaming_mode_e streaming_mode;
433 vcd_config_get_audio_streaming_mode(&streaming_mode);
434 if (VCD_AUDIO_STREAMING_MODE_OUTSIDE != streaming_mode) {
435 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Current audio streaming mode(%d)", streaming_mode);
436 return VCD_ERROR_NONE;
440 char normal_file_name[128] = {'\0',};
444 snprintf(normal_file_name, sizeof(normal_file_name), "/tmp/vc_streaming_%d_%d", getpid(), g_count);
445 int ret = access(normal_file_name, 0);
448 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] File is already exist");
449 if (0 == remove(normal_file_name)) {
450 SLOG(LOG_DEBUG, TAG_VCD, "[Recorder] Remove file");
460 SLOG(LOG_DEBUG, TAG_VCD, "[Recorder] File normal name : %s", normal_file_name);
463 g_normal_file = fopen(normal_file_name, "wb+x");
464 if (!g_normal_file) {
465 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] File not found!");
469 return VCD_ERROR_NONE;
472 int vcd_recorder_send_streaming(const void* buffer, const unsigned int length)
474 vcd_audio_streaming_mode_e streaming_mode;
475 vcd_config_get_audio_streaming_mode(&streaming_mode);
476 if (VCD_AUDIO_STREAMING_MODE_OUTSIDE != streaming_mode) {
477 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Current audio streaming mode(%d)", streaming_mode);
478 return VCD_ERROR_NONE;
481 if (NULL != g_audio_cb) {
482 int ret = g_audio_cb(buffer, length);
484 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to start streaming : %d", ret);
491 /* write pcm buffer */
493 fwrite(buffer, 1, length, g_normal_file);
496 return VCD_ERROR_NONE;
499 int vcd_recorder_stop_streaming()
501 SLOG(LOG_INFO, TAG_VCD, "[Recorder] stop streaming");
503 vcd_audio_streaming_mode_e streaming_mode;
504 vcd_config_get_audio_streaming_mode(&streaming_mode);
505 if (VCD_AUDIO_STREAMING_MODE_OUTSIDE != streaming_mode) {
506 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Current audio streaming mode(%d)", streaming_mode);
507 return VCD_ERROR_NONE;
512 fclose(g_normal_file);
515 return VCD_ERROR_NONE;
518 int vcd_recorder_change_system_volume()
520 int ret = VCD_ERROR_NONE;
522 if (!g_stream_for_volume_h) {
523 ret = sound_manager_create_stream_information_internal(SOUND_STREAM_TYPE_VOICE_RECOGNITION_SERVICE, NULL, NULL, &g_stream_for_volume_h);
525 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Fail to create stream information, ret(%d)", ret);
526 return VCD_ERROR_OPERATION_FAILED;
530 if (!g_virtual_sound_stream_h) {
531 ret = sound_manager_create_virtual_stream(g_stream_for_volume_h, &g_virtual_sound_stream_h);
533 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to create virtual stream, ret(%d)", ret);
534 return VCD_ERROR_OPERATION_FAILED;
537 ret = sound_manager_start_virtual_stream(g_virtual_sound_stream_h);
539 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to start virtual stream, ret(%d)", ret);
540 return VCD_ERROR_OPERATION_FAILED;
544 return VCD_ERROR_NONE;
547 int vcd_recorder_recover_system_volume()
549 int ret = VCD_ERROR_NONE;
551 if (g_virtual_sound_stream_h) {
552 ret = sound_manager_stop_virtual_stream(g_virtual_sound_stream_h);
554 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to stop virtual stream, ret(%d)", ret);
555 return VCD_ERROR_OPERATION_FAILED;
557 ret = sound_manager_destroy_virtual_stream(g_virtual_sound_stream_h);
559 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to destroy virtual stream, ret(%d)", ret);
560 return VCD_ERROR_OPERATION_FAILED;
562 g_virtual_sound_stream_h = NULL;
565 if (g_stream_for_volume_h) {
566 ret = sound_manager_destroy_stream_information(g_stream_for_volume_h);
568 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to destroy stream information, ret(%d)", ret);
569 return VCD_ERROR_OPERATION_FAILED;
571 g_stream_for_volume_h = NULL;
574 return VCD_ERROR_NONE;
577 int vcd_recorder_start()
579 vcd_audio_streaming_mode_e streaming_mode;
580 vcd_config_get_audio_streaming_mode(&streaming_mode);
581 if (VCD_AUDIO_STREAMING_MODE_OUTSIDE == streaming_mode) {
582 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Current audio streaming mode(%d)", streaming_mode);
583 return VCD_ERROR_NONE;
588 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Enter, recorder state(%d)", g_recorder_state);
589 if (VCD_RECORDER_STATE_RECORDING == g_recorder_state) {
590 return VCD_ERROR_NONE;
593 if (NULL != g_pcm_path) {
595 ecore_main_loop_thread_safe_call_async(__timer_read_test_func, NULL);
597 int ret = dependency_audio_manager_start_recording();
599 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to start recording, [ret(%d)]", ret);
600 return VCD_ERROR_OPERATION_FAILED;
604 g_recorder_state = VCD_RECORDER_STATE_RECORDING;
607 char normal_file_name[128] = {'\0',};
611 snprintf(normal_file_name, sizeof(normal_file_name), "/tmp/vc_normal_%d_%d", getpid(), g_count);
612 int ret = access(normal_file_name, 0);
615 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] File is already exist");
616 if (0 == remove(normal_file_name)) {
617 SLOG(LOG_DEBUG, TAG_VCD, "[Recorder] Remove file");
627 SLOG(LOG_DEBUG, TAG_VCD, "[Recorder] File normal name : %s", normal_file_name);
630 g_normal_file = fopen(normal_file_name, "wb+x");
631 if (!g_normal_file) {
632 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] File not found!");
635 return VCD_ERROR_NONE;
638 int vcd_recorder_stop()
640 vcd_audio_streaming_mode_e streaming_mode;
641 vcd_config_get_audio_streaming_mode(&streaming_mode);
642 if (VCD_AUDIO_STREAMING_MODE_OUTSIDE == streaming_mode) {
643 SLOG(LOG_INFO, TAG_VCD, "[Recorder] Current audio streaming mode(%d)", streaming_mode);
644 return VCD_ERROR_NONE;
647 if (VCD_RECORDER_STATE_READY == g_recorder_state) {
648 SLOG(LOG_DEBUG, TAG_VCD, "[Recorder] Recorder is already stopped");
649 return VCD_ERROR_NONE;
652 g_recorder_state = VCD_RECORDER_STATE_READY;
655 fclose(g_normal_file);
658 if (NULL != g_pcm_fp) {
663 if (NULL != g_pcm_path) {
668 int ret = dependency_audio_manager_stop_recording();
670 SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to stop audio : %d", ret);
675 return VCD_ERROR_NONE;
678 int vcd_recorder_get_state()
680 return g_recorder_state;
683 int vcd_recorder_set_pcm_path(const char *path)
686 return VCD_ERROR_INVALID_PARAMETER;
689 SLOG(LOG_INFO, TAG_VCD, "[Recorder] set pcm path : %s", path);
690 if (NULL != g_pcm_path) {
695 g_pcm_path = strdup(path);
696 return VCD_ERROR_NONE;