Introduce dependency audio manager 10/238210/6
authorSuyeon Hwang <stom.hwang@samsung.com>
Mon, 25 May 2020 02:39:44 +0000 (11:39 +0900)
committerSuyeon Hwang <stom.hwang@samsung.com>
Tue, 8 Jun 2021 08:05:44 +0000 (17:05 +0900)
In some cases, developer may need to change the audio source by device.
Dependency audio manager can allow developer to change the audio source.

This patch introduces dependency audio manager and default audio manager module.
Default audio manager uses tizen audio IO interface as audio source.

Change-Id: Ia757539f8a4b37be18796114b582f30813c05ebd
Signed-off-by: Suyeon Hwang <stom.hwang@samsung.com>
CMakeLists.txt
audio-manager/CMakeLists.txt [new file with mode: 0644]
audio-manager/inc/vc_audio_manager.h [new file with mode: 0644]
audio-manager/src/vc_audio_manager.cpp [new file with mode: 0644]
packaging/voice-control.spec
server/CMakeLists.txt
server/dependency_audio_manager.cpp [new file with mode: 0644]
server/dependency_audio_manager.h [new file with mode: 0644]
server/vcd_recorder.c

index 837437a1e87732b9a610c28c8d4a8142835caa6b..091ba640dfd962eb33155ff65134c48fd6a498e2 100644 (file)
@@ -48,12 +48,12 @@ INCLUDE(FindPkgConfig)
 IF("${_TV_PRODUCT}" STREQUAL "TRUE")
 pkg_check_modules(pkgs REQUIRED
     aul buxton2 capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wl2
-    capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf msfapi farfield-voice-api multi-assistant gmock
+    capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf msfapi farfield-voice-api gmock
 )
 ELSE()
 pkg_check_modules(pkgs REQUIRED
     aul buxton2 capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wl2
-    capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf multi-assistant gmock
+    capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf gmock
 )
 ENDIF()
 
@@ -70,6 +70,9 @@ ADD_SUBDIRECTORY(server)
 ## Engine Parser ##
 ADD_SUBDIRECTORY(engine-parser)
 
+## Dependency audio manager ##
+ADD_SUBDIRECTORY(audio-manager)
+
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/voice-control.info DESTINATION ${TZ_SYS_RO_SHARE}/parser-plugins)
 
 ## config ##
