blob: eb63e4bb6b7c1dacee5b9b9ca8ed839cc78ea58b [file] [log] [blame]
#include "AudioParamParser.h"
#include "AudioParamParserPriv.h"
#include "xml_parser_def.h"
#include "default_para.h"
#include "speech_drv.h"
#include "modem_afe_ctrl.h"
#include "audio_ctrl_service_inner_api.h"
#include "speech_UT_header.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <syslog.h>
#include <samplerate.h>
//#define RECORD_USE_UT_SOURCE
//#define PLAYBACK_USE_UT_SINK
#include <log/log.h>
#define ALOGD SLOGD
#define ALOGI SLOGI
#define ALOGW SLOGW
#define ALOGE SLOGE
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "audio-ctrl-service"
//#define UT_LOG
#ifdef UT_LOG
#define AUDIO_V_LOG ALOGD
#else
#define AUDIO_V_LOG
#endif
#define SPEECH_DRV_RETRY_TIME 3
#define SPEECH_DRV_RETRY_US 20000 //20ms
#define SPEECH_DRV_BGS_INTERVAL_US 20000 //20ms
#define MAX_REC_BUF_SIZE 3200//16000Hz 16bytes 100ms
#define MD_PCM_RECORD_HEADER_SYNC 0x1234
char *g_record_buf;
int g_want_to_speech_off_after_record_off;
int g_record_buf_size;
int g_record_read_virt_idx;
int g_record_write_virt_idx;
int g_record_virt_boundry;
int g_is_bgs_on;
/* SRC for inCall record UL*/
#define RECORD_SRC_BUF_SIZE 160 //in frame
#define RECORD_DST_BUF_SIZE 320 //in frame
#define RECORD_SRC_RATIO 2.0
const int g_converter_type = SRC_SINC_MEDIUM_QUALITY;
SRC_DATA g_incall_record_src_data;
SRC_STATE *g_incall_record_src_state;
float *g_incall_record_src_buffer;
float *g_incall_record_dst_buffer;
int16_t g_incall_record_dst_int_buffer[RECORD_DST_BUF_SIZE];
pthread_mutex_t g_mutex_record = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t g_mutex_playback = PTHREAD_MUTEX_INITIALIZER;
/* modem pcm record package header*/
typedef struct md_pcm_record_header {
uint16_t u16SyncWord;
uint16_t u16RawPcmDir;
uint16_t u16Freq;
uint16_t u16Length;
uint16_t u16Channel;
uint16_t u16BitFormat;
} MD_PCM_RECORD_HEADER;
static void parameterChanged(AppHandle *appHandle, const char *audioTypeName);
static void *speech_flow_upper_func_operator(void *arg);
static void *speech_flow_lower_func_operator(void *arg);
static void *speech_flow_dummy_sender(void *arg);
static void updateVolume(int xmlType);
static void updateDlGain(void);
static void updateUlGain(void);
const struct xml_param paramVolume[PARAM_NUM] = {
{
.id = XML_SPEECH_VOLUME,
.xml_type_name = "SpeechVol",
.update_xml_callback = updateVolume,
},
{
.id = XML_VOLUME,
.xml_type_name = "Volume",
.update_xml_callback = updateVolume,
},
{
.id = XML_GAIN_MAP_DL,
.xml_type_name = "VolumeGainMapUL",
.update_xml_callback = updateVolume,
},
{
.id = XML_GAIN_MAP_UL,
.xml_type_name = "VolumeGainMap",
.update_xml_callback = updateVolume,
},
};
#define DL_VOLUME_IDX_MIN 1
#define DL_VOLUME_IDX_MAX 7
static int g_is_speech_on;
static int g_current_output_device;
static int g_bt_wbs_on = FUNC_SET_BT_WB_default;
static int g_bt_client_has_ecnr;
static int g_volume_index;
static int g_speaker_type;
/* IPC variable*/
static pthread_t g_pthread_speech_flow_upper_rcv;
static pthread_t g_pthread_speech_flow_lower_rcv;
static pthread_t g_pthread_speech_flow_dummy_send;
static int g_ipc_upper_rcv_handler;
static int g_ipc_upper_send_handler;
static int g_ipc_lower_rcv_handler;
static int g_ipc_lower_send_handler;
int main() {
int paramIndex = 0;
AppOps *appOps = NULL;
AppHandle *appHandle = NULL;
struct stat st = {0};
#if !defined(MTK_DUMMY_AUDIO_PARSER)
appOps = appOpsGetInstance();
if (appOps == NULL) {
ALOGE("%s(), line %d ERROR", __func__, __LINE__);
return 1;
} else {
appHandle = appOps->appHandleGetInstance();
/* Wait for initial done */
usleep(100 * 1000);//100ms
/* Set the debug level to warn*/
appOps->appSetDebugLevel(WARN_LEVEL);
/* register callback func */
appOps->appHandleRegXmlChangedCb(appHandle, parameterChanged);
}
#endif
if (stat("/tmp/audio_ctrl_service", &st) == -1) {
mkdir("/tmp/audio_ctrl_service", 0700);
}
/* for service init */
mkfifo(ACS_IPC_FOR_UPPER_RCV, 0600);
mkfifo(ACS_IPC_FOR_UPPER_SEND, 0600);
mkfifo(ACS_IPC_FOR_LOWER_RCV, 0600);
mkfifo(ACS_IPC_FOR_LOWER_SEND, 0600);
pthread_create(&g_pthread_speech_flow_upper_rcv, NULL, speech_flow_upper_func_operator, NULL);
pthread_create(&g_pthread_speech_flow_lower_rcv, NULL, speech_flow_lower_func_operator, NULL);
pthread_create(&g_pthread_speech_flow_dummy_send, NULL, speech_flow_dummy_sender, NULL);
while (1) {
sleep(1000000);
}
#if !defined(MTK_DUMMY_AUDIO_PARSER)
/* Release appHandle resources */
appOps->appHandleUninit(appHandle);
#endif
return 0;
}
static void *speech_flow_upper_func_operator(void *arg) {
char buf[IPC_DATA_SIZE_MAX];
int size = 0, function_type = 0, first_param = 0;
int str_output_size = 0;
int func_result;
char *first_param_str;
char *second_param_str;
char buf_response[IPC_DATA_SIZE_MAX];
char *buf_for_get_data = buf; //use the buffer to get data out for ioplugin
ALOGD("%s()", __func__);
g_ipc_upper_rcv_handler = open(ACS_IPC_FOR_UPPER_RCV, O_RDONLY);
g_ipc_upper_send_handler = open(ACS_IPC_FOR_UPPER_SEND, O_WRONLY);
set_phonecall_rate(PHONECALL_SAMPLE_RATE);
g_volume_index = 4;//valid range: 0~7, 0 for mute
g_current_output_device = AUDIO_DEVICE_OUT_SPEAKER;
g_speaker_type = AUDIO_SPK_EXTAMP_LO;
while (1) {
size = read(g_ipc_upper_rcv_handler, buf, IPC_DATA_SIZE_MAX);
if (!size) {
ALOGE("%s(), IPC data size=%d, reset fifo!", __func__, size);
close(g_ipc_upper_rcv_handler);
g_ipc_upper_rcv_handler = open(ACS_IPC_FOR_UPPER_RCV, O_RDONLY);
continue;
}
/* finish string */
buf[size] = '\0';
/* parse string */
strtok_r(buf, ",", &first_param_str);
function_type = atoi(buf);
AUDIO_V_LOG("%s(), function_type=%d", __func__, function_type);
switch (function_type) {
case FUNC_AUDIO_CTRL_SERVICE_SPEECH_ON:
first_param = atoi(first_param_str);
pthread_mutex_lock(&g_mutex_record); //for g_want_to_speech_off_after_record_off
func_result = audio_ctrl_service_speech_on_inner(first_param, AUDIO_DEVICE_OUT_SPEAKER);
pthread_mutex_unlock(&g_mutex_record);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_M2M_CALL_ON:
first_param = atoi(first_param_str);
strtok_r(first_param_str, ",", &second_param_str);
pthread_mutex_lock(&g_mutex_playback);
func_result = audio_ctrl_service_M2M_Call_on_inner(first_param);
pthread_mutex_unlock(&g_mutex_playback);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_ECALL_ON:
first_param = atoi(first_param_str);
pthread_mutex_lock(&g_mutex_playback);
func_result = audio_ctrl_service_ECall_on_inner(first_param);
pthread_mutex_unlock(&g_mutex_playback);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_SET_DL_VOLUME:
case FUNC_AUDIO_CTRL_SERVICE_SET_BT_DL_GAIN:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_set_volume_index_inner(first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_BT_DL_GAIN:
func_result = audio_ctrl_service_get_volume_index_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_SET_SPEAKER_TYPE:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_set_speaker_type_inner(first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
#if defined(MTK_SPEECH_RECORD_SUPPORT)
case FUNC_AUDIO_CTRL_INCALL_RECORD_START:
first_param = atoi(first_param_str);
pthread_mutex_lock(&g_mutex_record);
func_result = audio_ctrl_service_inCall_record_start_inner(first_param);
pthread_mutex_unlock(&g_mutex_record);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_INCALL_RECORD_STOP:
pthread_mutex_lock(&g_mutex_record);
func_result = audio_ctrl_service_inCall_record_stop_inner();
pthread_mutex_unlock(&g_mutex_record);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_INCALL_RECORD_POINTER:
pthread_mutex_lock(&g_mutex_record);
func_result = audio_ctrl_service_inCall_record_pointer_inner();
pthread_mutex_unlock(&g_mutex_record);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_INCALL_RECORD_GET_WATERMARK:
pthread_mutex_lock(&g_mutex_record);
func_result = audio_ctrl_service_inCall_record_get_watermark_inner();
pthread_mutex_unlock(&g_mutex_record);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_INCALL_RECORD_GET_DATA:
first_param = atoi(first_param_str);
//use the "buf" to get data out for ioplugin
pthread_mutex_lock(&g_mutex_record);
func_result = audio_ctrl_service_inCall_record_get_data_inner
(first_param, buf_for_get_data);
pthread_mutex_unlock(&g_mutex_record);
str_output_size = sprintf(buf_response, "%d,", func_result);
if (func_result > 0) {
memcpy(buf_response + str_output_size, buf_for_get_data,
func_result);
str_output_size += func_result;
}
break;
#endif
#if defined(MTK_SPEECH_BGS_SUPPORT)
case FUNC_AUDIO_CTRL_INCALL_PLAYBACK_START:
pthread_mutex_lock(&g_mutex_playback);
func_result = audio_ctrl_service_inCall_playback_start_inner();
pthread_mutex_unlock(&g_mutex_playback);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_INCALL_PLAYBACK_STOP:
pthread_mutex_lock(&g_mutex_playback);
func_result = audio_ctrl_service_inCall_playback_stop_inner();
pthread_mutex_unlock(&g_mutex_playback);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_INCALL_PLAYBACK_SEND_DATA:
first_param = atoi(first_param_str);
strtok_r(first_param_str, ",", &second_param_str);
pthread_mutex_lock(&g_mutex_playback);
func_result = audio_ctrl_service_inCall_playback_send_data_inner
(first_param, second_param_str);
pthread_mutex_unlock(&g_mutex_playback);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_INCALL_PLAYBACK_SIMULATION:
first_param = atoi(first_param_str);
pthread_mutex_lock(&g_mutex_playback);
func_result = audio_ctrl_service_inCall_playback_simulation(first_param);
pthread_mutex_unlock(&g_mutex_playback);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
#endif
case FUNC_AUDIO_CTRL_SERVICE_IS_SPEECH_ON:
func_result = audio_ctrl_service_is_speech_on_inner(AUDIO_DEVICE_OUT_SPEAKER);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_RECORD_PERIOD_SIZE:
func_result = audio_ctrl_service_get_record_period_size_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_PLAYBACK_PERIOD_SIZE:
func_result = audio_ctrl_service_get_playback_period_size_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_RECORD_MAX_BUFFER_SIZE:
func_result = audio_ctrl_service_get_record_max_buffer_size_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_PLAYBACK_MAX_BUFFER_SIZE:
func_result = audio_ctrl_service_get_playback_max_buffer_size_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
#if defined(MTK_SPEECH_VM_SUPPORT)
case FUNC_AUDIO_CTRL_SERVICE_VMLOG_ON:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_vmlog_on_inner(first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_VMLOG_ON:
func_result = audio_ctrl_service_get_vmlog_on_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
#endif
case FUNC_AUDIO_CTRL_SERVICE_BT_SPEECH_ON:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_speech_on_inner(first_param, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_IS_BT_SPEECH_ON:
func_result = audio_ctrl_service_is_speech_on_inner(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_SET_BT_WBS:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_set_bt_wbs_inner(first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_BT_WBS:
func_result = audio_ctrl_service_get_bt_wbs_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
#if !defined(MTK_AUDIO_BRINGUP)
case FUNC_AUDIO_CTRL_SERVICE_SET_BT_CLIENT_HAS_ECNR:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_set_bt_client_has_ecnr_inner(first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_BT_CLIENT_HAS_ECNR:
func_result = audio_ctrl_service_get_bt_client_has_ecnr_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_SET_USE_BT_IN_CALL:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_set_use_bt_in_call_inner(first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
#endif
case FUNC_AUDIO_CTRL_SERVICE_GET_USE_BT_IN_CALL:
func_result = audio_ctrl_service_get_use_bt_in_call_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_RESET_INNER:
func_result = audio_ctrl_service_reset_inner();
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_SET_DL_MUTE:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_set_mute_inner(SPEECH_DL, first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_SET_UL_MUTE:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_set_mute_inner(SPEECH_UL, first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
case FUNC_AUDIO_CTRL_SERVICE_GET_MUTE:
first_param = atoi(first_param_str);
func_result = audio_ctrl_service_get_mute_inner(first_param);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
default:
break;
}
/*send result*/
write(g_ipc_upper_send_handler, buf_response, str_output_size);
}
close(g_ipc_upper_send_handler);
close(g_ipc_upper_rcv_handler);
}
static void *speech_flow_lower_func_operator(void *arg) {
char buf[IPC_DATA_SIZE_MAX];
int size = 0, function_type = 0, first_param = 0;
int str_output_size = 0;
int func_result;
char *first_param_str;
char *second_param_str;
char buf_response[IPC_DATA_SIZE_MAX];
char *buf_for_get_data = buf; //use the buffer to get data out for ioplugin
AUDIO_V_LOG("%s()", __func__);
g_ipc_lower_rcv_handler = open(ACS_IPC_FOR_LOWER_RCV, O_RDONLY);
g_ipc_lower_send_handler = open(ACS_IPC_FOR_LOWER_SEND, O_WRONLY);
while (1) {
size = read(g_ipc_lower_rcv_handler, buf, IPC_DATA_SIZE_MAX);
if (!size) {
ALOGE("%s(), IPC data size=%d, reset fifo!", __func__, size);
close(g_ipc_lower_rcv_handler);
g_ipc_lower_rcv_handler = open(ACS_IPC_FOR_LOWER_RCV, O_RDONLY);
continue;
}
/* finish string */
buf[size] = '\0';
/* parse string */
strtok_r(buf, ",", &first_param_str);
function_type = atoi(buf);
switch (function_type) {
#if defined(MTK_SPEECH_RECORD_SUPPORT)
case FUNC_AUDIO_CTRL_INCALL_SERVICE_RECORD_DATA_CB:
first_param = atoi(first_param_str);
strtok_r(first_param_str, ",", &second_param_str);
pthread_mutex_lock(&g_mutex_record);
func_result = audio_ctrl_service_inCall_record_data_cb_inner
(first_param, second_param_str);
pthread_mutex_unlock(&g_mutex_record);
str_output_size = sprintf(buf_response, "%d", func_result);
break;
#endif
default:
break;
}
/*send result*/
write(g_ipc_lower_send_handler, buf_response, str_output_size);
}
close(g_ipc_lower_send_handler);
close(g_ipc_lower_rcv_handler);
}
static void *speech_flow_dummy_sender(void *arg) {
int dummy_handler = 0;
AUDIO_V_LOG("%s()", __func__);
dummy_handler = open(ACS_IPC_FOR_UPPER_RCV, O_WRONLY);
dummy_handler = open(ACS_IPC_FOR_LOWER_RCV, O_WRONLY);
while (1) {
sleep(1000000);
}
close(dummy_handler);
}
static void parameterChanged(AppHandle *appHandle, const char *audioTypeName) {
AppOps *appOps = NULL;
int paramIndex;
AUDIO_V_LOG("%s()", __func__);
#if defined(MTK_DUMMY_AUDIO_PARSER)
return;
#else
appOps = appOpsGetInstance();
if (appOps == NULL) {
ALOGE("%s(), LINE %d ERROR", __func__, __LINE__);
return;
}
if (appOps->appHandleReloadAudioType(appHandle, audioTypeName) == APP_ERROR) {
ALOGE("%s(), Reload xml fail! (audioType = %s)", __func__, audioTypeName);
return;
}
for (paramIndex = 0; paramIndex < PARAM_NUM; paramIndex++) {
if (!strcmp(audioTypeName, paramVolume[paramIndex].xml_type_name)
&& paramVolume[paramIndex].update_xml_callback) {
paramVolume[paramIndex].update_xml_callback(paramVolume[paramIndex].id);
}
}
#endif
}
static void updateUlAnalogGain() {
int ul_ana_gain = 0, ret = 0;
/* digital part */
#if !defined(MTK_AUDIO_BRINGUP)
ul_ana_gain = speechdrv_get_ul_analog_gain();
#endif
ALOGD("%s(), get ul analog gain value: %d, valid range(0~30 dB)", __func__, ul_ana_gain);
/* analog part */
ret = set_UL_analog_gain(ul_ana_gain);
if (ret < 0)
ALOGE("%s(), set ul analog volume error, gain value: %d, errno: %d",
__func__, ul_ana_gain, ret);
}
static void updateDlAnalogGain(void) {
int dl_ana_gain = 0, ret = 0;
/* analog part */
#if !defined(MTK_AUDIO_BRINGUP)
dl_ana_gain = speechdrv_get_dl_analog_gain();
#endif
ALOGD("%s(), get dl analog gain value: %d, valid range(-40~8 dB)", __func__, dl_ana_gain);
/* analog part */
ret = set_DL_analog_gain(dl_ana_gain);
if (ret < 0)
ALOGE("%s(), set dl analog volume error, gain value: %d, errno: %d",
__func__, dl_ana_gain, ret);
}
static void updateDigitalGain() {
int ret = 0, retry_counter_analog = 5, retry = 1;
int retry_speech_drv_ite = 0;
int dl_ana_gain = 0;
/* digital part ul/dl*/
do {
#if !defined(MTK_AUDIO_BRINGUP)
ret = speechdrv_set_volume_index(g_volume_index, g_current_output_device);
#endif
++retry_speech_drv_ite;
if (!ret) {
break;
}
usleep(SPEECH_DRV_RETRY_US);
} while (ret && retry_speech_drv_ite < SPEECH_DRV_RETRY_TIME);
if (ret < 0)
ALOGE("%s(), set dl volume index error, g_volume_index: %d, errno: %d",
__func__, g_volume_index, ret);
}
static void updateVolume(int xmlType) {
ALOGD("%s(), xml name = %s", __func__, paramVolume[xmlType].xml_type_name);
updateDigitalGain();
if (xmlType != XML_GAIN_MAP_UL) {
updateDlAnalogGain();
}
if (xmlType != XML_GAIN_MAP_DL) {
updateUlAnalogGain();
}
}
//for bring up
int audio_ctrl_service_speech_on_inner(int enable, int output_device) {
int ret;
int retry_ite = 0;
int device_mode = 0;
int input_device;
int outputDevice;
ALOGD("%s(), enable=%d, output_device=0x%x", __func__, enable, output_device);
if (enable == g_is_speech_on) {
ALOGE("%s(), speech on status no change! g_is_speech_on: %d",
__func__, g_is_speech_on);
return 0;
}
g_is_speech_on = enable;
if (output_device == AUDIO_DEVICE_OUT_SPEAKER) {
input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
g_current_output_device = AUDIO_DEVICE_OUT_SPEAKER;
} else {
input_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
g_current_output_device = AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
}
do {
if (enable || !g_record_buf) {
//force to speaker , main mic
ret = speechdrv_set_speech_on(enable, input_device, g_current_output_device);
++retry_ite;
if (!ret) {
break;
}
} else { //recording!!
ALOGE("%s(), record is still on, Will auto sppech off after record off, don't worry!", __func__);
g_want_to_speech_off_after_record_off = 1;
ret = 0;
break;
}
usleep(SPEECH_DRV_RETRY_US);
} while (retry_ite < SPEECH_DRV_RETRY_TIME);
if (ret) {
return ret;
}
if (enable) {
if (output_device == AUDIO_DEVICE_OUT_SPEAKER) {
device_mode = get_default_device();
enable_phone_call_AFE_path(device_mode);
usleep(100 * 1000);//100ms
updateVolume(XML_SPEECH_VOLUME);
} else {
enable_phone_call_AFE_path(DEV_BT);
usleep(100 * 1000);//100ms
updateDigitalGain();
}
} else {
disable_phone_call_AFE_path();
}
return 0;
}
int audio_ctrl_service_M2M_Call_on_inner(int enable) {
int ret;
int retry_ite = 0;
int input_device;
ALOGD("%s(), enable=%d", __func__, enable);
if (enable == g_is_speech_on) {
ALOGE("%s(), speech on status no change! g_is_speech_on: %d",
__func__, g_is_speech_on);
return 0;
}
g_is_speech_on = enable;
input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
g_current_output_device = AUDIO_DEVICE_OUT_SPEAKER;
do {
if (enable || !g_record_buf) {
//force to speaker , main mic
ret = speechdrv_set_speech_on(enable, input_device, g_current_output_device);
++retry_ite;
if (!ret) {
break;
}
} else { //recording!!
ALOGE("%s(), record is still on, Will auto sppech off after record off, don't worry!", __func__);
g_want_to_speech_off_after_record_off = 1;
ret = 0;
break;
}
usleep(SPEECH_DRV_RETRY_US);
} while (retry_ite < SPEECH_DRV_RETRY_TIME);
if (ret) {
return ret;
}
return 0;
}
int audio_ctrl_service_ECall_on_inner(int enable) {
int ret;
int retry_ite = 0;
int device_mode = 0;
int input_device;
int outputDevice;
ALOGD("%s(), enable=%d", __func__, enable);
if (enable == g_is_speech_on) {
ALOGE("%s(), speech on status no change! g_is_speech_on: %d",
__func__, g_is_speech_on);
return 0;
}
g_is_speech_on = enable;
input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
g_current_output_device = AUDIO_DEVICE_OUT_SPEAKER;
do {
if (enable || !g_record_buf) {
//force to speaker , main mic
ret = speechdrv_set_speech_on(enable, input_device, g_current_output_device);
++retry_ite;
if (!ret) {
break;
}
} else { //recording!!
ALOGE("%s(), record is still on, Will auto sppech off after record off, don't worry!", __func__);
g_want_to_speech_off_after_record_off = 1;
ret = 0;
break;
}
usleep(SPEECH_DRV_RETRY_US);
} while (retry_ite < SPEECH_DRV_RETRY_TIME);
if (ret) {
return ret;
}
if (enable) {
device_mode = get_default_device();
enable_phone_call_AFE_path(device_mode);
usleep(100 * 1000);//100ms
updateVolume(XML_SPEECH_VOLUME);
} else {
disable_phone_call_AFE_path();
}
return 0;
}
int audio_ctrl_service_set_volume_index_inner(int volumeIdx) {
ALOGD("%s(), volumeIdx=%d, valid range (%d~%d)", __func__, volumeIdx, DL_VOLUME_IDX_MIN, DL_VOLUME_IDX_MAX);
if (volumeIdx > DL_VOLUME_IDX_MAX || volumeIdx < DL_VOLUME_IDX_MIN) {
ALOGE("%s(), Invalid DL gain value: %d, valid range (%d~%d)",
__func__, volumeIdx, DL_VOLUME_IDX_MIN, DL_VOLUME_IDX_MAX);
return -1;
}
g_volume_index = volumeIdx;
updateVolume(XML_SPEECH_VOLUME);
return 0;
}
int audio_ctrl_service_set_speaker_type_inner(int type) {
if (g_speaker_type == type) {
AUDIO_V_LOG("%s(), the same speaker type(0x%x), return.", __func__, g_speaker_type);
return 0;
}
speechdrv_set_speaker_type(type);
return 0;
}
int audio_ctrl_service_get_volume_index_inner() {
AUDIO_V_LOG("%s()", __func__);
return g_volume_index;
}
#if defined(MTK_SPEECH_RECORD_SUPPORT)
int audio_ctrl_service_inCall_record_start_inner(int buf_size) {
int ret;
AUDIO_V_LOG("%s()", __func__);
if (buf_size > MAX_REC_BUF_SIZE || buf_size <= 0 || buf_size % 2) {
return -EINVAL;
}
if (g_record_buf) {
ALOGE("%s(), record already open!", __func__);
return -EBUSY;
}
g_record_buf_size = buf_size;
g_record_buf = malloc(g_record_buf_size);
g_record_read_virt_idx = 0;
g_record_write_virt_idx = 0;
g_record_virt_boundry = buf_size * 1000;
#ifndef RECORD_USE_UT_SOURCE
// ret = speechdrv_set_RecordOn(RECORD_TYPE_MIX);
#else
ret = tmp_recordOn();
#endif
if (ret < 0) {
free(g_record_buf);
}
return ret;
}
int audio_ctrl_service_inCall_record_stop_inner() {
int ret;
AUDIO_V_LOG("%s()", __func__);
if (!g_record_buf) {
ALOGE("%s(), record not start!", __func__);
return -EINVAL;
}
#ifndef RECORD_USE_UT_SOURCE
// ret = speechdrv_set_RecordOff(RECORD_TYPE_MIX);
if (g_want_to_speech_off_after_record_off) {
// int ret_speech_off = speechdrv_set_speech_on(0, 0);
if (ret_speech_off) {
ALOGE("%s(), speechdrv_set_speech_on failed! err %d", __func__,
ret_speech_off);
}
g_want_to_speech_off_after_record_off = 0;
}
#else
ret = tmp_recordOff();
#endif
free(g_record_buf);
g_record_buf = 0;
return ret;
}
int audio_ctrl_service_inCall_record_get_watermark_inner() {
int watermark;
if (!g_record_buf) {
ALOGE("%s(), record not start!", __func__);
return -EINVAL;
}
watermark = (g_record_write_virt_idx - g_record_read_virt_idx + g_record_virt_boundry) % g_record_virt_boundry;
if (watermark > g_record_buf_size) { //XRUN
ALOGE("%s(), XRUN reset ptr", __func__);
g_record_write_virt_idx = g_record_read_virt_idx;
return -EPIPE;
}
return watermark;
}
int audio_ctrl_service_inCall_record_pointer_inner() {
int watermark;
AUDIO_V_LOG("%s()", __func__);
if (!g_record_buf) {
ALOGE("%s(), record not start!", __func__);
return -EINVAL;
}
watermark = audio_ctrl_service_inCall_record_get_watermark_inner();
if (watermark < 0) {
return watermark;
}
return (g_record_write_virt_idx % g_record_buf_size);
}
int check_copy_twice(int virt_ptr, int buf_size, int size) {
if (virt_ptr % buf_size + size > buf_size) {
return 1;
} else {
return 0;
}
}
int audio_ctrl_service_inCall_record_get_data_inner(int data_size, char *dest) {
int watermark;
int size_to_take;
int copy_twice = 0;
int read_phy_idx = g_record_read_virt_idx % g_record_buf_size;
int first_copy_size;
AUDIO_V_LOG("%s()", __func__);
if (!g_record_buf) {
ALOGE("%s(), record not start!", __func__);
return -EINVAL;
}
watermark = audio_ctrl_service_inCall_record_get_watermark_inner();
if (watermark < 0) {
return watermark;
}
size_to_take = (data_size < watermark) ? data_size : watermark;
copy_twice = check_copy_twice(g_record_read_virt_idx, g_record_buf_size, size_to_take);
if (!copy_twice) {
memcpy(dest, g_record_buf + read_phy_idx, size_to_take);
} else {
first_copy_size = g_record_buf_size - read_phy_idx;
memcpy(dest, g_record_buf + read_phy_idx, first_copy_size);
dest += first_copy_size;
memcpy(dest, g_record_buf, size_to_take - first_copy_size);
}
g_record_read_virt_idx += size_to_take;
g_record_read_virt_idx %= g_record_virt_boundry;
return size_to_take;
}
int audio_ctrl_service_inCall_record_data_cb_pcm(int data_size, char *data) {
int copy_twice = 0;
int write_phy_idx = g_record_write_virt_idx % g_record_buf_size;
int first_copy_size;
if (!g_record_buf) {
return -EINVAL;
}
copy_twice = check_copy_twice(g_record_write_virt_idx, g_record_buf_size, data_size);
if (!copy_twice) {
memcpy(g_record_buf + write_phy_idx, data, data_size);
} else {
first_copy_size = g_record_buf_size - write_phy_idx;
memcpy(g_record_buf + write_phy_idx, data, first_copy_size);
data += first_copy_size;
memcpy(g_record_buf, data, data_size - first_copy_size);
}
g_record_write_virt_idx += data_size;
g_record_write_virt_idx %= g_record_virt_boundry;
return data_size;
}
int16_t *do_record_8k_to_16k_src(int16_t *src, int size_byte) {
int offset, err;
int16_t *dst_buf;
assert(size_byte == RECORD_SRC_BUF_SIZE * 2);
if (!g_incall_record_src_state) { //not init
g_incall_record_src_state = src_new(g_converter_type, 1, &err);
if (!g_incall_record_src_state) {
ALOGE("%s(), src_new failed err=%d", __func__, err);
return NULL;
}
assert(!g_incall_record_src_buffer);
assert(!g_incall_record_dst_buffer);
g_incall_record_src_buffer = calloc(1, sizeof(float) * RECORD_SRC_BUF_SIZE);
g_incall_record_dst_buffer = calloc(1, sizeof(float) * RECORD_DST_BUF_SIZE);
g_incall_record_src_data.data_in = g_incall_record_src_buffer;
g_incall_record_src_data.data_out = g_incall_record_dst_buffer;
g_incall_record_src_data.src_ratio = RECORD_SRC_RATIO;
g_incall_record_src_data.end_of_input = 0;
}
/* do convert */
g_incall_record_src_data.input_frames = RECORD_SRC_BUF_SIZE;
g_incall_record_src_data.output_frames = RECORD_DST_BUF_SIZE;
src_short_to_float_array(src, g_incall_record_src_buffer, RECORD_SRC_BUF_SIZE);
err = src_process(g_incall_record_src_state, &g_incall_record_src_data);
if (err) {
ALOGE("%s(), src_process failed %d", __func__, err);
return NULL;
}
dst_buf = g_incall_record_dst_int_buffer;
if (g_incall_record_src_data.output_frames > g_incall_record_src_data.output_frames_gen) {
offset = g_incall_record_src_data.output_frames - g_incall_record_src_data.output_frames_gen;
} else {
offset = 0;
}
src_float_to_short_array(g_incall_record_dst_buffer, dst_buf + offset,
g_incall_record_src_data.output_frames_gen);
return dst_buf;
}
int audio_ctrl_service_inCall_record_data_cb_inner(int data_size, char *data) {
MD_PCM_RECORD_HEADER *md_pcm_record_header;
char *data_process_ptr = data;
char *pcm_data_ptr;
uint16_t syncWord;
uint16_t rawPcmDir;
uint16_t freq;
uint16_t pcmLength;
uint16_t channel;
uint16_t bitFormat;
int16_t *ul_data_ptr = 0;
int ul_data_ptr_size;
int ul_data_rate;
int16_t *dl_data_ptr = 0;
int dl_data_ptr_size;
int dl_data_rate;
int total_data_size;
int16_t *total_data_ptr;
int i, j;
int ret;
while (data_process_ptr < data + data_size) {
md_pcm_record_header = (MD_PCM_RECORD_HEADER *)data_process_ptr;
syncWord = md_pcm_record_header->u16SyncWord;
rawPcmDir = md_pcm_record_header->u16RawPcmDir;
freq = md_pcm_record_header->u16Freq;
pcmLength = md_pcm_record_header->u16Length;
channel = md_pcm_record_header->u16Channel;
bitFormat = md_pcm_record_header->u16BitFormat;
pcm_data_ptr = data_process_ptr + sizeof(MD_PCM_RECORD_HEADER);
if (syncWord != MD_PCM_RECORD_HEADER_SYNC) {
ALOGE("%s(), Invalid packet, sync word: 0x%x", __func__, syncWord);
return 0;
}
if (rawPcmDir == RECORD_TYPE_UL) {
assert(!ul_data_ptr);
ul_data_ptr = (uint16_t *)pcm_data_ptr;
ul_data_ptr_size = pcmLength;
ul_data_rate = freq;
assert(channel == 1);
} else {
assert(!dl_data_ptr);
dl_data_ptr = (uint16_t *)pcm_data_ptr;
dl_data_ptr_size = pcmLength;
dl_data_rate = freq;
assert(channel == 1);
}
data_process_ptr += sizeof(MD_PCM_RECORD_HEADER) + pcmLength;
}
assert(ul_data_ptr);
assert(dl_data_ptr);
//only UL can be 8k or 16k, DL must be 16k
total_data_size = dl_data_ptr_size;
assert(!(total_data_size % ul_data_ptr_size));
total_data_ptr = malloc(total_data_size);
if (ul_data_ptr_size < total_data_size) {
ul_data_ptr = do_record_8k_to_16k_src(ul_data_ptr, ul_data_ptr_size);
if (!ul_data_ptr) {
return -EINVAL;
}
ul_data_ptr_size *= 2;
}
assert(total_data_size == ul_data_ptr_size);
//MIX sound
for (i = 0; i < ul_data_ptr_size / 2; ++i) {
total_data_ptr[i] = ul_data_ptr[i] >> 1;
}
for (i = 0; i < dl_data_ptr_size / 2; ++i) {
total_data_ptr[i] += dl_data_ptr[i] >> 1;
}
//write data
ret = audio_ctrl_service_inCall_record_data_cb_pcm(total_data_size, total_data_ptr);
free(total_data_ptr);
return ret;
}
#endif
#if defined(MTK_SPEECH_BGS_SUPPORT)
int audio_ctrl_service_inCall_playback_start_inner() {
#ifndef PLAYBACK_USE_UT_SINK
int ret;
AUDIO_V_LOG("%s()", __func__);
if (!g_is_bgs_on) {
ret = speechdrv_bgs_open(PHONECALL_SAMPLE_RATE);
g_is_bgs_on = 1;
} else {
ALOGE("%s(), already start!", __func__);
return 0;
}
return 0;
#else
return UT_BGSOn();
#endif
}
int audio_ctrl_service_inCall_playback_stop_inner() {
#ifndef PLAYBACK_USE_UT_SINK
AUDIO_V_LOG("%s()", __func__);
speechdrv_bgs_close();
g_is_bgs_on = 0;
return 0;
#else
return UT_BGSOff();
#endif
}
static const uint16_t table_1k_tone_16000_hz[] = {
0x0000, 0x30FC, 0x5A82, 0x7641,
0x7FFF, 0x7641, 0x5A82, 0x30FB,
0x0001, 0xCF05, 0xA57E, 0x89C0,
0x8001, 0x89BF, 0xA57E, 0xCF05
};
static const uint32_t kSizeSinewaveTable = sizeof(table_1k_tone_16000_hz);
int audio_ctrl_service_inCall_playback_send_data_inner(int data_size, void *data_buf) {
#ifndef PLAYBACK_USE_UT_SINK
int ret;
int write_size;
int written_size = 0;
int try_cnt = 20;
if (!g_is_bgs_on) {
ALOGE("%s(), not running!", __func__);
return 0;
}
while (data_size > 0) {
write_size = (data_size > PLAYBACK_BUF_SIZE) ? PLAYBACK_BUF_SIZE : data_size;
AUDIO_V_LOG("%s(), sample rate: %d, data_size: %d, write_size: %d",
__func__, PHONECALL_SAMPLE_RATE, data_size, write_size);
ret = speechdrv_bgs_write(data_buf, write_size);
if (ret < 0) {
ALOGE("%s(), write to BGS error! ret: %d", __func__, ret);
break;
}
data_size -= ret;
data_buf += ret;
written_size += ret;
--try_cnt;
if (try_cnt <= 0) {
break;
}
usleep(SPEECH_DRV_BGS_INTERVAL_US);
}
return written_size;
#else
return UT_BGSSendData(data_buf, data_size);
#endif
}
int audio_ctrl_service_inCall_playback_simulation(int data_ms) {
uint32_t total_size = PHONECALL_SAMPLE_RATE * 2 * data_ms / 1000;
uint32_t buffer_size = PLAYBACK_PERIOD_SIZE;
uint32_t total_left = total_size, buffer_count = buffer_size, consume_byte = 0;
char buffer[PLAYBACK_PERIOD_SIZE] = {0};
ALOGD("+%s(), data_ms = %d, total_size = %d, buffer_size = %d",
__func__, data_ms, total_size, buffer_size);
audio_ctrl_service_inCall_playback_start_inner();
while (total_left > 0) {
uint32_t count = 0;
if (total_left > buffer_size) {
buffer_count = buffer_size;
} else {
buffer_count = total_left;
}
while (buffer_count > kSizeSinewaveTable) {
memcpy(buffer + count, table_1k_tone_16000_hz, kSizeSinewaveTable);
count += kSizeSinewaveTable;
buffer_count -= kSizeSinewaveTable;
}
if (buffer_count > 0) {
memcpy(buffer + count, table_1k_tone_16000_hz, buffer_count);
count += buffer_count;
}
consume_byte = audio_ctrl_service_inCall_playback_send_data_inner(buffer_size, buffer);
total_left -= count;
}
audio_ctrl_service_inCall_playback_stop_inner();
ALOGD("-%s(), data_ms = %d, total_size = %d, total_left = %d",
__func__, data_ms, total_size, total_left);
return total_size;
}
#endif
int audio_ctrl_service_is_speech_on_inner(int output_device) {
int result = 0;
if (!g_is_speech_on) {
result = 0;
return result;
}
if (output_device == g_current_output_device) {
result = 1;
} else {
result = 0;
}
AUDIO_V_LOG("%s(), result = %d, output_device=0x%x", __func__, result, output_device);
return result;
}
int audio_ctrl_service_get_record_period_size_inner() {
AUDIO_V_LOG("%s()", __func__);
return RECORD_PERIOD_SIZE;
}
int audio_ctrl_service_get_playback_period_size_inner() {
AUDIO_V_LOG("%s()", __func__);
return PLAYBACK_PERIOD_SIZE;
}
int audio_ctrl_service_get_record_max_buffer_size_inner() {
AUDIO_V_LOG("%s()", __func__);
return RECORD_MAX_BUFFER_SIZE;
}
int audio_ctrl_service_get_playback_max_buffer_size_inner() {
ALOGE("%s()", __func__);
return PLAYBACK_MAX_BUFFER_SIZE;
}
#if defined(MTK_SPEECH_VM_SUPPORT)
/* for vmlog, need to record if vmlog on */
int g_vmlog_on;
int audio_ctrl_service_vmlog_on_inner(int vmlog_on) {
g_vmlog_on = vmlog_on;
return speechdrv_set_vm_on(vmlog_on);
}
int audio_ctrl_service_get_vmlog_on_inner() {
return g_vmlog_on;
}
#endif
/* for BT setting */
int audio_ctrl_service_set_bt_wbs_inner(int bt_wbs_on) {
AUDIO_V_LOG("%s()", __func__);
g_bt_wbs_on = !!bt_wbs_on;
set_BT_WB(g_bt_wbs_on);
speechdrv_set_bt_wbs(g_bt_wbs_on);
return 0;
}
int audio_ctrl_service_get_bt_wbs_inner() {
AUDIO_V_LOG("%s()", __func__);
return g_bt_wbs_on;
}
int audio_ctrl_service_set_bt_client_has_ecnr_inner(int bt_client_ecnr_on) {
if (g_bt_client_has_ecnr == bt_client_ecnr_on) {
AUDIO_V_LOG("%s(), the same bt_nrec(0x%x) during voice call.", __func__, g_current_output_device);
return 0;
}
AUDIO_V_LOG("%s(), bt_client_ecnr_on(%d->%d)", __func__, g_bt_client_has_ecnr, bt_client_ecnr_on);
g_bt_client_has_ecnr = bt_client_ecnr_on;
return speechdrv_set_bt_nrec(bt_client_ecnr_on);
}
int audio_ctrl_service_get_bt_client_has_ecnr_inner() {
AUDIO_V_LOG("%s()", __func__);
return g_bt_client_has_ecnr;
}
#if !defined(MTK_AUDIO_BRINGUP)
int audio_ctrl_service_set_use_bt_in_call_inner(int turn_on_bt_in_call) {
AUDIO_V_LOG("%s()", __func__);
int new_output_device = AUDIO_DEVICE_NONE;
int input_device = AUDIO_DEVICE_NONE;
//if not in call, do nothing
if (!g_is_speech_on) { return 0; }
if (turn_on_bt_in_call) {
new_output_device = AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
} else {
new_output_device = AUDIO_DEVICE_OUT_SPEAKER;
}
if (new_output_device == g_current_output_device) {
AUDIO_V_LOG("%s(), the same output device(0x%x) during voice call.",
__func__, g_current_output_device);
return 0;
}
g_current_output_device = new_output_device;
if (g_current_output_device == AUDIO_DEVICE_OUT_SPEAKER) {
input_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
} else {
input_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
}
AUDIO_V_LOG("%s(), output device(0x%x), input_device(0x%x).",
__func__, g_current_output_device, input_device);
if (g_current_output_device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) {
dynamic_switch_phone_call_path(DEV_BT);
} else {
dynamic_switch_phone_call_path(get_default_device());
}
speechdrv_change_speech_device(input_device, g_current_output_device);
updateVolume(XML_SPEECH_VOLUME);
return 0;
}
#endif
int audio_ctrl_service_get_use_bt_in_call_inner() {
AUDIO_V_LOG("%s()", __func__);
if (!g_is_speech_on) { return 0; }
return (g_current_output_device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
}
int audio_ctrl_service_reset_inner() {
AUDIO_V_LOG("%s()", __func__);
g_want_to_speech_off_after_record_off = 0;
if (g_is_speech_on) {
disable_phone_call_AFE_path();
}
g_is_speech_on = 0;
return 0;
}
/* DL:0 UL:1 */
int g_dl_mute_on;
int g_ul_mute_on;
int audio_ctrl_service_set_mute_inner(int path, int is_mute) {
AUDIO_V_LOG("%s()", __func__);
if (path == SPEECH_DL) {
g_dl_mute_on = is_mute;
speechdrv_set_dl_mute(g_dl_mute_on);
} else {
g_ul_mute_on = is_mute;
speechdrv_set_ul_mute(g_ul_mute_on);
}
return 0;
}
int audio_ctrl_service_get_mute_inner(int path) {
AUDIO_V_LOG("%s()", __func__);
if (path == SPEECH_DL) {
return g_dl_mute_on;
} else {
return g_ul_mute_on;
}
}
#if defined(MTK_SPEECH_BGS_SUPPORT)
/* for BGS UT */
static const char const *g_BGS_file_path = "/tmp/bgs_UT.pcm";
FILE *g_UT_file;
int UT_BGSOn() {
g_UT_file = fopen(g_BGS_file_path, "w");
if (!g_UT_file) {
return -EIO;
}
return 0;
}
int UT_BGSOff() {
if (g_UT_file) {
fclose(g_UT_file);
}
g_UT_file = 0;
return 0;
}
int UT_BGSSendData(void *buf, int buf_size) {
int sleep_time_ms = buf_size * 1000 / PHONECALL_SAMPLE_RATE / 2;
if (!g_UT_file) {
ALOGE("%s(), plz send data after turn on", __func__);
return 0;
}
fwrite(buf, 1, buf_size, g_UT_file);
return buf_size;
}
#endif