From c6c8b07de7bb0e323a156cb68c3fb29578052c82 Mon Sep 17 00:00:00 2001 From: Suyeon Hwang Date: Mon, 25 May 2020 11:39:44 +0900 Subject: [PATCH] Introduce dependency audio manager 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 --- CMakeLists.txt | 7 +- audio-manager/CMakeLists.txt | 22 ++ audio-manager/inc/vc_audio_manager.h | 44 +++ audio-manager/src/vc_audio_manager.cpp | 278 ++++++++++++++++ packaging/voice-control.spec | 2 +- server/CMakeLists.txt | 1 + server/dependency_audio_manager.cpp | 217 ++++++++++++ server/dependency_audio_manager.h | 72 ++++ server/vcd_recorder.c | 440 +++++++------------------ 9 files changed, 766 insertions(+), 317 deletions(-) create mode 100644 audio-manager/CMakeLists.txt create mode 100644 audio-manager/inc/vc_audio_manager.h create mode 100644 audio-manager/src/vc_audio_manager.cpp create mode 100644 server/dependency_audio_manager.cpp create mode 100644 server/dependency_audio_manager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 837437a..091ba64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 0000000..5ac8b25 --- /dev/null +++ b/audio-manager/CMakeLists.txt @@ -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 index 0000000..6b7cdfd --- /dev/null +++ b/audio-manager/inc/vc_audio_manager.h @@ -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 + +#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 index 0000000..89a1788 --- /dev/null +++ b/audio-manager/src/vc_audio_manager.cpp @@ -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 + +#include +#include +#include +#include +#include +#include + +#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 diff --git a/packaging/voice-control.spec b/packaging/voice-control.spec index 0e0f10e..8c36205 100644 --- a/packaging/voice-control.spec +++ b/packaging/voice-control.spec @@ -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* diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 778f56d..b5e14ce 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -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 index 0000000..b604995 --- /dev/null +++ b/server/dependency_audio_manager.cpp @@ -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 +#include + +#include + +#include +#include +#include + +#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 index 0000000..caa0445 --- /dev/null +++ b/server/dependency_audio_manager.h @@ -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 +#include +#include + +#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__ */ diff --git a/server/vcd_recorder.c b/server/vcd_recorder.c index f122ef6..969d5b4 100644 --- a/server/vcd_recorder.c +++ b/server/vcd_recorder.c @@ -41,55 +41,41 @@ #include "vcd_dbus.h" #include "vcd_engine_agent.h" #include "vcd_recorder.h" +#include "dependency_audio_manager.h" #include "vcd_main.h" -#include - #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; } -- 2.34.1