diff --git a/audio-manager/CMakeLists.txt b/audio-manager/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5ac8b25
--- /dev/null
@@ -0,0 +1,22 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
+INCLUDE_DIRECTORIES(./inc)
+
+FOREACH(flag ${pkgs_CFLAGS})
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+## for LCOV
+#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror -fprofile-arcs -ftest-coverage")
+#SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror -fprofile-arcs -ftest-coverage")
+
+SET(SRCS
+       src/vc_audio_manager.cpp
+)
+
+## Executable ##
+ADD_LIBRARY("${PROJECT_NAME}-audio-manager" SHARED ${SRCS})
+TARGET_LINK_LIBRARIES("${PROJECT_NAME}-audio-manager" -ldl ${pkgs_LDFLAGS})
+
+## Install
+INSTALL(TARGETS "${PROJECT_NAME}-audio-manager" DESTINATION ${TZ_SYS_RO_SHARE}/voice/vc/1.0/dependency-audio-manager/)
diff --git a/audio-manager/inc/vc_audio_manager.h b/audio-manager/inc/vc_audio_manager.h
new file mode 100644 (file)
index 0000000..6b7cdfd
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef __VC_AUDIO_MANAGER_H__
+#define __VC_AUDIO_MANAGER_H__
+
+#include <tizen.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "vc_audio_manager"
+
+typedef int (*dependency_audio_manager_feed_audio_data)(const void* data, const unsigned int length);
+
+int vcd_dependency_initialize(sound_stream_info_h stream_info_h, dependency_audio_manager_feed_audio_data callback);
+int vcd_dependency_deinitialize(void);
+int vcd_dependency_set_audio_info(sound_stream_info_h stream_info_h, const char* audio_source_type, vce_audio_type_e type, int rate, int channel);
+int vcd_dependency_start_recording(void);
+int vcd_dependency_stop_recording(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VC_AUDIO_MANAGER_H__ */
diff --git a/audio-manager/src/vc_audio_manager.cpp b/audio-manager/src/vc_audio_manager.cpp
new file mode 100644 (file)
index 0000000..89a1788
--- /dev/null
@@ -0,0 +1,278 @@
+/**
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <unistd.h>
+
+#include <tizen.h>
+#include <Ecore.h>
+#include <dlog.h>
+#include <audio_io.h>
+#include <sound_manager.h>
+#include <sound_manager_internal.h>
+
+#include "vce.h"
+#include "vc_audio_manager.h"
+
+
+#define FOCUS_SERVER_READY "/tmp/.focus_server_ready"
+#define VCE_AUDIO_ID_NONE "VC_AUDIO_ID_NONE"           /**< None audio id */
+
+using namespace std;
+
+static dependency_audio_manager_feed_audio_data g_feed_audio_data = nullptr;
+
+static audio_in_h g_audio_h = nullptr;
+static vce_audio_type_e g_audio_type = VCE_AUDIO_TYPE_PCM_S16_LE;
+static int g_audio_rate = 0;
+static int g_audio_channel = 0;
+static char* g_audio_source_type = nullptr;
+
+volatile static bool g_is_recording = false;
+
+
+static bool __convert_audio_channel(int channel, audio_channel_e* output)
+{
+       audio_channel_e audio_ch = AUDIO_CHANNEL_MONO;
+
+       switch (channel) {
+       case 1: audio_ch = AUDIO_CHANNEL_MONO;          break;
+       case 2: audio_ch = AUDIO_CHANNEL_STEREO;        break;
+       case 3: audio_ch = AUDIO_CHANNEL_MULTI_3;       break;
+       case 4: audio_ch = AUDIO_CHANNEL_MULTI_4;       break;
+       case 5: audio_ch = AUDIO_CHANNEL_MULTI_5;       break;
+       case 6: audio_ch = AUDIO_CHANNEL_MULTI_6;       break;
+       case 7: audio_ch = AUDIO_CHANNEL_MULTI_7;       break;
+       case 8: audio_ch = AUDIO_CHANNEL_MULTI_8;       break;
+       default:
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Input channel is not supported. [channel(%d)]", channel);
+               return false;
+       }
+
+       *output = audio_ch;
+       return true;
+}
+
+static bool __convert_audio_sample_type(vce_audio_type_e audio_type, audio_sample_type_e* output)
+{
+       audio_sample_type_e audio_sample_type = AUDIO_SAMPLE_TYPE_S16_LE;
+
+       switch (audio_type) {
+       case VCE_AUDIO_TYPE_PCM_S16_LE:
+               audio_sample_type = AUDIO_SAMPLE_TYPE_S16_LE;
+               break;
+       case VCE_AUDIO_TYPE_PCM_U8:
+               audio_sample_type = AUDIO_SAMPLE_TYPE_U8;
+               break;
+       default:
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Invalid Audio Type. [type(%d)]", audio_type);
+               return false;
+       }
+
+       *output = audio_sample_type;
+       return true;
+}
+
+static Eina_Bool __recorder_timer_func(void *data)
+{
+       const int FRAME_LENGTH = 160;
+       const int BUFFER_LENGTH = FRAME_LENGTH * 2;
+
+       if (g_is_recording && nullptr != g_feed_audio_data) {
+               unsigned char buffer[BUFFER_LENGTH];
+               memset(buffer, '\0', BUFFER_LENGTH);
+
+               int read_bytes = audio_in_read(g_audio_h, buffer, BUFFER_LENGTH);
+               if (0 > read_bytes) {
+                       SLOG(LOG_WARN, LOG_TAG, "[WARNING] Fail to read audio : %d", read_bytes);
+                       return ECORE_CALLBACK_DONE;
+               }
+
+               // TODO: check return value?
+               g_feed_audio_data(buffer, read_bytes);
+       } else {
+               SLOG(LOG_DEBUG, LOG_TAG, "[DEBUG] Recording is finished");
+               return ECORE_CALLBACK_DONE;
+       }
+
+       return ECORE_CALLBACK_RENEW;
+}
+
+int vcd_dependency_initialize(sound_stream_info_h stream_info_h, dependency_audio_manager_feed_audio_data callback)
+{
+       int ret = 0;
+
+       g_audio_type = VCE_AUDIO_TYPE_PCM_S16_LE;
+       g_audio_rate = 16000;
+       g_audio_channel = 1;
+
+       audio_channel_e audio_ch = AUDIO_CHANNEL_MONO;
+       audio_sample_type_e audio_sample_type = AUDIO_SAMPLE_TYPE_U8;
+
+       SLOG(LOG_INFO, LOG_TAG, "[Recorder] Audio type(%d) rate(%d) channel(%d)", g_audio_type, g_audio_rate, g_audio_channel);
+
+       if (false == __convert_audio_channel(g_audio_channel, &audio_ch)) {
+               return VCE_ERROR_INVALID_PARAMETER;
+       }
+
+       if (false == __convert_audio_sample_type(g_audio_type, &audio_sample_type)) {
+               return VCE_ERROR_INVALID_PARAMETER;
+       }
+
+       ret = audio_in_create(g_audio_rate, audio_ch, audio_sample_type, &g_audio_h);
+       if (AUDIO_IO_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Rate(%d) Channel(%d) Type(%d)", g_audio_rate, audio_ch, audio_sample_type);
+               SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Fail to create audio handle : %d", ret);
+       }
+
+       if (0 != audio_in_set_sound_stream_info(g_audio_h, stream_info_h)) {
+               SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Fail to set stream info");
+       }
+
+       g_audio_source_type = strdup(VCE_AUDIO_ID_NONE);
+       g_feed_audio_data = callback;
+       g_is_recording = false;
+
+       return ret;
+}
+
+int vcd_dependency_deinitialize(void)
+{
+       int ret = 0;
+       if (g_is_recording) {
+               ret = audio_in_unprepare(g_audio_h);
+               if (0 != ret) {
+                       SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Fail to stop audio : %d", ret);
+               }
+               g_is_recording = false;
+       }
+
+       ret = audio_in_destroy(g_audio_h);
+       if (0 != ret) {
+               SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Fail to audio in destroy, ret(%d)", ret);
+       }
+
+       g_audio_h = nullptr;
+       g_feed_audio_data = nullptr;
+
+       g_audio_type = VCE_AUDIO_TYPE_PCM_S16_LE;
+       g_audio_rate = 0;
+       g_audio_channel = 0;
+
+       return ret;
+}
+
+int vcd_dependency_set_audio_info(sound_stream_info_h stream_info_h, const char* audio_source_type, vce_audio_type_e type, int rate, int channel)
+{
+       if (nullptr == audio_source_type) {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Invalid audio source type.");
+               return VCE_ERROR_INVALID_PARAMETER;
+       }
+
+       if (nullptr == g_audio_h || nullptr == g_audio_source_type) {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Audio in handle is not valid.");
+               return VCE_ERROR_INVALID_STATE;
+       }
+
+       if (0 == strncmp(g_audio_source_type, audio_source_type, strlen(g_audio_source_type)) ||
+                       (g_audio_type == type && g_audio_rate == rate && g_audio_channel == channel)) {
+               SLOG(LOG_INFO, LOG_TAG, "[DEBUG] No changed information");
+               return VCE_ERROR_NONE;
+       }
+
+       SLOG(LOG_INFO, LOG_TAG, "[Recorder] New audio type(%d) rate(%d) channel(%d)", type, rate, channel);
+       audio_in_destroy(g_audio_h);
+
+       audio_channel_e audio_ch = AUDIO_CHANNEL_MONO;
+       audio_sample_type_e audio_sample_type = AUDIO_SAMPLE_TYPE_U8;
+
+       if (false == __convert_audio_channel(channel, &audio_ch)) {
+               return VCE_ERROR_INVALID_PARAMETER;
+       }
+
+       if (false == __convert_audio_sample_type(type, &audio_sample_type)) {
+               return VCE_ERROR_INVALID_PARAMETER;
+       }
+
+       int ret = 0;
+       ret = audio_in_create(rate, audio_ch, audio_sample_type, &g_audio_h);
+       if (AUDIO_IO_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to create audio handle. [ret(%d)]", ret);
+               return ret;
+       }
+
+       if (0 != audio_in_set_sound_stream_info(g_audio_h, stream_info_h)) {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to set stream info");
+       }
+
+       g_audio_type = type;
+       g_audio_rate = rate;
+       g_audio_channel = channel;
+
+       return ret;
+}
+
+int vcd_dependency_start_recording(void)
+{
+       int ret = 0;
+
+       if (nullptr == g_audio_h) {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Audio in handle is not valid.");
+
+               return VCE_ERROR_INVALID_STATE;
+       }
+
+       ret = audio_in_prepare(g_audio_h);
+       if (AUDIO_IO_ERROR_NONE != ret) {
+               if (AUDIO_IO_ERROR_SOUND_POLICY == ret) {
+                       SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Audio is busy.");
+               } else {
+                       SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Fail to start audio : %d", ret);
+               }
+
+               return ret;
+       }
+
+       g_is_recording = true;
+
+       /* Add ecore timer to read audio data */
+       ecore_main_loop_thread_safe_call_async([](void* data)->void
+                       {
+                               ecore_timer_add(0, __recorder_timer_func, NULL);
+                       }, NULL);
+
+       return ret;
+}
+
+int vcd_dependency_stop_recording(void)
+{
+       int ret = 0;
+
+       if (nullptr == g_audio_h) {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Audio in handle is not valid.");
+
+               return VCE_ERROR_INVALID_STATE;
+       }
+
+       g_is_recording = false;
+
+       ret = audio_in_unprepare(g_audio_h);
+       if (AUDIO_IO_ERROR_NONE != ret) {
+               SLOG(LOG_ERROR, LOG_TAG, "[Recorder ERROR] Fail to stop audio : %d", ret);
+       }
+
+       return ret;
+}
\ No newline at end of file
index 0e0f10ee041fe2b8ceecf0bd1b860bf2aaf14f9f..8c362054ad879e25ee9d1f076db3f46fce2cb85e 100644 (file)
@@ -40,7 +40,6 @@ BuildRequires:  pkgconfig(msfapi)
 BuildRequires:  pkgconfig(farfield-voice-api)
 %endif
 BuildRequires:  pkgconfig(vconf)
-BuildRequires:  pkgconfig(multi-assistant)
 BuildRequires:  cmake
 BuildRequires:  pkgconfig(gmock)
 
@@ -187,6 +186,7 @@ mkdir -p %{_libdir}/voice/vc
 %{_libdir}/libvc_engine.so
 %{_bindir}/vc_getengine
 %{TZ_SYS_RO_SHARE}/voice/vc/1.0/vc-config.xml
+%{TZ_SYS_RO_SHARE}/voice/vc/1.0/dependency-audio-manager/libvc-audio-manager.so
 %{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice*
 %{TZ_SYS_RO_SHARE}/parser-plugins/voice-control.info
 %{TZ_SYS_RO_ETC}/package-manager/parserlib/metadata/libvc-engine-parser.so*
index 778f56d26774c1580735086a54a5ad89d212ffdc..b5e14ceb7c4c045564b17248db5f7b3712d444f1 100644 (file)
@@ -16,6 +16,7 @@ SET(SRCS
        vcd_recorder.c
        vcd_server.c
        vce.c
+       dependency_audio_manager.cpp
 )
 
 INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
diff --git a/server/dependency_audio_manager.cpp b/server/dependency_audio_manager.cpp
new file mode 100644 (file)
index 0000000..b604995
--- /dev/null
@@ -0,0 +1,217 @@
+/**
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include <stdexcept>
+
+#include <tizen.h>
+#include <dlog.h>
+#include <vconf.h>
+
+#include "dependency_audio_manager.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "dependency_am"
+
+
+static void *g_lib_handle = NULL;
+static vcd_dependency_module_interface g_interface = { NULL, };
+
+
+int dependency_audio_manager_initialize(sound_stream_info_h stream_info_h, dependency_audio_manager_feed_audio_data callback)
+{
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@ initialize");
+
+       const int FILEPATH_LEN = 512;
+       char filepath[FILEPATH_LEN] = {'\0', };
+       char *vconf_str = vconf_get_str(VCD_DEPENDENCY_MODULE_PATH);
+       if (vconf_str) {
+               snprintf(filepath, FILEPATH_LEN - 1, "%s", vconf_str);
+               free(vconf_str);
+       } else {
+               const char *default_path = VCD_DEPENDENCY_DEFAULT_PATH;
+               snprintf(filepath, FILEPATH_LEN - 1, "%s/%s", default_path, VCD_DEPENDENCY_DEFAULT_FILENAME);
+       }
+       filepath[FILEPATH_LEN - 1] = '\0';
+
+       char *error;
+       g_lib_handle = NULL;
+       g_lib_handle = dlopen(filepath, RTLD_LAZY);
+       if (NULL != (error = dlerror())) {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to dlopen(%s), error(%s)", filepath, error);
+               return -1; //MAS_ERROR_OPERATION_FAILED;
+       }
+
+       g_interface.initialize =
+               (vcd_dependency_initialize)dlsym(g_lib_handle, VCD_DEPENDENCY_FUNC_INITIALIZE);
+       g_interface.deinitialize =
+               (vcd_dependency_deinitialize)dlsym(g_lib_handle, VCD_DEPENDENCY_FUNC_DEINITIALIZE);
+       g_interface.set_audio_info =
+               (vcd_dependency_set_audio_info)dlsym(g_lib_handle, VCD_DEPENDENCY_FUNC_SET_AUDIO_INFO);
+       g_interface.start_recording =
+               (vcd_dependency_start_recording)dlsym(g_lib_handle, VCD_DEPENDENCY_FUNC_START_RECORDING);
+       g_interface.stop_recording =
+               (vcd_dependency_stop_recording)dlsym(g_lib_handle, VCD_DEPENDENCY_FUNC_STOP_RECORDING);
+
+       int ret = 0;
+       if (NULL != g_lib_handle) {
+               vcd_dependency_initialize func = g_interface.initialize;
+
+               if (NULL == func) {
+                       SLOG(LOG_ERROR, LOG_TAG, "[ERROR] symbol lookup failed : %s", VCD_DEPENDENCY_FUNC_INITIALIZE);
+               } else {
+                       try {
+                               ret = func(stream_info_h, callback);
+                       } catch (const std::exception& e) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] %s of dependency module threw exception : %s",
+                                       VCD_DEPENDENCY_FUNC_INITIALIZE, e.what());
+                       }
+
+                       if (0 != ret) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to initialize, ret(%d)", ret);
+                       }
+               }
+       } else {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] g_lib_handle is not valid");
+       }
+
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@");
+       return ret;
+}
+
+int dependency_audio_manager_deinitialize(void)
+{
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@ Deinitialize");
+       int ret = 0;
+       if (NULL != g_lib_handle) {
+               vcd_dependency_deinitialize func = g_interface.deinitialize;
+
+               if (NULL == func) {
+                       SLOG(LOG_ERROR, LOG_TAG, "[ERROR] symbol lookup failed : %s", VCD_DEPENDENCY_FUNC_DEINITIALIZE);
+               } else {
+                       try {
+                               ret = func();
+                       } catch (const std::exception& e) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] %s of dependency module threw exception : %s",
+                                       VCD_DEPENDENCY_FUNC_DEINITIALIZE, e.what());
+                       }
+
+                       if (0 != ret) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to initialize, ret(%d)", ret);
+                       }
+               }
+
+               dlclose(g_lib_handle);
+               g_lib_handle = NULL;
+       } else {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] g_lib_handle is not valid");
+       }
+
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@");
+       return ret;
+}
+
+int dependency_audio_manager_set_audio_info(sound_stream_info_h stream_info_h, const char* audio_source_type, vce_audio_type_e type, int rate, int channel)
+{
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@ Set audio information");
+       int ret = 0;
+       if (NULL != g_lib_handle) {
+               vcd_dependency_set_audio_info func = g_interface.set_audio_info;
+
+               if (NULL == func) {
+                       SLOG(LOG_ERROR, LOG_TAG, "[ERROR] symbol lookup failed : %s", VCD_DEPENDENCY_FUNC_SET_AUDIO_INFO);
+               } else {
+                       try {
+                               ret = func(stream_info_h, audio_source_type, type, rate, channel);
+                       } catch (const std::exception& e) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] %s of dependency module threw exception : %s",
+                                       VCD_DEPENDENCY_FUNC_SET_AUDIO_INFO, e.what());
+                       }
+
+                       if (0 != ret) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to initialize, ret(%d)", ret);
+                       }
+               }
+       } else {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] g_lib_handle is not valid");
+       }
+
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@");
+       return ret;
+}
+
+int dependency_audio_manager_start_recording()
+{
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@ Start recording");
+       int ret = 0;
+       if (NULL != g_lib_handle) {
+               vcd_dependency_start_recording func = g_interface.start_recording;
+
+               if (NULL == func) {
+                       SLOG(LOG_ERROR, LOG_TAG, "[ERROR] symbol lookup failed : %s", VCD_DEPENDENCY_FUNC_START_RECORDING);
+               } else {
+                       try {
+                               ret = func();
+                       } catch (const std::exception& e) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] %s of dependency module threw exception : %s",
+                                       VCD_DEPENDENCY_FUNC_START_RECORDING, e.what());
+                       }
+
+                       if (0 != ret) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to initialize, ret(%d)", ret);
+                       }
+               }
+       } else {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] g_lib_handle is not valid");
+       }
+
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@");
+       return ret;
+
+}
+
+int dependency_audio_manager_stop_recording(void)
+{
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@ Stop recording");
+       int ret = 0;
+       if (NULL != g_lib_handle) {
+               vcd_dependency_stop_recording func = g_interface.stop_recording;
+
+               if (NULL == func) {
+                       SLOG(LOG_ERROR, LOG_TAG, "[ERROR] symbol lookup failed : %s", VCD_DEPENDENCY_FUNC_STOP_RECORDING);
+               } else {
+                       try {
+                               ret = func();
+                       } catch (const std::exception& e) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] %s of dependency module threw exception : %s",
+                                       VCD_DEPENDENCY_FUNC_STOP_RECORDING, e.what());
+                       }
+
+                       if (0 != ret) {
+                               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] Fail to initialize, ret(%d)", ret);
+                       }
+               }
+       } else {
+               SLOG(LOG_ERROR, LOG_TAG, "[ERROR] g_lib_handle is not valid");
+       }
+
+       SLOG(LOG_DEBUG, LOG_TAG, "@@@");
+       return ret;
+}
\ No newline at end of file
diff --git a/server/dependency_audio_manager.h b/server/dependency_audio_manager.h
new file mode 100644 (file)
index 0000000..caa0445
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef __DEPENDENCY_AUDIO_MANAGER_H__
+#define __DEPENDENCY_AUDIO_MANAGER_H__
+
+#include <tzplatform_config.h>
+#include <sound_manager.h>
+#include <vce.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**************************************************************************************
+ *** Definitions for dependencies
+ *************************************************************************************/
+#define VCD_DEPENDENCY_DEFAULT_PATH tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0/dependency-audio-manager")
+#define VCD_DEPENDENCY_DEFAULT_FILENAME "libvc-audio-manager.so"
+#define VCD_DEPENDENCY_MODULE_PATH "db/voice/vc/dependency_module_path"
+
+
+typedef int (*dependency_audio_manager_feed_audio_data)(const void* data, const unsigned int length);
+
+
+#define VCD_DEPENDENCY_FUNC_INITIALIZE "vcd_dependency_initialize"
+typedef int (*vcd_dependency_initialize)(sound_stream_info_h stream_info_h, dependency_audio_manager_feed_audio_data callback);
+#define VCD_DEPENDENCY_FUNC_DEINITIALIZE "vcd_dependency_deinitialize"
+typedef int (*vcd_dependency_deinitialize)(void);
+#define VCD_DEPENDENCY_FUNC_SET_AUDIO_INFO "vcd_dependency_set_audio_info"
+typedef int (*vcd_dependency_set_audio_info)(sound_stream_info_h stream_info_h, const char* audio_source_type, vce_audio_type_e type, int rate, int channel);
+#define VCD_DEPENDENCY_FUNC_START_RECORDING "vcd_dependency_start_recording"
+typedef int (*vcd_dependency_start_recording)(void);
+#define VCD_DEPENDENCY_FUNC_STOP_RECORDING "vcd_dependency_stop_recording"
+typedef int (*vcd_dependency_stop_recording)(void);
+
+
+typedef struct {
+       vcd_dependency_initialize               initialize;
+       vcd_dependency_deinitialize             deinitialize;
+       vcd_dependency_set_audio_info   set_audio_info;
+       vcd_dependency_start_recording  start_recording;
+       vcd_dependency_stop_recording   stop_recording;
+} vcd_dependency_module_interface;
+
+
+int dependency_audio_manager_initialize(sound_stream_info_h stream_info_h, dependency_audio_manager_feed_audio_data callback);
+int dependency_audio_manager_deinitialize(void);
+int dependency_audio_manager_set_audio_info(sound_stream_info_h stream_info_h, const char* audio_source_type, vce_audio_type_e type, int rate, int channel);
+int dependency_audio_manager_start_recording(void);
+int dependency_audio_manager_stop_recording(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DEPENDENCY_AUDIO_MANAGER_H__ */
index f122ef6257a8660940ff0f082498c5f906b74d79..969d5b4c0f1727bde5bd77528c0a45993689ef20 100644 (file)
 #include "vcd_dbus.h"
 #include "vcd_engine_agent.h"
 #include "vcd_recorder.h"
+#include "dependency_audio_manager.h"
 #include "vcd_main.h"
 
-#include <multi_assistant_internal.h>
-
 #define FRAME_LENGTH 320
 #define BUFFER_LENGTH FRAME_LENGTH * 2
 
-#define FOCUS_SERVER_READY             "/tmp/.focus_server_ready"
-
-#define VCE_AUDIO_ID_NONE              "VC_AUDIO_ID_NONE"              /**< None audio id */
-#define VCE_AUDIO_ID_FFV               "VC_FARFIELD_VOICE_VD"
-
-static vcd_recorder_state_e    g_recorder_state = VCD_RECORDER_STATE_READY;
-
-static vcd_recoder_audio_cb    g_audio_cb = NULL;
-
-static vcd_recorder_interrupt_cb       g_interrupt_cb = NULL;
-
-static audio_in_h      g_audio_h;
-
-static sound_stream_info_h     g_stream_info_h;
+#define FOCUS_SERVER_READY     "/tmp/.focus_server_ready"
 
-static vce_audio_type_e g_audio_type;
+#define VCE_AUDIO_ID_NONE      "VC_AUDIO_ID_NONE"              /**< None audio id */
+#define VCE_AUDIO_ID_FFV       "VC_FARFIELD_VOICE_VD"
 
-static int     g_audio_rate;
 
-static int             g_audio_channel;
+static vcd_recorder_state_e g_recorder_state = VCD_RECORDER_STATE_READY;
 
-static char    g_normal_buffer[BUFFER_LENGTH + 10];
+static vcd_recoder_audio_cb g_audio_cb = NULL;
+static vcd_recorder_interrupt_cb g_interrupt_cb = NULL;
 
-static bool    g_is_valid_audio_in = false;
+static sound_stream_info_h g_stream_info_h = NULL;
+static sound_stream_info_h g_stream_for_volume_h = NULL;
+static virtual_sound_stream_h g_virtual_sound_stream_h = NULL;
 
-static bool    g_is_valid_bt_in = false;
+static bool g_is_valid_audio_in = false;
+static bool g_is_valid_bt_in = false;
 
-static char*   g_current_audio_type = NULL;
+static char* g_current_audio_type = NULL;
+static int g_buffer_count = 0;
+static int g_device_id = -1;
 
 static char* g_pcm_path = NULL;
 static FILE* g_pcm_fp = NULL;
 
-static int     g_buffer_count;
-
-static int     g_device_id = -1;
-
 #ifdef TV_FFV_MODE
 farfield_voice_h g_farfieldvoice_h = NULL;
 #endif
 
-static sound_stream_info_h     g_stream_for_volume_h = NULL;
-static virtual_sound_stream_h  g_virtual_sound_stream_h = NULL;
 
 /* Sound buf save */
 #if 0
@@ -97,12 +83,11 @@ static virtual_sound_stream_h       g_virtual_sound_stream_h = NULL;
 #endif
 
 #ifdef BUF_SAVE_MODE
-static FILE* g_normal_file;
-
+static FILE* g_normal_file = NULL;
 static int g_count = 1;
 #endif
 
-static float get_volume_decibel(char* data, int size);
+static float get_volume_decibel(const char* data, const unsigned int size);
 
 #ifdef TV_MSF_WIFI_MODE
 static void __msf_wifi_audio_data_receive_cb(msf_wifi_voice_data_s *voice_data, void* user_data)
@@ -260,33 +245,6 @@ static void _ffv_audio_function_cb(void* data, unsigned int length, void* user_d
 }
 #endif
 
-void audio_streaming_cb(ma_audio_streaming_event_e event, char* buffer, int len, void* user_data)
-{
-       if (0 == g_buffer_count || 0 == g_buffer_count % 50) {
-               SLOG(LOG_INFO, TAG_VCD, "[Recorder INFO] MA_ap audio function callback is invoked");
-
-               if (100000 == g_buffer_count) {
-                       g_buffer_count = 0;
-               }
-       }
-
-       g_buffer_count++;
-
-       if (NULL != g_audio_cb) {
-               if (0 != g_audio_cb(buffer, len)) {
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to read audio");
-               }
-       }
-
-       /* Set volume */
-       if (0 == g_buffer_count % 15) {
-               float vol_db = get_volume_decibel(buffer, len);
-               if (0 != vcdc_send_set_volume(vcd_client_manager_get_pid(), vol_db)) {
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder] Fail to send recording volume(%f)", vol_db);
-               }
-       }
-}
-
 #if 1
 static const char* __get_focus_changed_reason_code(sound_stream_focus_change_reason_e reason)
 {
@@ -410,6 +368,41 @@ static void __device_connection_changed_cb(sound_device_h device, bool is_connec
        return;
 }
 
+static int __feed_audio_data_cb(const void* data, const unsigned int length)
+{
+       if (NULL != g_audio_cb) {
+               if (0 != g_audio_cb(data, length)) {
+                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to read audio");
+                       vcd_recorder_stop();
+               }
+       }
+
+       if (0 == g_buffer_count % 15) {
+               float vol_db = get_volume_decibel((char*)data, length);
+               if (0 != vcdc_send_set_volume(vcd_client_manager_get_pid(), vol_db)) {
+                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder] Fail to send recording volume(%f)", vol_db);
+               }
+       }
+
+       if (0 == g_buffer_count % 50) {
+               SLOG(LOG_WARN, TAG_VCD, "[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, length);
+
+               if (100000 == g_buffer_count) {
+                       g_buffer_count = 0;
+               }
+       }
+
+       g_buffer_count++;
+
+#ifdef BUF_SAVE_MODE
+       /* write pcm buffer */
+       fwrite(data, 1, BUFFER_LENGTH, g_normal_file);
+#endif
+
+       return 0;
+}
+
+
 int vcd_recorder_create(vcd_recoder_audio_cb audio_cb, vcd_recorder_interrupt_cb interrupt_cb)
 {
        if (NULL == audio_cb || NULL == interrupt_cb) {
@@ -440,42 +433,6 @@ int vcd_recorder_create(vcd_recoder_audio_cb audio_cb, vcd_recorder_interrupt_cb
        g_pcm_fp = NULL;
        g_pcm_path = NULL;
 
-       g_audio_type = VCE_AUDIO_TYPE_PCM_S16_LE;
-       g_audio_rate = 16000;
-       g_audio_channel = 1;
-
-       audio_channel_e audio_ch;
-       audio_sample_type_e audio_type;
-
-       SLOG(LOG_INFO, TAG_VCD, "[Recorder] Audio type(%d) rate(%d) channel(%d)", g_audio_type, g_audio_rate, g_audio_channel);
-
-       switch (g_audio_channel) {
-       case 1: audio_ch = AUDIO_CHANNEL_MONO;          break;
-       case 2: audio_ch = AUDIO_CHANNEL_STEREO;        break;
-       default:
-               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Input channel is not supported");
-               return VCD_ERROR_OPERATION_FAILED;
-               break;
-       }
-
-       switch (g_audio_type) {
-       case VCE_AUDIO_TYPE_PCM_S16_LE: audio_type = AUDIO_SAMPLE_TYPE_S16_LE;  break;
-       case VCE_AUDIO_TYPE_PCM_U8:     audio_type = AUDIO_SAMPLE_TYPE_U8;      break;
-       default:
-               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Invalid Audio Type");
-               return VCD_ERROR_OPERATION_FAILED;
-               break;
-       }
-
-       ret = audio_in_create(g_audio_rate, audio_ch, audio_type, &g_audio_h);
-       if (AUDIO_IO_ERROR_NONE == ret) {
-               g_is_valid_audio_in = true;
-       } else {
-               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Rate(%d) Channel(%d) Type(%d)", g_audio_rate, audio_ch, audio_type);
-               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to create audio handle : %d", ret);
-               g_is_valid_audio_in = false;
-       }
-
        ret = sound_manager_add_device_connection_changed_cb(SOUND_DEVICE_IO_DIRECTION_IN_MASK, __device_connection_changed_cb, NULL, &g_device_id);
        if (0 != ret)
                SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to add device connection changed callback");
@@ -486,8 +443,11 @@ int vcd_recorder_create(vcd_recoder_audio_cb audio_cb, vcd_recorder_interrupt_cb
                __apply_device_for_stream_routing();
        }
 
-       if (0 != audio_in_set_sound_stream_info(g_audio_h, g_stream_info_h)) {
-               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to set stream info");
+       if (0 != dependency_audio_manager_initialize(g_stream_info_h, __feed_audio_data_cb)) {
+               SLOG(LOG_ERROR, TAG_VCD, "[ERROR] Fail to initialize dependency audio manager");
+               g_is_valid_audio_in = false;
+       } else {
+               g_is_valid_audio_in = true;
        }
 
        g_audio_cb = audio_cb;
@@ -533,9 +493,6 @@ int vcd_recorder_create(vcd_recoder_audio_cb audio_cb, vcd_recorder_interrupt_cb
 
        SLOG(LOG_INFO, TAG_VCD, "[Recorder] Audio type : %s", g_current_audio_type);
 
-       ma_ap_initialize();
-       ma_ap_set_audio_streaming_cb(audio_streaming_cb, NULL);
-
        /* Set audio feed callback */
 #ifdef TV_BT_MODE
        if (BT_ERROR_NONE != bt_hid_set_audio_data_receive_cb(_bt_hid_audio_data_receive_cb, NULL)) {
@@ -559,26 +516,26 @@ int vcd_recorder_create(vcd_recoder_audio_cb audio_cb, vcd_recorder_interrupt_cb
 
 int vcd_recorder_destroy()
 {
-       ma_ap_deinitialize();
-       int ret = -1;
        if (VCD_RECORDER_STATE_RECORDING == g_recorder_state) {
                vcd_recorder_stop();
        }
 
-       ret = sound_manager_remove_device_connection_changed_cb(g_device_id);
-       if (0 != ret)
+       int ret = sound_manager_remove_device_connection_changed_cb(g_device_id);
+       if (0 != ret) {
                SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to remove device connection changed callback, ret(%d)", ret);
+       }
        g_device_id = -1;
 
        ret = sound_manager_destroy_stream_information(g_stream_info_h);
-       if (0 != ret)
+       if (0 != ret) {
                SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to destroy stream info, ret(%d)", ret);
+       }
        g_stream_info_h = NULL;
 
-       ret = audio_in_destroy(g_audio_h);
-       if (0 != ret)
+       ret = dependency_audio_manager_deinitialize();
+       if (0 != ret) {
                SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to audio in destroy, ret(%d)", ret);
-       g_audio_h = NULL;
+       }
 
 
 #ifdef TV_MSF_WIFI_MODE
@@ -606,18 +563,20 @@ int vcd_recorder_destroy()
                g_current_audio_type = NULL;
        }
 
-       if (g_pcm_path)
+       if (NULL != g_pcm_path) {
                free(g_pcm_path);
-       g_pcm_path = NULL;
+               g_pcm_path = NULL;
+       }
 
-       if (g_pcm_fp)
+       if (NULL != g_pcm_fp) {
                fclose(g_pcm_fp);
-       g_pcm_fp = NULL;
+               g_pcm_fp = NULL;
+       }
 
        return VCD_ERROR_NONE;
 }
 
-int vcd_recorder_set(const char* audio_type, vce_audio_type_e type, int rate, int channel)
+static int __set_audio_source_type(const char* audio_type)
 {
        if (NULL == audio_type) {
                SLOG(LOG_INFO, TAG_VCD, "[Recorder] Audio type is NULL");
@@ -627,7 +586,7 @@ int vcd_recorder_set(const char* audio_type, vce_audio_type_e type, int rate, in
        if (NULL != g_current_audio_type) {
                if (0 == strncmp(g_current_audio_type, audio_type, strlen(g_current_audio_type))) {
                        SLOG(LOG_INFO, TAG_VCD, "[Recorder] Current audio type is already set : %s", audio_type);
-                       return 0;
+                       return VCD_ERROR_NONE;
                }
        } else {
                SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Recorder is NOT created");
@@ -657,96 +616,43 @@ int vcd_recorder_set(const char* audio_type, vce_audio_type_e type, int rate, in
                }
        }
 
+       if (NULL != g_current_audio_type) {
+               free(g_current_audio_type);
+               g_current_audio_type = NULL;
+       }
+
+       g_current_audio_type = strdup(audio_type);
+
+       return VCD_ERROR_NONE;
+}
+
+int vcd_recorder_set(const char* audio_type, vce_audio_type_e type, int rate, int channel)
+{
        int ret = -1;
+       ret = __set_audio_source_type(audio_type);
+       if (0 != ret) {
+               return ret;
+       }
+
        /* Check BT audio */
        if (0 == strncmp(VCE_AUDIO_ID_BLUETOOTH, audio_type, strlen(VCE_AUDIO_ID_BLUETOOTH))) {
                if (false == g_is_valid_bt_in) {
                        SLOG(LOG_ERROR, TAG_VCD, "[Recorder] BT audio is NOT valid");
                        return VCD_ERROR_OPERATION_REJECTED;
                }
-
-               if (NULL != g_current_audio_type) {
-                       free(g_current_audio_type);
-                       g_current_audio_type = NULL;
-               }
-
-               g_current_audio_type = strdup(audio_type);
        } else if (0 == strncmp(VCE_AUDIO_ID_WIFI, audio_type, strlen(VCE_AUDIO_ID_WIFI))) {
-               if (NULL != g_current_audio_type) {
-                       free(g_current_audio_type);
-                       g_current_audio_type = NULL;
-               }
-
-               g_current_audio_type = strdup(audio_type);
        } else if (0 == strncmp(VCE_AUDIO_ID_FFV, audio_type, strlen(VCE_AUDIO_ID_FFV))) {
-               if (NULL != g_current_audio_type) {
-                       free(g_current_audio_type);
-                       g_current_audio_type = NULL;
-               }
-
-               g_current_audio_type = strdup(audio_type);
        } else {
                if (false == g_is_valid_audio_in) {
                        SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Audio-in is NOT valid");
                        return VCD_ERROR_OPERATION_REJECTED;
                }
 
-               if (g_audio_type != type || g_audio_rate != rate || g_audio_channel != channel) {
-                       SLOG(LOG_INFO, TAG_VCD, "[Recorder] New audio type(%d) rate(%d) channel(%d)", type, rate, channel);
-                       audio_in_destroy(g_audio_h);
-                       g_audio_h = NULL;
-
-                       audio_channel_e audio_ch = AUDIO_CHANNEL_MONO;
-                       audio_sample_type_e audio_sample_type;
-
-                       switch (channel) {
-                       case 1: audio_ch = AUDIO_CHANNEL_MONO;          break;
-                       case 2: audio_ch = AUDIO_CHANNEL_STEREO;        break;
-                       case 3: audio_ch = AUDIO_CHANNEL_MULTI_3;       break;
-                       case 4: audio_ch = AUDIO_CHANNEL_MULTI_4;       break;
-                       case 5: audio_ch = AUDIO_CHANNEL_MULTI_5;       break;
-                       case 6: audio_ch = AUDIO_CHANNEL_MULTI_6;       break;
-                       case 7: audio_ch = AUDIO_CHANNEL_MULTI_7;       break;
-                       case 8: audio_ch = AUDIO_CHANNEL_MULTI_8;       break;
-                       default:
-                               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Input channel is not supported, audio_ch(%d)", audio_ch);
-                               return VCD_ERROR_OPERATION_FAILED;
-                               break;
-                       }
-
-                       switch (type) {
-                       case VCE_AUDIO_TYPE_PCM_S16_LE: audio_sample_type = AUDIO_SAMPLE_TYPE_S16_LE;   break;
-                       case VCE_AUDIO_TYPE_PCM_U8:     audio_sample_type = AUDIO_SAMPLE_TYPE_U8;       break;
-                       default:
-                               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Invalid Audio Type");
-                               return VCD_ERROR_OPERATION_FAILED;
-                               break;
-                       }
-
-                       ret = audio_in_create(rate, audio_ch, audio_sample_type, &g_audio_h);
-                       if (AUDIO_IO_ERROR_NONE != ret) {
-                               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to create audio handle : %d", ret);
-                               g_is_valid_audio_in = false;
-                               return VCD_ERROR_OPERATION_FAILED;
-                       }
-
-                       if (0 != audio_in_set_sound_stream_info(g_audio_h, g_stream_info_h)) {
-                               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to set stream info");
-                       }
-
-                       g_audio_type = type;
-                       g_audio_rate = rate;
-                       g_audio_channel = channel;
-               }
-
-#ifdef TV_BT_MODE
-               if (NULL != g_current_audio_type) {
-                       free(g_current_audio_type);
-                       g_current_audio_type = NULL;
+               ret = dependency_audio_manager_set_audio_info(g_stream_info_h, audio_type, type, rate, channel);
+               if (0 != ret) {
+                       g_is_valid_audio_in = false;
+                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to set audio information");
                }
-
-               g_current_audio_type = strdup(audio_type);
-#endif
        }
 
        SLOG(LOG_INFO, TAG_VCD, "[Recorder] Current audio type is changed : %s", g_current_audio_type);
@@ -770,9 +676,10 @@ int vcd_recorder_get(char** audio_type)
        return 0;
 }
 
-static float get_volume_decibel(char* data, int size)
+// TODO: make common function?
+static float get_volume_decibel(const char* data, const unsigned int size)
 {
-#define MAX_AMPLITUDE_MEAN_16 32768
+       const int MAX_AMPLITUDE_MEAN_16 = 32768;
 
        int i, depthByte;
        int count = 0;
@@ -827,6 +734,7 @@ Eina_Bool __read_test_func(void *data)
 
        buffer_size = MIN(buffer_size, BUFFER_LENGTH);
 
+       // TODO: change to __feed_audio_data_cb
        if (NULL != g_audio_cb && buffer_size != 0)
                g_audio_cb(buffer, buffer_size);
 
@@ -842,65 +750,9 @@ Eina_Bool __read_test_func(void *data)
        return EINA_TRUE;
 }
 
-Eina_Bool __read_normal_func(void *data)
-{
-       int ret = -1;
-
-       if (VCD_RECORDER_STATE_RECORDING != g_recorder_state) {
-               SLOG(LOG_INFO, TAG_VCD, "[Recorder] Exit audio reading normal func");
-               return EINA_FALSE;
-       }
-
-       memset(g_normal_buffer, '\0', BUFFER_LENGTH + 10);
-
-       ret = audio_in_read(g_audio_h, g_normal_buffer, BUFFER_LENGTH);
-       if (0 > ret) {
-               SLOG(LOG_WARN, TAG_VCD, "[Recorder WARNING] Fail to read audio : %d", ret);
-               g_recorder_state = VCD_RECORDER_STATE_READY;
-               return EINA_FALSE;
-       }
-
-       if (NULL != g_audio_cb) {
-               if (0 != g_audio_cb(g_normal_buffer, BUFFER_LENGTH)) {
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to read audio : %d", ret);
-                       vcd_recorder_stop();
-                       return EINA_FALSE;
-               }
-       }
-
-       /* Set volume */
-       if (0 == g_buffer_count % 30) {
-               float vol_db = get_volume_decibel(g_normal_buffer, BUFFER_LENGTH);
-               if (0 != vcdc_send_set_volume(vcd_client_manager_get_pid(), vol_db)) {
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder] Fail to send recording volume(%f)", vol_db);
-               }
-       }
-
-       if (0 == g_buffer_count || 0 == g_buffer_count % 50) {
-               SLOG(LOG_WARN, TAG_VCD, "[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, ret);
-
-               if (100000 == g_buffer_count) {
-                       g_buffer_count = 0;
-               }
-       }
-
-       g_buffer_count++;
-
-#ifdef BUF_SAVE_MODE
-       /* write pcm buffer */
-       fwrite(g_normal_buffer, 1, BUFFER_LENGTH, g_normal_file);
-#endif
-
-       return EINA_TRUE;
-}
-
-static void __timer_read_normal_func(void *data)
+static void __timer_read_test_func(void *data)
 {
-       SLOG(LOG_DEBUG, TAG_VCD, "[Recorder] before __read_normal_func");
-       if (g_pcm_path)
-               ecore_timer_add(0, __read_test_func, NULL);
-       else
-               ecore_timer_add(0, __read_normal_func, NULL);
+       ecore_timer_add(0, __read_test_func, NULL);
        return;
 }
 
@@ -921,48 +773,11 @@ static void __check_audio_format()
                return;
        }
 
-       if (g_audio_type != type || g_audio_rate != rate || g_audio_channel != channel) {
-               SLOG(LOG_INFO, TAG_VCD, "[Recorder] New audio type(%d) rate(%d) channel(%d)", type, rate, channel);
-               audio_in_destroy(g_audio_h);
-               g_audio_h = NULL;
-
-               audio_channel_e audio_ch;
-               audio_sample_type_e audio_type;
-
-               switch (channel) {
-               case 1: audio_ch = AUDIO_CHANNEL_MONO;          break;
-               case 2: audio_ch = AUDIO_CHANNEL_STEREO;        break;
-               default:
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Input channel is not supported");
-                       return;
-                       break;
-               }
-
-               switch (type) {
-               case VCE_AUDIO_TYPE_PCM_S16_LE: audio_type = AUDIO_SAMPLE_TYPE_S16_LE;  break;
-               case VCE_AUDIO_TYPE_PCM_U8:     audio_type = AUDIO_SAMPLE_TYPE_U8;      break;
-               default:
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Invalid Audio Type");
-                       return;
-                       break;
-               }
-
-               ret = audio_in_create(rate, audio_ch, audio_type, &g_audio_h);
-               if (AUDIO_IO_ERROR_NONE != ret) {
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to create audio handle : %d", ret);
-                       g_is_valid_audio_in = false;
-                       return;
-               }
-
-               if (0 != audio_in_set_sound_stream_info(g_audio_h, g_stream_info_h)) {
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to set stream info");
-               }
-
-               g_audio_type = type;
-               g_audio_rate = rate;
-               g_audio_channel = channel;
-       } else {
-               SLOG(LOG_INFO, TAG_VCD, "[Recorder] audio type(%d) rate(%d) channel(%d)", g_audio_type, g_audio_rate, g_audio_channel);
+       ret = dependency_audio_manager_set_audio_info(g_stream_info_h, VCE_AUDIO_ID_NONE, type, rate, channel);
+       if (0 != ret) {
+               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to set audio information");
+               g_is_valid_audio_in = false;
+               return;
        }
 }
 
@@ -1136,24 +951,21 @@ int vcd_recorder_start()
                return VCD_ERROR_NONE;
        }
 
-       if (NULL != g_current_audio_type && 0 == strncmp(VCE_AUDIO_ID_NONE, g_current_audio_type, strlen(VCE_AUDIO_ID_NONE))) {
-               /* check audio format */
-               __check_audio_format();
-
-               ret = audio_in_prepare(g_audio_h);
-               if (AUDIO_IO_ERROR_NONE != ret) {
-                       if (AUDIO_IO_ERROR_SOUND_POLICY == ret) {
-                               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Audio is busy.");
-                               return VCD_ERROR_RECORDER_BUSY;
-                       } else {
-                               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to start audio : %d", ret);
-                       }
-                       return VCD_ERROR_OPERATION_FAILED;
+       if (NULL != g_pcm_path) {
+               // For testing
+               ecore_main_loop_thread_safe_call_async(__timer_read_test_func, NULL);
+       } else {
+               if (NULL != g_current_audio_type && 0 == strncmp(VCE_AUDIO_ID_NONE, g_current_audio_type, strlen(VCE_AUDIO_ID_NONE))) {
+                       /* check audio format */
+                       __check_audio_format();
                }
+       }
 
-               /* Add ecore timer to read audio data */
-               ecore_main_loop_thread_safe_call_async(__timer_read_normal_func, NULL);
-               SLOG(LOG_INFO, TAG_VCD, "[Recorder] Start audio in recorder");
+       ret = dependency_audio_manager_start_recording();
+       if (0 != ret) {
+               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to start recording, [ret(%d)]", ret);
+
+               return ret;
        }
 
        g_recorder_state = VCD_RECORDER_STATE_RECORDING;
@@ -1200,8 +1012,10 @@ int vcd_recorder_stop()
                return VCD_ERROR_NONE;
        }
 
-       if (VCD_RECORDER_STATE_READY == g_recorder_state)
+       if (VCD_RECORDER_STATE_READY == g_recorder_state) {
+               SLOG(LOG_DEBUG, TAG_VCD, "[Recorder] Recorder is already stopped");
                return VCD_ERROR_NONE;
+       }
 
        g_recorder_state = VCD_RECORDER_STATE_READY;
 
@@ -1217,15 +1031,13 @@ int vcd_recorder_stop()
                fclose(g_pcm_fp);
        g_pcm_fp = NULL;
 
-       if (NULL != g_current_audio_type && 0 == strncmp(VCE_AUDIO_ID_NONE, g_current_audio_type, strlen(VCE_AUDIO_ID_NONE))) {
-               ret = audio_in_unprepare(g_audio_h);
-               if (AUDIO_IO_ERROR_NONE != ret) {
-                       SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to stop audio : %d", ret);
-                       return VCD_ERROR_OPERATION_FAILED;
-               }
+       ret = dependency_audio_manager_stop_recording();
+       if (0 != ret) {
+               SLOG(LOG_ERROR, TAG_VCD, "[Recorder ERROR] Fail to stop audio : %d", ret);
+               return ret;
        }
 
-       vcd_recorder_set(VCE_AUDIO_ID_NONE, g_audio_type, g_audio_rate, g_audio_channel);
+       __set_audio_source_type(VCE_AUDIO_ID_NONE);
 
        return VCD_ERROR_NONE;
 }