Files
AC707N/SDK/audio/framework/plugs/source/esco_file.c
T
2025-12-03 11:12:34 +08:00

234 lines
6.0 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".esco_file.data.bss")
#pragma data_seg(".esco_file.data")
#pragma const_seg(".esco_file.text.const")
#pragma code_seg(".esco_file.text")
#endif
#include "classic/hci_lmp.h"
#include "source_node.h"
#include "sync/audio_syncts.h"
#include "media/bt_audio_timestamp.h"
#include "reference_time.h"
#include "app_config.h"
#if TCFG_USER_BT_CLASSIC_ENABLE
struct esco_file_hdl {
u8 start;
u8 stop;
u8 esco_len;
u8 first_timestamp;
u8 frame_time;
u8 reference;
u32 clkn;
u32 coding_type;
struct stream_node *node;
void *ts_handle;
u8 bt_addr[6];
};
static void esco_file_timestamp_setup(struct esco_file_hdl *hdl);
static void esco_frame_pack_timestamp(struct esco_file_hdl *hdl, struct stream_frame *frame, u32 clkn)
{
u32 frame_clkn = clkn;
if (!hdl->ts_handle) {
return;
}
if (hdl->first_timestamp) {
hdl->first_timestamp = 0;
} else {
if (((frame_clkn - hdl->clkn) & 0x7fffff) != hdl->frame_time) {
printf("frame_clkn =%d ,clkn %d %d\n", frame_clkn, ((frame_clkn - hdl->clkn) & 0x7fffff), hdl->frame_time);
frame_clkn = hdl->clkn + hdl->frame_time;
}
}
frame->timestamp = esco_audio_timestamp_update(hdl->ts_handle, frame_clkn);
frame->flags |= FRAME_FLAG_TIMESTAMP_ENABLE | FRAME_FLAG_UPDATE_TIMESTAMP;
hdl->clkn = clkn;
}
static void esco_start_abandon_data(struct esco_file_hdl *hdl)
{
lmp_private_esco_suspend_resume(1);
}
static void esco_stop_abandon_data(struct esco_file_hdl *hdl)
{
lmp_private_esco_suspend_resume(2);
}
static void esco_packet_rx_notify(void *_hdl)
{
struct esco_file_hdl *hdl = (struct esco_file_hdl *)_hdl;
jlstream_wakeup_thread(NULL, hdl->node, NULL);
}
static enum stream_node_state esco_get_frame(void *_hdl, struct stream_frame **_frame)
{
int len = 0;
u32 frame_clkn = 0;
struct esco_file_hdl *hdl = (struct esco_file_hdl *)_hdl;
struct stream_frame *frame;
u8 *packet = lmp_private_get_esco_packet(&len, &frame_clkn);
if (!packet) {
*_frame = NULL;
return NODE_STA_RUN | NODE_STA_SOURCE_NO_DATA;
}
frame = jlstream_get_frame(hdl->node->oport, len);
frame->len = len;
if (hdl->frame_time == 0xff) {
/*对SCO链路获取不到T_sco的容错*/
hdl->frame_time = len >= 60 ? 12 : 6;
}
memcpy(frame->data, packet, len);
esco_frame_pack_timestamp(hdl, frame, frame_clkn);
lmp_private_free_esco_packet(packet);
*_frame = frame;
return NODE_STA_RUN;
}
static void *esco_init(void *priv, struct stream_node *node)
{
struct esco_file_hdl *hdl = zalloc(sizeof(*hdl));
hdl->node = node;
node->type |= NODE_TYPE_IRQ;
return hdl;
}
static int esco_ioc_set_bt_addr(struct esco_file_hdl *hdl, u8 *bt_addr)
{
memcpy(hdl->bt_addr, bt_addr, 6);
return 0;
}
static void esco_ioc_get_fmt(struct esco_file_hdl *hdl, struct stream_fmt *fmt)
{
int type = lmp_private_get_esco_packet_type();
int media_type = type & 0xff;
if (media_type == 0) {
fmt->sample_rate = 8000;
fmt->coding_type = AUDIO_CODING_CVSD;
} else {
fmt->sample_rate = 16000;
fmt->coding_type = AUDIO_CODING_MSBC;
}
fmt->channel_mode = AUDIO_CH_MIX;
hdl->coding_type = fmt->coding_type;
}
static void esco_ioc_stop(struct esco_file_hdl *hdl)
{
hdl->stop = 1;
lmp_esco_set_rx_notify(hdl->bt_addr, NULL, NULL);
}
void esco_ts_handle_create(struct esco_file_hdl *hdl)
{
if (!hdl) {
return;
}
#define ESCO_DELAY_TIME 60
#define ESCO_RECOGNTION_TIME 220
int delay_time = ESCO_DELAY_TIME;
/* if (get_sniff_out_status()) { */
/* clear_sniff_out_status(); */
/* if (ESCO_SIRI_WAKEUP()) { */
/* [>fix : Siri出sniff蓝牙数据到音频通路延迟过长,容易引入同步的问题<] */
/* delay_time = ESCO_RECOGNTION_TIME; */
/* } */
/* } */
if (!hdl->ts_handle) {
hdl->reference = audio_reference_clock_select(hdl->bt_addr, 0);//0 - a2dp主机,1 - tws, 2 - BLE
hdl->frame_time = (lmp_private_get_esco_packet_type() >> 8) & 0xff;
hdl->ts_handle = esco_audio_timestamp_create(hdl->frame_time, delay_time, TIME_US_FACTOR);
}
hdl->first_timestamp = 1;
}
void esco_ts_handle_release(struct esco_file_hdl *hdl)
{
if (!hdl) {
return;
}
if (hdl->ts_handle) {
esco_audio_timestamp_close(hdl->ts_handle);
hdl->ts_handle = NULL;
audio_reference_clock_exit(hdl->reference);
}
}
static void esco_file_timestamp_setup(struct esco_file_hdl *hdl)
{
int err = stream_node_ioctl(hdl->node, NODE_UUID_BT_AUDIO_SYNC, NODE_IOC_SYNCTS, 0);
if (err) {
return;
}
esco_ts_handle_create(hdl);
}
static void esco_file_timestamp_close(struct esco_file_hdl *hdl)
{
esco_ts_handle_release(hdl);
}
static int esco_ioctl(void *_hdl, int cmd, int arg)
{
struct esco_file_hdl *hdl = (struct esco_file_hdl *)_hdl;
switch (cmd) {
case NODE_IOC_SET_BTADDR:
esco_ioc_set_bt_addr(hdl, (u8 *)arg);
break;
case NODE_IOC_GET_FMT:
esco_ioc_get_fmt(hdl, (struct stream_fmt *)arg);
break;
case NODE_IOC_SUSPEND:
lmp_esco_set_rx_notify(hdl->bt_addr, NULL, NULL);
esco_start_abandon_data(hdl);
esco_file_timestamp_close(hdl);
break;
case NODE_IOC_START:
esco_stop_abandon_data(hdl);
lmp_esco_set_rx_notify(hdl->bt_addr, hdl, esco_packet_rx_notify);
esco_file_timestamp_setup(hdl);
break;
case NODE_IOC_STOP:
esco_ioc_stop(hdl);
esco_file_timestamp_close(hdl);
break;
}
return 0;
}
static void esco_release(void *_hdl)
{
struct esco_file_hdl *hdl = (struct esco_file_hdl *)_hdl;
free(hdl);
}
REGISTER_SOURCE_NODE_PLUG(esco_file_plug) = {
.uuid = NODE_UUID_ESCO_RX,
.init = esco_init,
.get_frame = esco_get_frame,
.ioctl = esco_ioctl,
.release = esco_release,
};
#endif /* #if TCFG_USER_BT_CLASSIC_ENABLE */