234 lines
6.0 KiB
C
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 */
|
|
|