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

680 lines
20 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.

/***********************************Jieli tech************************************************
File : localtws.c
By : Huxi
brief:
Email: huxi@zh-jieli.com
date : 2020-07
********************************************************************************************/
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "classic/tws_api.h"
#include "classic/tws_local_media_sync.h"
#include "localtws/localtws.h"
#include "clock_cfg.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "audio_enc.h"
#include "app_task.h"
#include "bt/bt_tws.h"
#include "bt/bt.h"
#if TCFG_DEC2TWS_ENABLE
#define LOCALTWS_LOG_ENABLE
#ifdef LOCALTWS_LOG_ENABLE
#define LOCALTWS_LOG log_i //y_printf
#define LOCALTWS_LOG_CHAR putchar
#else
#define LOCALTWS_LOG(...)
#define LOCALTWS_LOG_CHAR(...)
#endif
//////////////////////////////////////////////////////////////////////////////
#define LOCALTWS_MEDIA_ALLOC_EN 1 // 使用空间申请方式
#define LOCALTWS_CHANGE_USE_BT_CMD 1 // 使用蓝牙命令发送localtws变化信息
const u16 LOCALTWS_MEDIA_BUF_LEN = (12 * 1024); // localtws传输空间
const u16 LOCALTWS_MEDIA_BUF_LIMIT_LEN = (LOCALTWS_MEDIA_BUF_LEN * 7 / 10); // 起始数据累计达到该值才发送
const u16 LOCALTWS_MEDIA_TO_MS = 6000; // tws多长时间没收到数据认为是超时
#ifdef CONFIG_MIXER_CYCLIC
#if MIXER_AUDIO_DIRECT_OUT
const u16 LOCALTWS_MIXER_BUF_LEN = (8); // mixer空间大小有直通
#else /*MIXER_AUDIO_DIRECT_OUT*/
const u16 LOCALTWS_MIXER_BUF_LEN = (256 * 2 * 2); // mixer空间大小没有直通
#endif /*MIXER_AUDIO_DIRECT_OUT*/
#else /*CONFIG_MIXER_CYCLIC*/
const u16 LOCALTWS_MIXER_BUF_LEN = 8; // mixer空间大小只有一个通道时直接输出不经过该buf
#endif /*CONFIG_MIXER_CYCLIC*/
//////////////////////////////////////////////////////////////////////////////
//
#if (LOCALTWS_MEDIA_ALLOC_EN == 0)
static u8 localtws_media_buf[LOCALTWS_MEDIA_BUF_LEN] sec(.dec2tws_mem);
#endif
struct localtws_globle_hdl g_localtws = {0};
//////////////////////////////////////////////////////////////////////////////
//
extern struct audio_encoder_task *encode_task;
extern struct audio_decoder_task decode_task;
extern void local_tws_sync_no_check_data_buf(u8 no_check);
extern void tws_api_local_media_trans_clear_no_ready(void);
extern u8 is_tws_active_device(void);
extern int tone_get_status();
extern void localtws_decoder_resume_pre(void);
static u8 tws_background_connected_flag = 0;
///////////////////////////////////////////////////////////////////////////////////
void set_tws_background_connected_flag(u8 flag)
{
tws_background_connected_flag = flag;
}
u8 get_tws_background_connected_flag()
{
return tws_background_connected_flag;
}
/*----------------------------------------------------------------------------*/
/**@brief tws数据处理
@param *data: 数据
@param len: 数据长度
@param rx: 收数
@return 0: 成功
@note 弱函数重定义
*/
/*----------------------------------------------------------------------------*/
int tws_api_local_media_sync_rx_handler_notify(u8 *data, int len, u8 rx)
{
/* LOCALTWS_LOG_CHAR('r'); */
if (g_localtws.drop_frame_start) {
/* LOCALTWS_LOG("localtws_wait_drop_over\n"); */
LOCALTWS_LOG_CHAR('O');
LOCALTWS_LOG_CHAR('V');
LOCALTWS_LOG_CHAR(' ');
}
return localtws_tws_rx_handler_notify(data, len, rx);
}
/*----------------------------------------------------------------------------*/
/**@brief localtws事件发送
@param event_type: 事件
@param value: 事件参数
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void localtws_dec_event(u8 event_type, u32 value)
{
struct sys_event event;
event.type = SYS_BT_EVENT;
event.arg = (void *)SYS_BT_EVENT_FROM_TWS;
event.u.bt.event = event_type;
event.u.bt.value = value;
sys_event_notify(&event);
}
/*----------------------------------------------------------------------------*/
/**@brief localtws事件回调
@param event: 事件
@param *pram: 事件参数
@return 0: 成功
@note
*/
/*----------------------------------------------------------------------------*/
static int localtws_globle_event_cb(int event, int *pram)
{
switch (event) {
#if (!LOCALTWS_CHANGE_USE_BT_CMD)
case LOCALTWS_GLOBLE_EVENT_MEDIA_START:
localtws_dec_event(TWS_EVENT_LOCAL_MEDIA_START, pram[0]);
break;
case LOCALTWS_GLOBLE_EVENT_MEDIA_STOP:
localtws_dec_event(TWS_EVENT_LOCAL_MEDIA_STOP, 0);
break;
#endif
case LOCALTWS_GLOBLE_EVENT_MEDIA_TIMEOUT:
localtws_dec_event(TWS_EVENT_LOCAL_MEDIA_STOP, 0);
break;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief localtws检查活动设备
@param
@return true: 活动设备
@return false: 非活动设备
@note
*/
/*----------------------------------------------------------------------------*/
static int localtws_globle_check_active(void)
{
if (app_check_curr_task(APP_BT_TASK)) {
// 蓝牙模式一定是unactive设备
return false;
}
if (is_tws_active_device()) {
return true;
}
return false;
}
/*----------------------------------------------------------------------------*/
/**@brief localtws中断传输判断
@param
@return true: 中断传输
@return false: 继续传输
@note
*/
/*----------------------------------------------------------------------------*/
static int localtws_globle_check_frame_drop(void)
{
if (tone_get_status() || bt_media_is_running()) {
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////
//
/*----------------------------------------------------------------------------*/
/**@brief localtws全局初始化
@param
@return 0: 成功
@note
*/
/*----------------------------------------------------------------------------*/
static int localtws_globle_init(void)
{
os_mutex_create(&g_localtws.mutex);
#if LOCALTWS_MEDIA_ALLOC_EN
g_localtws.media_buf_malloc = 1;
#else
g_localtws.media_buf = localtws_media_buf;
#endif
localtws_globle_set_event_cb(localtws_globle_event_cb);
localtws_globle_set_check_active(localtws_globle_check_active);
localtws_globle_set_resume(localtws_dec_resume);
localtws_globle_set_data_abandon(localtws_media_dat_abandon);
localtws_globle_set_frame_drop(localtws_globle_check_frame_drop);
localtws_media_enable();
return 0;
}
__initcall(localtws_globle_init);
/*----------------------------------------------------------------------------*/
/**@brief localtws检测是否使能
@param
@return true: 使能
@return false: 不使能
@note
*/
/*----------------------------------------------------------------------------*/
int localtws_check_enable(void)
{
int state = tws_api_get_tws_state();
if ((state & TWS_STA_SIBLING_CONNECTED)) {
return true;
}
return false;
}
/*----------------------------------------------------------------------------*/
/**@brief localtws蓝牙事件处理
@param *evt: 蓝牙事件
@return 0: 成功
@note
*/
/*----------------------------------------------------------------------------*/
#define __this (&app_bt_hdl)
int localtws_bt_event_deal(struct bt_event *evt)
{
/* int state = tws_api_get_tws_state(); */
/* LOCALTWS_LOG(">>>>>>>>>>>>>>>>> %s, state:0x%x ", __func__, state); */
switch (evt->event) {
case TWS_EVENT_CONNECTED:
__this->cmd_flag = 2;
tws_background_connected_flag = 1;
app_task_switch_to(APP_BT_TASK);
case TWS_EVENT_CONNECTION_DETACH:
if (g_localtws.dec_restart) {
g_localtws.dec_restart();
}
break;
}
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief localtws mixer事件回调
@param *mixer: 句柄
@param event: 事件
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void localtws_mixer_event_handler(struct audio_mixer *mixer, int event)
{
switch (event) {
case MIXER_EVENT_OPEN:
break;
case MIXER_EVENT_CLOSE:
break;
case MIXER_EVENT_SR_CHANGE:
break;
}
}
/*----------------------------------------------------------------------------*/
/**@brief localtws mixer 检查采样率
@param *mixer: 句柄
@param sr: 采样率
@return 支持的采样率
@note
*/
/*----------------------------------------------------------------------------*/
static u32 localtws_mixer_check_sbc_sr(struct audio_mixer *mixer, u32 sr)
{
return localtws_enc_sbc_sample_rate_select(sr, 1);
}
/*----------------------------------------------------------------------------*/
/**@brief localtws mixer 关闭
@param *pfmt: 音频信息
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void localtws_mixer_close(struct audio_fmt *pfmt)
{
if (g_localtws.mixer_buf) {
audio_mixer_close(&g_localtws.mixer);
free(g_localtws.mixer_buf);
g_localtws.mixer_buf = NULL;
}
}
/*----------------------------------------------------------------------------*/
/**@brief 打开localtws mixer
@param *enc: 编码句柄
@param *pfmt: 音频信息
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void localtws_mixer_open(struct localtws_enc_hdl *enc, struct audio_fmt *pfmt)
{
g_localtws.mixer_buf = malloc(LOCALTWS_MIXER_BUF_LEN);
ASSERT(g_localtws.mixer_buf);
// 打开mixer
audio_mixer_open(&g_localtws.mixer);
audio_mixer_set_event_handler(&g_localtws.mixer, localtws_mixer_event_handler);
/* if (pfmt->coding_type & AUDIO_CODING_SBC) { */
/* audio_mixer_set_check_sr_handler(&g_localtws.mixer, localtws_mixer_check_sbc_sr); */
/* } */
// 固定mixer采样率
audio_mixer_set_sample_rate(&g_localtws.mixer, MIXER_SR_SPEC, pfmt->sample_rate);
/*初始化mix_buf的长度*/
audio_mixer_set_output_buf(&g_localtws.mixer, g_localtws.mixer_buf, LOCALTWS_MIXER_BUF_LEN);
/* audio_mixer_set_channel_num(&g_localtws.mixer, audio_output_channel_num()); */
audio_mixer_set_channel_num(&g_localtws.mixer, pfmt->channel);
#ifdef CONFIG_MIXER_CYCLIC
audio_mixer_set_min_len(&g_localtws.mixer, LOCALTWS_MIXER_BUF_LEN / 2);
#endif
struct audio_stream_entry *entries[8] = {NULL};
// 数据流串联
u8 entry_cnt = 0;
entries[entry_cnt++] = &g_localtws.mixer.entry;
entries[entry_cnt++] = &enc->entry;
g_localtws.mixer.stream = audio_stream_open(&g_localtws.mixer, audio_mixer_stream_resume);
audio_stream_add_list(g_localtws.mixer.stream, entries, entry_cnt);
}
//////////////////////////////////////////////////////////////////////////////
// lib weak func
/*----------------------------------------------------------------------------*/
/**@brief localtws编码打开完成
@param *enc: 编码句柄
@param *pfmt: 音频信息
@return 0-成功
@note 弱函数重定义
*/
/*----------------------------------------------------------------------------*/
int localtws_enc_open_use(struct localtws_enc_hdl *enc, struct audio_fmt *pfmt)
{
/* if (!encode_task) { */
/* encode_task = zalloc(sizeof(*encode_task)); */
/* ASSERT(encode_task); */
/* audio_encoder_task_create(encode_task, "audio_enc"); */
/* } */
audio_encoder_task_open();
enc->encode_task = encode_task;
if (pfmt->coding_type & AUDIO_CODING_SBC) {
clock_add(ENC_TWS_SBC_CLK);
} else {
clock_add(ENC_MP3_CLK);
}
clock_set_cur();
localtws_mixer_open(enc, pfmt);
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief localtws编码关闭完成
@param *enc: 编码句柄
@return
@note 弱函数重定义
*/
/*----------------------------------------------------------------------------*/
void localtws_enc_close_use(struct localtws_enc_hdl *enc)
{
struct audio_fmt *pfmt = &enc->encoder.fmt;
audio_encoder_task_close();
/* if (encode_task) { */
/* audio_encoder_task_del(encode_task); */
/* free(encode_task); */
/* encode_task = NULL; */
/* } */
if (enc->encoder.enc_ops->coding_type & AUDIO_CODING_SBC) {
clock_remove(ENC_TWS_SBC_CLK);
} else {
clock_remove(ENC_MP3_CLK);
}
clock_set_cur();
localtws_mixer_close(pfmt);
}
/*----------------------------------------------------------------------------*/
/**@brief localtws转换打开完成
@param *dec: 转换句柄
@param *pfmt: 音频信息
@return 0-成功
@note 弱函数重定义
*/
/*----------------------------------------------------------------------------*/
int localtws_code_convert_open_use(struct localtws_code_convert_hdl *dec, struct audio_fmt *pfmt)
{
dec->decode_task = &decode_task;
audio_stream_add_tail(g_localtws.mixer.stream, &dec->entry);
return 0;
}
/*----------------------------------------------------------------------------*/
/**@brief localtws转换关闭完成
@param *dec: 转换句柄
@return
@note 弱函数重定义
*/
/*----------------------------------------------------------------------------*/
void localtws_code_convert_close_use(struct localtws_code_convert_hdl *dec)
{
}
//////////////////////////////////////////////////////////////////////////////
// enc api
/*----------------------------------------------------------------------------*/
/**@brief 打开localtws编码
@param *pfmt: 音频信息
@param flag: 源信息
@return true: 成功
@return false: 失败
@note
*/
/*----------------------------------------------------------------------------*/
int localtws_enc_api_open(struct audio_fmt *pfmt, u32 flag)
{
if (localtws_check_enable() == true) {
struct audio_fmt enc_fmt = {0};
if (pfmt->coding_type != AUDIO_CODING_MP3) {
pfmt->coding_type = AUDIO_CODING_SBC;
}
if (pfmt->coding_type == AUDIO_CODING_SBC) {
pfmt->sample_rate = localtws_enc_sbc_sample_rate_select(pfmt->sample_rate, 1);
}
enc_fmt.coding_type = pfmt->coding_type;
enc_fmt.bit_rate = 128;
enc_fmt.channel = pfmt->channel;
enc_fmt.sample_rate = pfmt->sample_rate;
LOCALTWS_LOG("localtws sr:%d, chnum:%d, cod:0x%x \n", enc_fmt.sample_rate, enc_fmt.channel, enc_fmt.coding_type);
int ret = localtws_enc_open(&enc_fmt);
if (ret == 0) {
if (enc_fmt.coding_type != AUDIO_CODING_SBC) {
ret = localtws_code_convert_open(&enc_fmt);
}
if (ret == 0) {
localtws_push_open();
audio_stream_add_tail(g_localtws.mixer.stream, &g_localtws.push.entry);
if (flag & LOCALTWS_ENC_FLAG_STREAM) {
localtws_enc_set_stream_data_ctrl(localtws_dec_out_is_start, 500);
} else {
local_tws_sync_no_check_data_buf(1);
}
localtws_start(&enc_fmt);
return true;
} else {
localtws_enc_close();
}
}
}
return false;
}
/*----------------------------------------------------------------------------*/
/**@brief localtws编码写入
@param *data: 数据
@param len: 数据长度
@return 实际写入长度
@note
*/
/*----------------------------------------------------------------------------*/
int localtws_enc_api_write(s16 *data, int len)
{
return localtws_enc_write(NULL, data, len);
}
/*----------------------------------------------------------------------------*/
/**@brief 关闭localtws编码
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
void localtws_enc_api_close(void)
{
localtws_enc_close();
localtws_code_convert_close();
localtws_push_close();
localtws_stop();
}
//////////////////////////////////////////////////////////////////////////////
// api
/*----------------------------------------------------------------------------*/
/**@brief localtws设置等待a2dp状态
@param flag: 状态
@return
@note
*/
/*----------------------------------------------------------------------------*/
void localtws_set_wait_a2dp_start(u8 flag)
{
if (localtws_dec_is_open()) {
g_localtws.drop_frame_start = flag;
}
}
#if LOCALTWS_CHANGE_USE_BT_CMD
enum {
LOCALTWS_BT_CMD_MEDIA = 0,
LOCALTWS_BT_CMD_PAUSE,
};
struct localtws_bt_info {
int cmd;
int value;
};
#define TWS_FUNC_ID_LOCALTWS TWS_FUNC_ID('L', 'C', 'L', 'T')
static void localtws_rx_data(void *data, u16 len, bool rx)
{
struct localtws_bt_info info;
memcpy(&info, data, sizeof(struct localtws_bt_info));
switch (info.cmd) {
case LOCALTWS_BT_CMD_MEDIA:
if (!rx) {
return;
}
y_printf("localtws_rx_data:0x%x \n", info.value);
g_localtws.media_value = info.value;
if (info.value) {
localtws_dec_event(TWS_EVENT_LOCAL_MEDIA_START, info.value);
} else {
localtws_dec_event(TWS_EVENT_LOCAL_MEDIA_STOP, 0);
}
break;
case LOCALTWS_BT_CMD_PAUSE:
y_printf("localtws_rx pause:%d \n", info.value);
if (info.value) {
g_localtws.tws_send_pause = LOCALTWS_MEDIA_DEC_PAUSE;
g_localtws.fade_ms = 30;
g_localtws.fade_out_mute_ms = 10;
} else {
g_localtws.tws_send_pause = LOCALTWS_MEDIA_DEC_PAUSE_RECOVER;
g_localtws.fade_ms = 30;
}
break;
}
}
REGISTER_TWS_FUNC_STUB(localtws_rx) = {
.func_id = TWS_FUNC_ID_LOCALTWS,
.func = localtws_rx_data,
};
#endif /*LOCALTWS_CHANGE_USE_BT_CMD*/
/*----------------------------------------------------------------------------*/
/**@brief localtws启动
@param *pfmt: 音频信息
@return
@note 活动设备主动调用
*/
/*----------------------------------------------------------------------------*/
void localtws_start(struct audio_fmt *pfmt)
{
clock_add_set(LOCALTWS_CLK);
localtws_media_set_info((u8 *)&g_localtws.media_value, pfmt);
#if LOCALTWS_CHANGE_USE_BT_CMD
struct localtws_bt_info info = {0};
info.cmd = LOCALTWS_BT_CMD_MEDIA;
info.value = g_localtws.media_value;
tws_api_send_data_to_sibling((u8 *)&info, sizeof(struct localtws_bt_info), TWS_FUNC_ID_LOCALTWS);
#endif /*LOCALTWS_CHANGE_USE_BT_CMD*/
localtws_dec_open(g_localtws.media_value);
}
/*----------------------------------------------------------------------------*/
/**@brief localtws停止
@param
@return
@note 活动设备主动调用
*/
/*----------------------------------------------------------------------------*/
void localtws_stop(void)
{
LOCALTWS_LOG("localtws_stop\n");
g_localtws.tws_stop = 1;
// 清除还没有准备发射的
tws_api_local_media_trans_clear_no_ready();
#if LOCALTWS_CHANGE_USE_BT_CMD
struct localtws_bt_info info = {0};
info.cmd = LOCALTWS_BT_CMD_MEDIA;
info.value = 0;
tws_api_send_data_to_sibling((u8 *)&info, sizeof(struct localtws_bt_info), TWS_FUNC_ID_LOCALTWS);
#else /*LOCALTWS_CHANGE_USE_BT_CMD*/
// 发送一个结束包
localtws_media_send_end(200);
int to_cnt = 0;
// 超时等待结束包被取走
while (tws_api_local_media_trans_check_total(0)) {
localtws_decoder_resume_pre();
os_time_dly(1);
to_cnt += 10;
if (to_cnt > 500) {
LOCALTWS_LOG("local tws send end timer out \n");
break;
}
}
#endif /*LOCALTWS_CHANGE_USE_BT_CMD*/
localtws_dec_close(0);
g_localtws.tws_stop = 0;
clock_remove_set(LOCALTWS_CLK);
}
void localtws_decoder_pause(u8 pause)
{
#if LOCALTWS_CHANGE_USE_BT_CMD
struct localtws_bt_info info = {0};
info.cmd = LOCALTWS_BT_CMD_PAUSE;
info.value = pause;
tws_api_send_data_to_sibling((u8 *)&info, sizeof(struct localtws_bt_info), TWS_FUNC_ID_LOCALTWS);
#else /*LOCALTWS_CHANGE_USE_BT_CMD*/
if (pause) {
// 发送一个暂停命令避免从机收数超时进入stop
localtws_dec_pause();
}
#endif /*LOCALTWS_CHANGE_USE_BT_CMD*/
}
#else
void set_tws_background_connected_flag(u8 flag)
{
}
u8 get_tws_background_connected_flag()
{
return 0;
}
#endif /*(defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))*/