X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=server%2Fsttd_recorder.c;h=6b19499114fd912f62231483ac64bdf41d993178;hb=931382eed914f816618db156bdde73c0fb3a76f8;hp=da65b56d406b76191a125e602c301e578c6a6a17;hpb=1ef33ee75879fecb9e80bc87cc8c060f3d9cb741;p=platform%2Fcore%2Fuifw%2Fstt.git diff --git a/server/sttd_recorder.c b/server/sttd_recorder.c index da65b56..6b19499 100644 --- a/server/sttd_recorder.c +++ b/server/sttd_recorder.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2011-2016 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 @@ -11,697 +11,622 @@ * limitations under the License. */ +#ifdef TV_PRODUCT +#define TV_BT_MODE +#endif -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#ifdef TV_BT_MODE +#include +#endif -/* private Header */ +#include "stt_defs.h" +#include "sttd_dbus.h" #include "sttd_recorder.h" #include "sttd_main.h" -/* Contant values */ -#define DEF_TIMELIMIT 120 -#define DEF_SAMPLERATE 16000 -#define DEF_BITRATE_AMR 12200 -#define DEF_MAXSIZE 1024 * 1024 * 5 -#define DEF_SOURCECHANNEL 1 -#define DEF_BUFFER_SIZE 1024 -/* Sound buf save */ -//#define BUF_SAVE_MODE - -typedef struct { - unsigned int size_limit; - unsigned int time_limit; - unsigned int now; - unsigned int now_ms; - unsigned int frame; - float volume; +#define FRAME_LENGTH 160 +#define BUFFER_LENGTH FRAME_LENGTH * 2 - /* For MMF */ - unsigned int bitrate; - unsigned int samplerate; - sttd_recorder_channel channel; - sttd_recorder_state state; - sttd_recorder_audio_type audio_type; +static pthread_mutex_t sttd_audio_in_handle_mutex = PTHREAD_MUTEX_INITIALIZER; - sttvr_audio_cb streamcb; +typedef enum { + STTD_RECORDER_STATE_NONE = -1, + STTD_RECORDER_STATE_READY = 0, /**< Recorder is ready to start */ + STTD_RECORDER_STATE_RECORDING /**< In the middle of recording */ +} sttd_recorder_state; - MMHandleType rec_handle; - MMHandleType ply_handle; -} sttd_recorder_s; - - -static sttd_recorder_s *g_objRecorer = NULL; -static bool g_init = false; +typedef struct { + int uid; + audio_in_h audio_h; + stte_audio_type_e audio_type; +} stt_recorder_s; -static char g_temp_file_name[128] = {'\0',}; +static stt_recorder_s* g_recorder = NULL; -/* Recorder obj */ -sttd_recorder_s *__recorder_getinstance(); -void __recorder_state_set(sttd_recorder_state state); +static stt_recorder_audio_cb g_audio_cb; -/* MMFW caller */ -int __recorder_setup(); -int __recorder_run(); -int __recorder_pause(); -int __recorder_send_buf_from_file(); +static sound_stream_info_h g_stream_info_h; -int __recorder_cancel_to_stop(); -int __recorder_commit_to_stop(); +static stt_recorder_interrupt_cb g_interrupt_cb; +static sttd_recorder_state g_recorder_state = STTD_RECORDER_STATE_NONE; -/* Event Callback Function */ -gboolean _mm_recorder_audio_stream_cb (MMCamcorderAudioStreamDataType *stream, void *user_param) -{ - sttd_recorder_s *pVr = __recorder_getinstance(); +static int g_buffer_count; - if (stream->length > 0 && stream->data) { - pVr->frame++; - - /* If stream callback is set */ - if (STTD_RECORDER_PCM_S16 == pVr->audio_type || STTD_RECORDER_PCM_U8 == pVr->audio_type) { +/* Sound buf save for test */ +/* +#define BUF_SAVE_MODE +*/ #ifdef BUF_SAVE_MODE - /* write pcm buffer */ - fwrite(stream->data, 1, stream->length, g_pFile); -#else - if (pVr->streamcb) { - pVr->streamcb(stream->data, stream->length); - } -#endif - } - } - - return TRUE; -} - +static char g_temp_file_name[128] = {'\0',}; -int _camcorder_message_cb (int id, void *param, void *user_param) -{ - MMMessageParamType *m = (MMMessageParamType *)param; +static FILE* g_pFile; - sttd_recorder_s *pVr = __recorder_getinstance(); +static int g_count = 1; +#endif - if (pVr) { - switch(id) { - case MM_MESSAGE_CAMCORDER_STATE_CHANGED_BY_ASM: - break; - case MM_MESSAGE_CAMCORDER_STATE_CHANGED: - break; - case MM_MESSAGE_CAMCORDER_MAX_SIZE: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] MM_MESSAGE_CAMCORDER_MAX_SIZE"); - sttd_recorder_stop(); - break; - case MM_MESSAGE_CAMCORDER_NO_FREE_SPACE: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] MM_MESSAGE_CAMCORDER_NO_FREE_SPACE"); - sttd_recorder_cancel(); - break; - case MM_MESSAGE_CAMCORDER_TIME_LIMIT: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] MM_MESSAGE_CAMCORDER_TIME_LIMIT"); - sttd_recorder_stop(); - break; - case MM_MESSAGE_CAMCORDER_ERROR: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] MM_MESSAGE_CAMCORDER_ERROR"); - sttd_recorder_cancel(); - break; - case MM_MESSAGE_CAMCORDER_RECORDING_STATUS: - break; - case MM_MESSAGE_CAMCORDER_CURRENT_VOLUME: - pVr->volume = m->rec_volume_dB; - break; - default: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Other Message=%d", id); - break; - } - } else { - return -1; - } +#ifdef TV_BT_MODE +static float get_volume_decibel(char* data, int size, stte_audio_type_e type); - return 0; -} +//static stt_recorder_s* __get_recorder(int engine_id); +static int g_bt_extend_count; -sttd_recorder_s *__recorder_getinstance() -{ - if (!g_objRecorer) { - g_objRecorer = NULL; - g_objRecorer = g_malloc0(sizeof(sttd_recorder_s)); - - /* set default value */ - g_objRecorer->time_limit = DEF_TIMELIMIT; - g_objRecorer->size_limit = DEF_MAXSIZE; - g_objRecorer->now = 0; - g_objRecorer->now_ms = 0; - g_objRecorer->frame = 0; - g_objRecorer->volume = 0.0f; - g_objRecorer->state = STTD_RECORDER_STATE_READY; - g_objRecorer->channel = STTD_RECORDER_CHANNEL_MONO; - g_objRecorer->audio_type = STTD_RECORDER_PCM_S16; - g_objRecorer->samplerate = DEF_SAMPLERATE; - g_objRecorer->streamcb = NULL; - } - - return g_objRecorer; -} +#define SMART_CONTROL_EXTEND_CMD 0x03 +#define SMART_CONTROL_START_CMD 0x04 -void __recorder_state_set(sttd_recorder_state state) +static void _bt_cb_hid_state_changed(int result, bool connected, const char *remote_address, void *user_data) { - sttd_recorder_s* pVr = __recorder_getinstance(); - pVr->state = state; + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Bluetooth Event [%d] Received address [%s]", result, remote_address); } -void __recorder_remove_temp_file() +static void _bt_hid_audio_data_receive_cb(bt_hid_voice_data_s *voice_data, void *user_data) { - /* NOTE: temp file can cause permission problem */ - if (0 != access(g_temp_file_name, R_OK|W_OK)) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] *** You don't have access right to temp file"); - } else { - if (0 != remove(g_temp_file_name)) { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to remove temp file"); - } + if (STTD_RECORDER_STATE_RECORDING != g_recorder_state) { + /* SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Exit audio reading normal func"); */ + return; } -} + if (NULL != g_audio_cb) { + if (0 != g_audio_cb((void*)voice_data->audio_buf, (unsigned int)voice_data->length)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to read audio"); + sttd_recorder_stop(); + } -/* MMFW Interface functions */ -int __recorder_setup() -{ - sttd_recorder_s *pVr = __recorder_getinstance(); - - /* mm-camcorder preset */ - MMCamPreset cam_info; - - int mmf_ret = MM_ERROR_NONE; - int err = 0; - char* err_attr_name = NULL; - - cam_info.videodev_type = MM_VIDEO_DEVICE_NONE; + if (NULL == g_recorder) { + return; + } - /* Create camcorder */ - mmf_ret = mm_camcorder_create( &pVr->rec_handle, &cam_info); - if (MM_ERROR_NONE != mmf_ret) { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail mm_camcorder_create ret=(%X)", mmf_ret); - return mmf_ret; + float vol_db = get_volume_decibel((char*)voice_data->audio_buf, (int)voice_data->length, g_recorder->audio_type); + if (0 != sttdc_send_set_volume(g_recorder->uid, vol_db)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder] Fail to send recording volume(%f)", vol_db); + } } - switch (pVr->audio_type) { - case STTD_RECORDER_PCM_U8: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] STTD_RECORDER_PCM_U8"); - err = mm_camcorder_set_attributes(pVr->rec_handle, - &err_attr_name, - MMCAM_MODE, MM_CAMCORDER_MODE_AUDIO, - MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, + if (0 == g_buffer_count || 0 == g_buffer_count % 50) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, voice_data->length); - MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC, - MMCAM_FILE_FORMAT, MM_FILE_FORMAT_3GP, - - MMCAM_AUDIO_SAMPLERATE, pVr->samplerate, - MMCAM_AUDIO_FORMAT, MM_CAMCORDER_AUDIO_FORMAT_PCM_U8, - MMCAM_AUDIO_CHANNEL, pVr->channel, - MMCAM_AUDIO_INPUT_ROUTE, MM_AUDIOROUTE_CAPTURE_NORMAL, - NULL ); - - if (MM_ERROR_NONE != err) { - /* Error */ - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail mm_camcorder_set_attributes ret=(%X)", mmf_ret); - return err; + if (0 == g_bt_extend_count % 5 && 0 != g_buffer_count) { + const unsigned char input_data[2] = {SMART_CONTROL_EXTEND_CMD, 0x10 }; + if (BT_ERROR_NONE != bt_hid_send_rc_command(NULL, input_data, sizeof(input_data))) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail bt_hid_send_rc_command(NULL, %s, %d)", input_data, sizeof(input_data)); + } else { + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Extend bt audio recorder"); + } } - - break; + g_bt_extend_count++; - case STTD_RECORDER_PCM_S16: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] STTD_RECORDER_PCM_S16"); - err = mm_camcorder_set_attributes(pVr->rec_handle, - &err_attr_name, - MMCAM_MODE, MM_CAMCORDER_MODE_AUDIO, - MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, - MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC, - MMCAM_FILE_FORMAT, MM_FILE_FORMAT_3GP, - MMCAM_AUDIO_SAMPLERATE, pVr->samplerate, - MMCAM_AUDIO_FORMAT, MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE, - MMCAM_AUDIO_CHANNEL, pVr->channel, - MMCAM_AUDIO_INPUT_ROUTE, MM_AUDIOROUTE_CAPTURE_NORMAL, - NULL ); - - if (MM_ERROR_NONE != err) { - /* Error */ - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail mm_camcorder_set_attributes ret=(%X)", mmf_ret); - return err; + if (100000 == g_buffer_count) { + g_buffer_count = 0; } - break; - - case STTD_RECORDER_AMR: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] STTD_RECORDER_AMR"); - err = mm_camcorder_set_attributes(pVr->rec_handle, - &err_attr_name, - MMCAM_MODE, MM_CAMCORDER_MODE_AUDIO, - MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, - - MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AMR, - MMCAM_FILE_FORMAT, MM_FILE_FORMAT_AMR, + } - MMCAM_AUDIO_SAMPLERATE, pVr->samplerate, - MMCAM_AUDIO_CHANNEL, pVr->channel, + g_buffer_count++; - MMCAM_AUDIO_INPUT_ROUTE, MM_AUDIOROUTE_CAPTURE_NORMAL, - MMCAM_TARGET_TIME_LIMIT, pVr->time_limit, - MMCAM_TARGET_FILENAME, g_temp_file_name, strlen(g_temp_file_name)+1, - NULL ); +#ifdef BUF_SAVE_MODE + /* write pcm buffer */ + fwrite(data, 1, len, g_pFile); +#endif + return; +} +#endif - if (MM_ERROR_NONE != err) { - /* Error */ - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail mm_camcorder_set_attributes ret=(%X)", mmf_ret); - return err; - } - break; - default: - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder ERROR]"); - return -1; - break; +const char* __stt_get_focus_changed_reason_code(sound_stream_focus_change_reason_e reason) +{ + switch (reason) { + case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA: return "SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA"; + case SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM: return "SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM"; + case SOUND_STREAM_FOCUS_CHANGED_BY_ALARM: return "SOUND_STREAM_FOCUS_CHANGED_BY_ALARM"; + case SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION: return "SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION"; + case SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY: return "SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY"; + case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION: return "SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION"; + case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION: return "SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION"; + case SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE: return "SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE"; + case SOUND_STREAM_FOCUS_CHANGED_BY_VOIP: return "SOUND_STREAM_FOCUS_CHANGED_BY_VOIP"; + case SOUND_STREAM_FOCUS_CHANGED_BY_CALL: return "SOUND_STREAM_FOCUS_CHANGED_BY_CALL"; + case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA_EXTERNAL_ONLY: return "SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA_EXTERNAL_ONLY"; + default: return "Undefined reason code"; } +} - mmf_ret = mm_camcorder_set_audio_stream_callback(pVr->rec_handle, (mm_camcorder_audio_stream_callback)_mm_recorder_audio_stream_cb, NULL); - if (MM_ERROR_NONE != err) { - /* Error */ - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail mm_camcorder_set_audio_stream_callback ret=(%X)", mmf_ret); - return err; - } - - mmf_ret = mm_camcorder_set_message_callback(pVr->rec_handle, (MMMessageCallback)_camcorder_message_cb, pVr); - if (MM_ERROR_NONE != err) { - /* Error */ - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail mm_camcorder_set_message_callback ret=(%X)", mmf_ret); - return err; - } +void __recorder_focus_state_cb(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_e focus_state, + sound_stream_focus_change_reason_e reason, int sound_behavior, const char *extra_info, void *user_data) +{ + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Focus state changed cb"); - mmf_ret = mm_camcorder_realize(pVr->rec_handle); - if (MM_ERROR_NONE != err) { - /* Error */ - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail mm_camcorder_realize=(%X)", mmf_ret); - return err; + if (stream_info != g_stream_info_h) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Invalid stream info handle"); + return; } + SLOG(LOG_WARN, TAG_STTD, "[Recorder] focus state changed to (%d) with reason(%s)", (int)focus_state, __stt_get_focus_changed_reason_code(reason)); - /* Camcorder start */ - mmf_ret = mm_camcorder_start(pVr->rec_handle); - if (MM_ERROR_NONE != mmf_ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail mm_camcorder_start=(%X)", mmf_ret); - return mmf_ret; + if (STTD_RECORDER_STATE_RECORDING == g_recorder_state && SOUND_STREAM_FOCUS_STATE_RELEASED == focus_state) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder] Focus released as interrupt"); + if (NULL != g_interrupt_cb) { + g_interrupt_cb(); + } } - - SLOG(LOG_DEBUG, TAG_STTD, " - size_limit=%3d", pVr->size_limit); - SLOG(LOG_DEBUG, TAG_STTD, " - time_limit=%3d", pVr->time_limit); - SLOG(LOG_DEBUG, TAG_STTD, " - Audio Type=%d", pVr->audio_type); - SLOG(LOG_DEBUG, TAG_STTD, " - Sample rates=%d", pVr->samplerate); - SLOG(LOG_DEBUG, TAG_STTD, " - channel=%d", pVr->channel); - - return 0; } -int __recorder_run() -{ - sttd_recorder_s *pVr = __recorder_getinstance(); - int mmf_ret = MM_ERROR_NONE; - /* If recorder already has recording state, cancel */ - if (STTD_RECORDER_STATE_RECORDING == pVr->state) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Stop recording first"); - __recorder_cancel_to_stop(); +int sttd_recorder_initialize(stt_recorder_audio_cb audio_cb, stt_recorder_interrupt_cb interrupt_cb) +{ + if (NULL == audio_cb || NULL == interrupt_cb) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Input param is NOT valid"); + return STTD_ERROR_INVALID_PARAMETER; } - - /* Reset frame number */ - pVr->frame = 0; - /* Record start */ - mmf_ret = mm_camcorder_record(pVr->rec_handle); - if(MM_ERROR_NONE != mmf_ret ) { - /* Error */ - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail mm_camcorder_record=(%X)", mmf_ret); - return mmf_ret; + if (STTD_RECORDER_STATE_NONE != g_recorder_state) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Current state of recorder is recording"); + return STTD_ERROR_INVALID_STATE; } - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Success mm_camcorder_record"); - return 0; -} + if (0 != pthread_mutex_init(&sttd_audio_in_handle_mutex, NULL)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to initialize audio in handle mutex."); + } -int __recorder_pause() -{ - sttd_recorder_s *pVr = __recorder_getinstance(); - int mmf_ret = MM_ERROR_NONE; - MMCamcorderStateType state_now = MM_CAMCORDER_STATE_NONE; + g_audio_cb = audio_cb; + g_interrupt_cb = interrupt_cb; + g_recorder_state = STTD_RECORDER_STATE_NONE; + g_recorder = NULL; - /* Get state from MMFW */ - mmf_ret = mm_camcorder_get_state(pVr->rec_handle, &state_now); - if(mmf_ret != MM_ERROR_NONE ) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to get state : mm_camcorder_get_state"); - return mmf_ret; + if (0 != sound_manager_create_stream_information(SOUND_STREAM_TYPE_VOICE_RECOGNITION, __recorder_focus_state_cb, NULL, &g_stream_info_h)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to create stream info"); } - /* Check recording state */ - if(MM_CAMCORDER_STATE_RECORDING != state_now) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Not recording state"); - return mmf_ret; +#ifdef TV_BT_MODE + if (BT_ERROR_NONE != bt_initialize()) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to init bt"); + return STTD_ERROR_OPERATION_FAILED; } - /* Pause recording */ - mmf_ret = mm_camcorder_pause(pVr->rec_handle); - if(mmf_ret == MM_ERROR_NONE ) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] mm_camcorder_pause OK"); - return mmf_ret; + if (BT_ERROR_NONE != bt_hid_host_initialize(_bt_cb_hid_state_changed, NULL)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail bt_hid_host_initialize()"); + return STTD_ERROR_OPERATION_FAILED; } +#endif return 0; } -int __recorder_cancel_to_stop() +int sttd_recorder_deinitialize() { - sttd_recorder_s *pVr = __recorder_getinstance(); - int mmf_ret = MM_ERROR_NONE; - MMCamcorderStateType rec_status = MM_CAMCORDER_STATE_NONE; - - /* Cancel camcorder */ - mmf_ret = mm_camcorder_cancel(pVr->rec_handle); - if(mmf_ret != MM_ERROR_NONE ) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to mm_camcorder_cancel"); - return -1; + if (0 != pthread_mutex_destroy(&sttd_audio_in_handle_mutex)) { + SLOG(LOG_ERROR, TAG_STTD, "[Server ERROR] Fail to destroy audio in handle mutex."); } - /* Stop camcorder */ - mmf_ret = mm_camcorder_stop(pVr->rec_handle); - if(mmf_ret != MM_ERROR_NONE ) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to mm_camcorder_stop"); - return -1; + if (0 != sound_manager_destroy_stream_information(g_stream_info_h)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to destroy stream info"); } - /* Release resouces */ - mm_camcorder_get_state(pVr->rec_handle, &rec_status); - if (MM_CAMCORDER_STATE_READY == rec_status) { - mmf_ret = mm_camcorder_unrealize(pVr->rec_handle); - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Call mm_camcorder_unrealize ret=(%X)", mmf_ret); + if (NULL != g_recorder) { + audio_in_destroy(g_recorder->audio_h); + g_recorder->audio_h = NULL; + free(g_recorder); + g_recorder = NULL; } - return 0; -} +#ifdef __UNUSED_CODES__ + /* Remove all recorder */ + GSList *iter = NULL; + stt_recorder_s *recorder = NULL; + iter = g_slist_nth(g_recorder_list, 0); -int __recorder_commit_to_stop() -{ - sttd_recorder_s *pVr = __recorder_getinstance(); - int mmf_ret = MM_ERROR_NONE; - MMCamcorderStateType rec_status = MM_CAMCORDER_STATE_NONE; + while (NULL != iter) { + recorder = iter->data; - /* Commit camcorder */ - mmf_ret = mm_camcorder_commit(pVr->rec_handle); - if(mmf_ret != MM_ERROR_NONE ) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail mm_camcorder_commit=%x", mmf_ret); - } + if (NULL != recorder) { + g_recorder_list = g_slist_remove(g_recorder_list, recorder); + if (recorder->audio_h) { + audio_in_destroy(recorder->audio_h); + recorder->audio_h = NULL; + } + free(recorder); + } - /* Stop camcorder */ - mmf_ret = mm_camcorder_stop(pVr->rec_handle); - if(mmf_ret != MM_ERROR_NONE ) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail mm_camcorder_stop=%x", mmf_ret); + iter = g_slist_nth(g_recorder_list, 0); } +#endif - /* Release resouces */ - mm_camcorder_get_state(pVr->rec_handle, &rec_status); - if (MM_CAMCORDER_STATE_READY == rec_status) { - mmf_ret = mm_camcorder_unrealize(pVr->rec_handle); - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Call mm_camcorder_unrealize ret=(%X)", mmf_ret); - } +#ifdef TV_BT_MODE + bt_hid_host_deinitialize(); + + bt_deinitialize(); +#endif + + g_recorder_state = STTD_RECORDER_STATE_NONE; return 0; } +int sttd_recorder_set_audio_session() +{ + return 0; +} -int __recorder_send_buf_from_file() +int sttd_recorder_unset_audio_session() { - sttd_recorder_s *pVr = __recorder_getinstance(); + return 0; +} - FILE * pFile; - if (!pVr->streamcb) { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Return callback is not set"); - return -1; +int sttd_recorder_create(stte_audio_type_e type, int channel, unsigned int sample_rate) +{ + /* Check engine id is valid */ + if (NULL != g_recorder) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is already registered"); + return STTD_ERROR_INVALID_PARAMETER; } - if (STTD_RECORDER_AMR != pVr->audio_type) { -#ifndef BUF_SAVE_MODE - return 0; -#else - fclose(g_pFile); -#endif - } + audio_in_h temp_in_h = NULL; - pFile = fopen(g_temp_file_name, "rb"); - if (!pFile) { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] File not found!"); - return -1; +#ifndef TV_BT_MODE + 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_STTD, "[Recorder ERROR] Input channel is not supported"); + return STTD_ERROR_OPERATION_FAILED; + break; } - char buff[1024]; - size_t read_size = 0; - int ret = 0; - - while (!feof(pFile)) { - read_size = fread(buff, 1, 1024, pFile); - if (read_size > 0) { - ret = pVr->streamcb((void*)buff, read_size); + switch (type) { + case STTE_AUDIO_TYPE_PCM_S16_LE: audio_type = AUDIO_SAMPLE_TYPE_S16_LE; break; + case STTE_AUDIO_TYPE_PCM_U8: audio_type = AUDIO_SAMPLE_TYPE_U8; break; + default: + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Invalid Audio Type"); + return STTD_ERROR_OPERATION_FAILED; + break; + } - if(ret != 0) { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to set recording"); - break; - } + int ret; + ret = audio_in_create(sample_rate, audio_ch, audio_type, &temp_in_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to create audio handle : %d", ret); + return STTD_ERROR_OPERATION_FAILED; + } +#else + if (BT_ERROR_NONE != bt_hid_set_audio_data_receive_cb(_bt_hid_audio_data_receive_cb, NULL)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail bt_hid_set_audio_data_receive_cb()"); + return STTD_ERROR_OPERATION_FAILED; + } +#endif + + stt_recorder_s* recorder; + recorder = (stt_recorder_s*)calloc(1, sizeof(stt_recorder_s)); + if (NULL == recorder) { +#ifndef TV_BT_MODE + if (temp_in_h) { + audio_in_destroy(temp_in_h); + temp_in_h = NULL; } +#endif + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to allocate memory"); + return STTD_ERROR_OUT_OF_MEMORY; } - fclose(pFile); + recorder->uid = -1; + recorder->audio_h = temp_in_h; + recorder->audio_type = type; + + g_recorder = recorder; + + g_recorder_state = STTD_RECORDER_STATE_READY; return 0; } -int __vr_mmcam_destroy() +int sttd_recorder_destroy() { - int err = 0; - sttd_recorder_s *pVr = __recorder_getinstance(); - - MMCamcorderStateType rec_status = MM_CAMCORDER_STATE_NONE; - - mm_camcorder_get_state(pVr->rec_handle, &rec_status); - if (rec_status == MM_CAMCORDER_STATE_NULL) { - err = mm_camcorder_destroy(pVr->rec_handle); - - if (MM_ERROR_NONE == err) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] mm_camcorder_destroy OK"); - pVr->rec_handle = 0; - } else { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Error mm_camcorder_destroy %x", err); + // critical section required because this function can be called from stt engine thread context + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Enter critical section"); + pthread_mutex_lock(&sttd_audio_in_handle_mutex); + + /* Check engine id is valid */ + if (NULL == g_recorder) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid"); + pthread_mutex_unlock(&sttd_audio_in_handle_mutex); + return STTD_ERROR_INVALID_PARAMETER; + } + +#ifndef TV_BT_MODE + int ret; + if (STTD_RECORDER_STATE_RECORDING == g_recorder_state) { + if (g_recorder->audio_h) { + ret = audio_in_unprepare(g_recorder->audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to unprepare audioin : %d", ret); + } } + g_recorder_state = STTD_RECORDER_STATE_READY; } - return 0; -} - + if (g_recorder->audio_h) { + ret = audio_in_destroy(g_recorder->audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to destroy audioin : %d", ret); + } + g_recorder->audio_h = NULL; + } -/* External functions */ -int sttd_recorder_init() -{ - /* Create recorder instance */ - sttd_recorder_s *pVr = __recorder_getinstance(); - if (!pVr) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to initialize voice recorder!"); - return -1; +#else + if (STTD_RECORDER_STATE_RECORDING == g_recorder_state) { + g_recorder_state = STTD_RECORDER_STATE_READY; } - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Voice Recorder Initialized p=%p", pVr); - /* Set temp file name */ - snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/stt_temp_%d", getpid()); - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Temp file name=[%s]", g_temp_file_name); + bt_hid_unset_audio_data_receive_cb(); +#endif + + free(g_recorder); + g_recorder = NULL; - g_init = true; + pthread_mutex_unlock(&sttd_audio_in_handle_mutex); + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Leave critical section"); return 0; } -int sttd_recorder_set(sttd_recorder_audio_type type, sttd_recorder_channel ch, unsigned int sample_rate, - unsigned int max_time, sttvr_audio_cb cbfunc) +static float get_volume_decibel(char* data, int size, stte_audio_type_e type) { - sttd_recorder_s *pVr = __recorder_getinstance(); - int ret = 0; - - if (STTD_RECORDER_STATE_RECORDING == pVr->state) - __recorder_cancel_to_stop(); - - if (STTD_RECORDER_STATE_READY != pVr->state) - __vr_mmcam_destroy(); + #define MAX_AMPLITUDE_MEAN_16 32768 + #define MAX_AMPLITUDE_MEAN_08 128 + + int i, depthByte; + int count = 0; + + float db = 0.0; + float rms = 0.0; + unsigned long long square_sum = 0; + + if (type == STTE_AUDIO_TYPE_PCM_S16_LE) + depthByte = 2; + else + depthByte = 1; + + for (i = 0; i < size; i += (depthByte<<1)) { + if (depthByte == 2) { + short pcm16 = 0; + memcpy(&pcm16, data + i, sizeof(short)); + square_sum += pcm16 * pcm16; + } else { + char pcm8 = 0; + memcpy(&pcm8, data + i, sizeof(char)); + square_sum += pcm8 * pcm8; + } + count++; + } - /* Set attributes */ - pVr->audio_type = type; - pVr->channel = ch; - pVr->samplerate = sample_rate; - pVr->time_limit = max_time; + if (0 == count) + rms = 0.0; + else + rms = sqrt((double)square_sum/count); - /* Stream data Callback function */ - if (cbfunc) - pVr->streamcb = cbfunc; + if (depthByte == 2) + db = 20 * log10(rms/MAX_AMPLITUDE_MEAN_16); + else + db = 20 * log10(rms/MAX_AMPLITUDE_MEAN_08); - return ret; + return db; } -int sttd_recorder_start() +#ifndef TV_BT_MODE +Eina_Bool __read_audio_func(void *data) { - int ret = 0; + int read_byte = -1; + static char g_buffer[BUFFER_LENGTH]; - __recorder_remove_temp_file(); - -#ifdef BUF_SAVE_MODE - sttd_recorder_s *pVr = __recorder_getinstance(); - if (!pVr) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to initialize voice recorder!"); - return -1; + /* Check engine id is valid */ + if (NULL == g_recorder) { + return EINA_FALSE; } - if (STTD_RECORDER_AMR != pVr->audio_type) { - /* open test file */ - g_pFile = fopen(g_temp_file_name, "wb+"); - if (!g_pFile) { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] File not found!"); - return -1; - } + if (STTD_RECORDER_STATE_READY == g_recorder_state) { + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Exit audio reading func"); + return EINA_FALSE; } -#endif - /* Check if initialized */ - ret = __recorder_setup(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __recorder_setup"); + read_byte = audio_in_read(g_recorder->audio_h, g_buffer, BUFFER_LENGTH); + if (0 > read_byte) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Fail to read audio : %d", read_byte); + g_recorder_state = STTD_RECORDER_STATE_READY; + return EINA_FALSE; } - /* Start camcorder */ - ret = __recorder_run(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __recorder_run"); + if (0 != g_audio_cb(g_buffer, read_byte)) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Fail audio callback"); + sttd_recorder_stop(); + return EINA_FALSE; } - __recorder_state_set(STTD_RECORDER_STATE_RECORDING); - - return 0; -} - - -int sttrecorder_pause() -{ - int ret = 0; - - ret = __recorder_pause(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __recorder_pause"); - return -1; + if (0 == g_buffer_count % 30) { + float vol_db = get_volume_decibel(g_buffer, BUFFER_LENGTH, g_recorder->audio_type); + if (0 != sttdc_send_set_volume(g_recorder->uid, vol_db)) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder] Fail to send recording volume(%f)", vol_db); + } } - /* Set state */ - __recorder_state_set(STTD_RECORDER_STATE_PAUSED); + /* Audio read log */ + if (0 == g_buffer_count % 50) { + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder][%d] Recording... : read_size(%d)", g_buffer_count, read_byte); - return 0; -} - -int sttd_recorder_cancel() -{ - int ret = 0; - ret = __recorder_cancel_to_stop(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __recorder_cancel_to_stop"); - return -1; + if (100000 == g_buffer_count) { + g_buffer_count = 0; + } } - ret = __vr_mmcam_destroy(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __vr_mmcam_destroy"); - return -1; - } + g_buffer_count++; - /* Set state */ - __recorder_state_set(STTD_RECORDER_STATE_READY); +#ifdef BUF_SAVE_MODE + /* write pcm buffer */ + fwrite(g_buffer, 1, BUFFER_LENGTH, g_pFile); +#endif - return 0; + return EINA_TRUE; } +#endif - -int sttd_recorder_stop() +int sttd_recorder_start(int uid) { - int ret = 0; + if (STTD_RECORDER_STATE_RECORDING == g_recorder_state) + return 0; - ret = __recorder_commit_to_stop(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __recorder_commit_to_stop"); - return -1; + int ret = -1; +#ifndef TV_BT_MODE + /* Check engine id is valid */ + if (NULL == g_recorder) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid"); + return STTD_ERROR_INVALID_PARAMETER; } - ret = __recorder_send_buf_from_file(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __recorder_send_buf_from_file"); - return -1; - } - - ret = __vr_mmcam_destroy(); - if (ret) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to call __vr_mmcam_destroy"); - return -1; + ret = sound_manager_acquire_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_RECORDING, SOUND_BEHAVIOR_NONE, NULL); + if (SOUND_MANAGER_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to acquire focus : %d", ret); + } else { + ret = audio_in_set_sound_stream_info(g_recorder->audio_h, g_stream_info_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to set stream info"); + } } - __recorder_state_set(STTD_RECORDER_STATE_READY); - - return 0; -} + ret = audio_in_prepare(g_recorder->audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to start audio : %d", ret); + return STTD_ERROR_RECORDER_BUSY; + } + /* Add ecore timer to read audio data */ + ecore_timer_add(0, __read_audio_func, NULL); -int sttd_recorder_destroy() -{ - /* Destroy recorder object */ - if (g_objRecorer) - g_free(g_objRecorer); +#else + g_bt_extend_count = 0; + const unsigned char input_data[2] = {SMART_CONTROL_START_CMD, 0x00 }; + int bt_retry = 0; + bool started = false; + while (5 > bt_retry) { + ret = bt_hid_send_rc_command(NULL, input_data, sizeof(input_data)); + if (BT_ERROR_NONE == ret) { + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Start bt audio recorder"); + started = true; + break; + } else if (BT_ERROR_NOW_IN_PROGRESS == ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail bt_hid_send_rc_command(NULL, %s, %d)", input_data, sizeof(input_data)); + usleep(50000); + bt_retry++; + } else { + break; + } + } + if (false == started) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to start bt audio"); + return STTD_ERROR_OPERATION_FAILED; + } +#endif + g_recorder_state = STTD_RECORDER_STATE_RECORDING; + g_recorder->uid = uid; - g_objRecorer = NULL; - - __recorder_state_set(STTD_RECORDER_STATE_READY); + g_buffer_count = 0; - return 0; -} +#ifdef BUF_SAVE_MODE + g_count++; + snprintf(g_temp_file_name, sizeof(g_temp_file_name), "/tmp/stt_temp_%d_%d", getpid(), g_count); + SECURE_SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Temp file name=[%s]", g_temp_file_name); -int sttd_recorder_state_get(sttd_recorder_state* state) -{ - sttd_recorder_s *pVr = __recorder_getinstance(); - if (!pVr) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to get instance"); + /* open test file */ + g_pFile = fopen(g_temp_file_name, "wb+"); + if (!g_pFile) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] File not found!"); return -1; } - - *state = pVr->state; +#endif return 0; } - -int sttd_recorder_get_volume(float *vol) +int sttd_recorder_stop() { - sttd_recorder_state state; + if (STTD_RECORDER_STATE_READY == g_recorder_state) + return 0; - sttd_recorder_s *pVr = __recorder_getinstance(); - if (!pVr) { - SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Fail to get instance"); - return -1; + /* Check engine id is valid */ + if (NULL == g_recorder) { + SLOG(LOG_WARN, TAG_STTD, "[Recorder WARNING] Engine id is not valid"); + return STTD_ERROR_INVALID_PARAMETER; } - sttd_recorder_state_get(&state); - if (STTD_RECORDER_STATE_RECORDING != state) { - SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Not in Recording state"); - return -1; + g_recorder->uid = -1; + + int ret = -1; +#ifndef TV_BT_MODE + ret = audio_in_unprepare(g_recorder->audio_h); + if (AUDIO_IO_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to unprepare audioin : %d", ret); + } +#else + int bt_retry = 0; + bool stopped = false; + while (5 > bt_retry) { + ret = bt_hid_rc_stop_sending_voice(NULL); + if (BT_ERROR_NONE == ret) { + SLOG(LOG_DEBUG, TAG_STTD, "[Recorder] Stop bt audio"); + stopped = true; + break; + } else if (BT_ERROR_NOW_IN_PROGRESS == ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail bt_hid_rc_stop_sending_voice()"); + usleep(50000); + bt_retry++; + } else { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] bt_hid_rc_stop_sending_voice(): ret(%d)", ret); + break; + } + } + if (false == stopped) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to stop bt audio(%d)", ret); +// return STTD_ERROR_OPERATION_FAILED; } - *vol = pVr->volume; +#endif + + g_recorder_state = STTD_RECORDER_STATE_READY; + + ret = sound_manager_release_focus(g_stream_info_h, SOUND_STREAM_FOCUS_FOR_RECORDING, SOUND_BEHAVIOR_NONE, NULL); + if (SOUND_MANAGER_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_STTD, "[Recorder ERROR] Fail to release focus :%d", ret); + } + +#ifdef BUF_SAVE_MODE + fclose(g_pFile); +#endif return 0; }