#include "system/includes.h" #include "media/includes.h" #include "application/audio_dec_app.h" #include "tone_player.h" #include "audio_config.h" #include "app_main.h" #include "audio_dec.h" #include "sine_make.h" #if TCFG_USER_TWS_ENABLE #include "bt_tws.h" #endif/*TCFG_USER_TWS_ENABLE*/ ////////////////////////////////////////////////////////////////////////////// #define TWS_FUNC_ID_TONE2TWS TWS_FUNC_ID('2', 'T', 'W', 'S') #if TCFG_TONE2TWS_ENABLE #define TONE_TWS_CONFIRM_TIME 700 #else #define TONE_TWS_CONFIRM_TIME 500 #endif ////////////////////////////////////////////////////////////////////////////// static const char *const tone_index[] = { [IDEX_TONE_NUM_0] = SDFILE_RES_ROOT_PATH"tone/0.*", [IDEX_TONE_NUM_1] = SDFILE_RES_ROOT_PATH"tone/1.*", [IDEX_TONE_NUM_2] = SDFILE_RES_ROOT_PATH"tone/2.*", [IDEX_TONE_NUM_3] = SDFILE_RES_ROOT_PATH"tone/3.*", [IDEX_TONE_NUM_4] = SDFILE_RES_ROOT_PATH"tone/4.*", [IDEX_TONE_NUM_5] = SDFILE_RES_ROOT_PATH"tone/5.*", [IDEX_TONE_NUM_6] = SDFILE_RES_ROOT_PATH"tone/6.*", [IDEX_TONE_NUM_7] = SDFILE_RES_ROOT_PATH"tone/7.*", [IDEX_TONE_NUM_8] = SDFILE_RES_ROOT_PATH"tone/8.*", [IDEX_TONE_NUM_9] = SDFILE_RES_ROOT_PATH"tone/9.*", [IDEX_TONE_BT_MODE] = SDFILE_RES_ROOT_PATH"tone/bt.*", [IDEX_TONE_BT_CONN] = SDFILE_RES_ROOT_PATH"tone/bt_conn.*", [IDEX_TONE_BT_DISCONN] = SDFILE_RES_ROOT_PATH"tone/bt_dconn.*", [IDEX_TONE_TWS_CONN] = SDFILE_RES_ROOT_PATH"tone/tws_conn.*", [IDEX_TONE_TWS_DISCONN] = SDFILE_RES_ROOT_PATH"tone/tws_dconn.*", [IDEX_TONE_LOW_POWER] = SDFILE_RES_ROOT_PATH"tone/low_power.*", [IDEX_TONE_POWER_OFF] = SDFILE_RES_ROOT_PATH"tone/power_off.*", [IDEX_TONE_POWER_ON] = SDFILE_RES_ROOT_PATH"tone/power_on.*", [IDEX_TONE_RING] = SDFILE_RES_ROOT_PATH"tone/ring.*", [IDEX_TONE_MAX_VOL] = SDFILE_RES_ROOT_PATH"tone/vol_max.*", [IDEX_TONE_NORMAL] = TONE_NORMAL, #if (TCFG_APP_MUSIC_EN) [IDEX_TONE_MUSIC] = SDFILE_RES_ROOT_PATH"tone/music.*", #endif #if (TCFG_APP_LINEIN_EN) [IDEX_TONE_LINEIN] = SDFILE_RES_ROOT_PATH"tone/linein.*", #endif #if (TCFG_APP_FM_EN) [IDEX_TONE_FM] = SDFILE_RES_ROOT_PATH"tone/fm.*", #endif #if (TCFG_APP_PC_EN) [IDEX_TONE_PC] = SDFILE_RES_ROOT_PATH"tone/pc.*", #endif #if (TCFG_APP_RTC_EN) [IDEX_TONE_RTC] = SDFILE_RES_ROOT_PATH"tone/rtc.*", #endif #if (TCFG_APP_RECORD_EN) [IDEX_TONE_RECORD] = SDFILE_RES_ROOT_PATH"tone/record.*", #endif } ; #if TCFG_TONE2TWS_ENABLE // 用于转发的提示音 static const char *const tone2tws_index[] = { TONE_BT_MODE, TONE_MUSIC, TONE_LINEIN, TONE_FM, TONE_PC, TONE_RTC, TONE_RECORD, TONE_RES_ROOT_PATH"tone/sd.*", TONE_RES_ROOT_PATH"tone/udisk.*", } ; #endif /* * 参数配置: * freq : 实际频率 * 512 * points : 正弦波点数 * win : 正弦窗 * decay : 衰减系数(百分比), 正弦窗模式下为频率设置:频率*512 * */ static const struct sin_param sine_16k_normal[] = { /*{0, 1000, 0, 100},*/ {200 << 9, 4000, 0, 100}, }; #if CONFIG_USE_DEFAULT_SINE static const struct sin_param sine_tws_disconnect_16k[] = { /* {390 << 9, 4026, SINE_TOTAL_VOLUME / 4026}, {262 << 9, 8000, SINE_TOTAL_VOLUME / 8000}, */ {262 << 9, 4026, 0, 100}, {390 << 9, 8000, 0, 100}, }; static const struct sin_param sine_tws_connect_16k[] = { /* {262 << 9, 4026, SINE_TOTAL_VOLUME / 4026}, {390 << 9, 8000, SINE_TOTAL_VOLUME / 8000}, */ {262.298 * 512, 8358, 0, 100}, }; static const struct sin_param sine_low_power[] = { {848 << 9, 3613, 0, 50}, {639 << 9, 3623, 0, 50}, }; static const struct sin_param sine_ring[] = { {450 << 9, 24960, 1, 16.667 * 512}, {0, 16000, 0, 100}, }; static const struct sin_param sine_tws_max_volume[] = { {210 << 9, 2539, 0, 100}, {260 << 9, 7619, 0, 100}, {400 << 9, 2539, 0, 100}, }; #endif ////////////////////////////////////////////////////////////////////////////// struct tone_dec_handle *tone_dec = NULL; ////////////////////////////////////////////////////////////////////////////// /*----------------------------------------------------------------------------*/ /**@brief 按序列号获取sine数组 @param id: 序号 @param *num: 数组个数 @return sine数组 @note */ /*----------------------------------------------------------------------------*/ static const struct sin_param *get_sine_param_data(u8 id, u8 *num) { const struct sin_param *param_data; switch (id) { case SINE_WTONE_NORAML: param_data = sine_16k_normal; *num = ARRAY_SIZE(sine_16k_normal); break; #if CONFIG_USE_DEFAULT_SINE case SINE_WTONE_TWS_CONNECT: param_data = sine_tws_connect_16k; *num = ARRAY_SIZE(sine_tws_connect_16k); break; case SINE_WTONE_TWS_DISCONNECT: param_data = sine_tws_disconnect_16k; *num = ARRAY_SIZE(sine_tws_disconnect_16k); break; case SINE_WTONE_LOW_POWER: param_data = sine_low_power; *num = ARRAY_SIZE(sine_low_power); break; case SINE_WTONE_RING: param_data = sine_ring; *num = ARRAY_SIZE(sine_ring); break; case SINE_WTONE_MAX_VOLUME: param_data = sine_tws_max_volume; *num = ARRAY_SIZE(sine_tws_max_volume); break; #endif default: return NULL; } return param_data; } /*----------------------------------------------------------------------------*/ /**@brief 提示音播放基础函数(带有事件回调) @param **list: 文件名 @param follow: 现有提示音播放完毕后跟随着播放 @param preemption: 打断标记 @param *evt_handler: 事件回调接口 @param *evt_priv: 事件回调私有句柄 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ static int tone_play_open_with_callback_base(const char **list, u8 follow, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv, int sync_confirm_time) { if (follow && tone_dec) { struct tone_dec_list_handle *dec_list = tone_dec_list_create(tone_dec, list, preemption, evt_handler, evt_priv, NULL, NULL); int ret = tone_dec_list_add_play(tone_dec, dec_list); if (ret == false) { tone_play_stop(); return -1; } return 0; } tone_dec_stop(&tone_dec, 1, TONE_DEC_STOP_BY_OTHER_PLAY); tone_dec = tone_dec_create(); if (tone_dec == NULL) { return -1; } tone_dec_set_sin_get_hdl(tone_dec, get_sine_param_data); struct tone_dec_list_handle *dec_list = tone_dec_list_create(tone_dec, list, preemption, evt_handler, evt_priv, NULL, NULL); if (dec_list) { dec_list->sync_confirm_time = sync_confirm_time; } int ret = tone_dec_list_add_play(tone_dec, dec_list); if (ret == false) { tone_play_stop(); return -1; } return 0; } #if TCFG_TONE2TWS_ENABLE #include "app_task.h" static u32 tone2tws_dat = 0; /*----------------------------------------------------------------------------*/ /**@brief tws提示音数据处理 @param dat: 数据 @return @note 在任务中集中处理tws信息 */ /*----------------------------------------------------------------------------*/ static void tone2tws_rx_play(u32 dat) { int idex = dat - 1; if (idex >= ARRAY_SIZE(tone2tws_index)) { return ; } /* y_printf("tone2tws_rx_play name:%d \n", tone2tws_index[idex]); */ char *single_file[2] = {NULL}; // is file name single_file[0] = (char *)tone2tws_index[idex]; single_file[1] = NULL; tone_play_open_with_callback_base(single_file, 0, 1, NULL, NULL, TONE_TWS_CONFIRM_TIME); } void tone2tws_bt_task_start(u8 tone_play) { if (tone2tws_dat == 0) { return ; } if (tone_play) { // 播放蓝牙提示音,抛弃该提示音 tone2tws_dat = 0; } else { // 播放该提示音 tone2tws_rx_play(tone2tws_dat); tone2tws_dat = 0; } } static void tone2tws_rx_callback_func(u32 dat) { /* printf("tone2tws_rx_callback_func\n"); */ if (!dat) { return ; } #if TCFG_DEC2TWS_ENABLE if (tone2tws_dat) { // 释放旧的 tone2tws_dat = 0; } if (APP_BT_TASK != app_get_curr_task()) { r_printf("tone2tws task:%d ", app_get_curr_task()); // 该提示音一定是在蓝牙模式播放,否则代表有问题。 // 等返回蓝牙模式再播放 tone2tws_dat = dat; return ; } #endif tone2tws_rx_play(dat); } /*----------------------------------------------------------------------------*/ /**@brief 提示音tws私有信息处理 @param *data: 数据 @param len: 数据长度 @param rx: 1-接受端 @return @note */ /*----------------------------------------------------------------------------*/ static void tone2tws_tws_rx_data(void *data, u16 len, bool rx) { /* printf("tone2tws_tws_rx_data, l:%d, rx:%d \n", len, rx); */ if (!rx) { return; } /* printf("data rx \n"); */ /* printf_buf(data, len); */ u32 dat; memcpy(&dat, data, 4); /* y_printf("rx dat:%d \n", dat); */ // 该函数是在中断里面调用,实际处理放在task里面 int argv[3]; argv[0] = (int)tone2tws_rx_callback_func; argv[1] = 1; argv[2] = (int)dat; int ret = os_taskq_post_type("app_core", Q_CALLBACK, 3, argv); /* printf("put taskq, ret:%d, len:%d \n", ret, len); */ if (ret) { log_e("taskq post err \n"); } } REGISTER_TWS_FUNC_STUB(tws_tone2tws_rx) = { .func_id = TWS_FUNC_ID_TONE2TWS, .func = tone2tws_tws_rx_data, }; #endif /*----------------------------------------------------------------------------*/ /**@brief 提示音播放(带有事件回调) @param **list: 文件名 @param follow: 现有提示音播放完毕后跟随着播放 @param preemption: 打断标记 @param *evt_handler: 事件回调接口 @param *evt_priv: 事件回调私有句柄 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_open_with_callback(const char **list, u8 follow, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv) { int sync_confirm_time = 0; #if TCFG_TONE2TWS_ENABLE int state = tws_api_get_tws_state(); if (state & TWS_STA_SIBLING_CONNECTED) { // 有tws连接,检查是否需要把提示音推送给对方 char *name = list[0]; for (int i = 0; i < ARRAY_SIZE(tone2tws_index); i++) { if (IS_REPEAT_BEGIN(name) || IS_REPEAT_END(name)) { break; } if (IS_DEFAULT_SINE(name) || IS_DEFAULT_SINE(tone2tws_index[i])) { if ((u32)name == (u32)tone2tws_index[i]) { // is sine idx u32 dat = i + 1; tws_api_send_data_to_sibling(&dat, 4, TWS_FUNC_ID_TONE2TWS); sync_confirm_time = TONE_TWS_CONFIRM_TIME; break; } } else if (!strcmp(tone2tws_index[i], name)) { // is file name u32 dat = i + 1; tws_api_send_data_to_sibling(&dat, 4, TWS_FUNC_ID_TONE2TWS); sync_confirm_time = TONE_TWS_CONFIRM_TIME; break; } } } #endif return tone_play_open_with_callback_base(list, follow, preemption, evt_handler, evt_priv, sync_confirm_time); } /*----------------------------------------------------------------------------*/ /**@brief 按文件播放提示音 @param *name: 文件名 @param preemption: 打断标记 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play(const char *name, u8 preemption) { char *single_file[2] = {NULL}; single_file[0] = (char *)name; single_file[1] = NULL; return tone_play_open_with_callback(single_file, 0, preemption, NULL, NULL); } /*----------------------------------------------------------------------------*/ /**@brief 按文件播放提示音 @param *name: 文件名 @param preemption: 打断标记 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_by_path(const char *name, u8 preemption) { return tone_play(name, preemption); } /*----------------------------------------------------------------------------*/ /**@brief 按序列号播放提示音 @param index: 序列号 @param preemption: 打断标记 @param *evt_handler: 事件回调接口 @param *evt_priv: 事件回调私有句柄 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_index_with_callback(u8 index, u8 preemption, void (*evt_handler)(void *priv), void *evt_priv) { if (index >= IDEX_TONE_NONE) { return -1; } char *single_file[2] = {NULL}; single_file[0] = (char *)tone_index[index]; single_file[1] = NULL; return tone_play_open_with_callback(single_file, 0, preemption, evt_handler, evt_priv); } /*----------------------------------------------------------------------------*/ /**@brief 按序列号播放提示音(带有事件回调) @param index: 序列号 @param preemption: 打断标记 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_index(u8 index, u8 preemption) { return tone_play_index_with_callback(index, preemption, NULL, NULL); } /*----------------------------------------------------------------------------*/ /**@brief 按文件名列表播放提示音 @param **list: 文件名列表 @param preemption: 打断标记 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_file_list_play(const char **list, u8 preemption) { return tone_play_open_with_callback(list, 0, preemption, NULL, NULL); } /*----------------------------------------------------------------------------*/ /**@brief 按序列号播放提示音 @param index: 序列号 @param preemption: 打断标记 @param *evt_handler: 事件回调接口 @param *evt_priv: 事件回调私有句柄 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_with_callback_by_index(u8 index, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv) { if (index >= IDEX_TONE_NONE) { return -1; } char *single_file[2] = {NULL}; single_file[0] = (char *)tone_index[index]; single_file[1] = NULL; return tone_play_open_with_callback(single_file, 0, preemption, evt_handler, evt_priv); } /*----------------------------------------------------------------------------*/ /**@brief 按名字播放提示音 @param *name: 文件名 @param preemption: 打断标记 @param *evt_handler: 事件回调接口 @param *evt_priv: 事件回调私有句柄 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_with_callback_by_name(char *name, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv) { char *single_file[2] = {NULL}; single_file[0] = name; single_file[1] = NULL; return tone_play_open_with_callback(single_file, 0, preemption, evt_handler, evt_priv); } /*----------------------------------------------------------------------------*/ /**@brief 按列表播放提示音 @param **list: 文件列表 @param preemption: 打断标记 @param *evt_handler: 事件回调接口 @param *evt_priv: 事件回调私有句柄 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_with_callback_by_list(const char **list, u8 preemption, void (*evt_handler)(void *priv, int flag), void *evt_priv) { return tone_play_open_with_callback(list, 0, preemption, evt_handler, evt_priv); } /*----------------------------------------------------------------------------*/ /**@brief 停止指定序号提示音 @param index: 序号 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_stop_by_index(u8 index) { if (index >= IDEX_TONE_NONE) { return -1; } tone_dec_stop_spec_file(&tone_dec, tone_index[index], 1, TONE_DEC_STOP_BY_OTHER_PLAY); return 0; } /*----------------------------------------------------------------------------*/ /**@brief 停止指定序号提示音 @param path: 序号 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_stop_by_path(char *path) { if (path == NULL) { return -1; } tone_dec_stop_spec_file(&tone_dec, path, 1, TONE_DEC_STOP_BY_OTHER_PLAY); return 0; } /*----------------------------------------------------------------------------*/ /**@brief 停止提示音播放 @param @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int tone_play_stop(void) { tone_dec_stop(&tone_dec, 1, TONE_DEC_STOP_BY_OTHER_PLAY); return 0; } /*----------------------------------------------------------------------------*/ /**@brief 提示音暂停播放 @param *dec 提示音解码句柄 @return @note */ /*----------------------------------------------------------------------------*/ void tone_dec_list_pp(struct tone_dec_handle *dec) { if (dec) { if (dec->dec_file) { audio_dec_app_pp(dec->dec_file->dec); } if (dec->dec_sin) { audio_dec_app_pp(dec->dec_sin->dec); } } } /*----------------------------------------------------------------------------*/ /**@brief 提示音暂停播放 @param @return 0:成功 @note 该接口不适用于tws对箱版本 */ /*----------------------------------------------------------------------------*/ int tone_play_pp(void) { tone_dec_list_pp(tone_dec); return 0; } /*----------------------------------------------------------------------------*/ /**@brief 获取提示音播放状态 @param @return TONE_START: 正在播放 @return TONE_STOP: 不在播放 @note */ /*----------------------------------------------------------------------------*/ int tone_get_status(void) { if (tone_dec && tone_dec->cur_list) { return TONE_START; } return TONE_STOP; } /*----------------------------------------------------------------------------*/ /**@brief 获取提示音播放解码器状态 @param @return TONE_START: 正在解码 @return TONE_STOP: 不在解码 @note */ /*----------------------------------------------------------------------------*/ int tone_get_dec_status() { if (!tone_dec) { return TONE_STOP; } if (tone_dec->dec_sin && (tone_dec->dec_sin->dec->decoder.state != DEC_STA_WAIT_STOP)) { return TONE_START; } if (tone_dec->dec_file && (tone_dec->dec_file->dec->decoder.state != DEC_STA_WAIT_STOP)) { return TONE_START; } return TONE_STOP; } /*----------------------------------------------------------------------------*/ /**@brief 超时等待提示音播放解码完成 @param timeout_ms: 超时等待 @return TONE_START: 正在解码 @return TONE_STOP: 不在解码 @note */ /*----------------------------------------------------------------------------*/ int tone_dec_wait_stop(u32 timeout_ms) { u32 to_cnt = 0; while (tone_get_dec_status()) { /* putchar('t'); */ os_time_dly(1); if (timeout_ms) { to_cnt += 10; if (to_cnt >= timeout_ms) { break; } } } return tone_get_dec_status(); } /*----------------------------------------------------------------------------*/ /**@brief 提示音idle判断 @param @return 1: idle @return 0: busy @note */ /*----------------------------------------------------------------------------*/ static u8 tone_dec_idle_query() { if (tone_get_status() == TONE_START) { return 0; } return 1; } REGISTER_LP_TARGET(tone_dec_lp_target) = { .name = "tone_dec", .is_idle = tone_dec_idle_query, };