KT24-1110_65E-HA-651B/cpu/br25/audio_dec/tone_player.c
2024-11-10 18:44:17 +08:00

675 lines
21 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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,
};