Files
2025-12-03 11:12:34 +08:00

821 lines
27 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".a2dp_file.data.bss")
#pragma data_seg(".a2dp_file.data")
#pragma const_seg(".a2dp_file.text.const")
#pragma code_seg(".a2dp_file.text")
#endif
#include "btstack/a2dp_media_codec.h"
#include "btstack/avctp_user.h"
#include "source_node.h"
#include "classic/tws_api.h"
#include "system/timer.h"
#include "sync/audio_syncts.h"
#include "media/bt_audio_timestamp.h"
#include "os/os_api.h"
#include "jiffies.h"
#include "a2dp_streamctrl.h"
#include "reference_time.h"
#include "effects/effects_adj.h"
#include "app_config.h"
#if TCFG_USER_BT_CLASSIC_ENABLE
#define A2DP_TIMESTAMP_ENABLE 1
struct a2dp_file_params {
u8 edr_to_local_time;
} __attribute__((packed));
struct a2dp_file_hdl {
u8 start;
/*u8 reassemble;*/
u16 timer;
u16 wake_up_timer;
void *file;
int media_type;
struct stream_node *node;
void *ts_handle;
u32 sample_rate;
u16 codec_version;
u8 channel_num;
u16 seqn;
u32 base_time;
u32 timestamp;
u32 ts_sample_rate;
u32 dts;//total frams
u16 delay_time;
u8 sync_step;
u8 reference;
struct a2dp_media_frame frame;
int frame_len;
void *stream_ctrl;
u8 bt_addr[6];
u8 tws_case;
u8 handshake_state;
u32 request_timeout;
u32 handshake_timeout;
/*struct stream_frame *reassembled_frame;*/
u8 link_jl_dongle; //连接jl_dongle
u8 rtp_ts_en; //使用rtp的时间戳
u16 jl_dongle_latency ;
u8 edr_to_local_time;
u8 timestamp_enable;
u32 ts_align_time;//统计时间戳对齐动作的耗时
};
extern const uint32_t CONFIG_A2DP_DELAY_TIME_AAC;
extern const uint32_t CONFIG_A2DP_DELAY_TIME_SBC;
extern const int CONFIG_JL_DONGLE_PLAYBACK_LATENCY;
extern const int CONFIG_JL_DONGLE_PLAYBACK_DYNAMIC_LATENCY_ENABLE;
extern const int CONFIG_A2DP_DELAY_TIME_LO;
extern const int CONFIG_A2DP_SBC_DELAY_TIME_LO;
extern const int CONFIG_BTCTLER_TWS_ENABLE;
extern const int CONFIG_DONGLE_SPEAK_ENABLE;
extern void bt_audio_reference_clock_select(void *addr, u8 network);
extern u32 bt_audio_reference_clock_time(u8 network);
extern int a2dp_get_packet_pcm_frames(struct a2dp_file_hdl *hdl, u8 *data, int len);
static int a2dp_stream_ts_enable_detect(struct a2dp_file_hdl *hdl, u8 *packet, int *drop);
static void a2dp_frame_pack_timestamp(struct a2dp_file_hdl *hdl, struct stream_frame *frame, u8 *data, int pcm_frames);
static void a2dp_file_timestamp_setup(struct a2dp_file_hdl *hdl);
extern void bt_edr_conn_system_clock_init(void *addr, u8 factor);
extern u32 bt_edr_conn_master_to_local_time(void *addr, u32 usec);
static u8 a2dp_low_latency = 0;
#define msecs_to_bt_time(m) (((m + 1)* 1000) / 625)
#define a2dp_seqn_before(a, b) ((a < b && (u16)(b - a) < 1000) || (a > b && (u16)(a - b) > 1000))
#define RB16(b) (u16)(((u8 *)b)[0] << 8 | (((u8 *)b))[1])
#define RB32(b) (u32)(((u8 *)b)[0] << 24 | (((u8 *)b))[1] << 16 | (((u8 *)b))[2] << 8 | (((u8 *)b))[3])
#include "a2dp_handshake.c"
/*#include "a2dp_aac_demuxer.c"*/
void a2dp_file_low_latency_enable(u8 enable)
{
a2dp_low_latency = enable;
}
static void abandon_a2dp_data(void *p)
{
struct a2dp_file_hdl *hdl = (struct a2dp_file_hdl *)p;
struct a2dp_media_frame _frame;
while (a2dp_media_try_get_packet(hdl->file, &_frame) > 0) {
a2dp_media_free_packet(hdl->file, _frame.packet);
}
/*a2dp_media_clear_packet_before_seqn(hdl->file, 0);*/
}
static void a2dp_file_start_abandon_data(struct a2dp_file_hdl *hdl)
{
int role = TWS_ROLE_MASTER;
/*if (CONFIG_BTCTLER_TWS_ENABLE) {
role = tws_api_get_role();
}*/
if (role == TWS_ROLE_MASTER) {
if (hdl->timer == 0) {
hdl->timer = sys_timer_add(hdl, abandon_a2dp_data, 100);
puts("start_abandon_a2dp_data\n");
}
}
}
static void a2dp_file_stop_abandon_data(struct a2dp_file_hdl *hdl)
{
if (hdl->timer) {
sys_timer_del(hdl->timer);
hdl->timer = 0;
}
}
static void a2dp_source_wake_jlstream_run(void *_hdl)
{
struct a2dp_file_hdl *hdl = (struct a2dp_file_hdl *)_hdl;
if (hdl->start && (hdl->node->state & NODE_STA_SOURCE_NO_DATA)) {
jlstream_wakeup_thread(NULL, hdl->node, NULL);
}
}
static void a2dp_source_direct_wake_jlstream_run(void *_hdl)
{
struct a2dp_file_hdl *hdl = (struct a2dp_file_hdl *)_hdl;
if (hdl) {
if (hdl->node) {
jlstream_wakeup_thread(NULL, hdl->node, NULL);
}
hdl->ts_align_time += 4;
}
}
static enum stream_node_state a2dp_get_frame(void *_hdl, struct stream_frame **pframe)
{
struct a2dp_file_hdl *hdl = (struct a2dp_file_hdl *)_hdl;
struct a2dp_media_frame _frame;
int drop = 0;
int stream_error = 0;
*pframe = NULL;
#if A2DP_TIMESTAMP_ENABLE
if (!hdl->rtp_ts_en && !hdl->ts_handle) {
int err = a2dp_tws_media_handshake(hdl);
if (hdl->timestamp_enable && err) {
if (!hdl->wake_up_timer) {//快速唤醒数据流,加速tws时间戳交互的过程
hdl->ts_align_time = 0;
hdl->wake_up_timer = sys_hi_timer_add((void *)hdl, a2dp_source_direct_wake_jlstream_run, 4);
}
return NODE_STA_RUN | NODE_STA_SOURCE_NO_DATA;
}
log_d(">>>>handshake time %d ms<<<<\n", hdl->ts_align_time);
if (hdl->wake_up_timer) {
sys_hi_timer_del(hdl->wake_up_timer);
hdl->wake_up_timer = 0;
}
a2dp_file_timestamp_setup(hdl);
}
#endif
if ((!hdl->ts_handle /* || hdl->edr_to_local_time */) && hdl->start == 0) {
int delay = a2dp_media_get_remain_play_time(hdl->file, 1);
if (delay < (hdl->ts_handle ? hdl->delay_time : 300)) {
return NODE_STA_RUN | NODE_STA_SOURCE_NO_DATA;
}
hdl->start = 1;
}
int len = hdl->frame_len;
if (len == 0) {
if (hdl->stream_ctrl) {
stream_error = a2dp_stream_control_pull_frame(hdl->stream_ctrl, &_frame, &len);
} else {
len = a2dp_media_try_get_packet(hdl->file, &_frame);
}
if (len <= 0) {
return NODE_STA_RUN | NODE_STA_SOURCE_NO_DATA;
}
hdl->frame_len = len;
memcpy(&hdl->frame, &_frame, sizeof(struct a2dp_media_frame));
} else {
memcpy(&_frame, &hdl->frame, sizeof(struct a2dp_media_frame));
}
hdl->seqn = RB16((u8 *)_frame.packet + 2);
int err = a2dp_stream_ts_enable_detect(hdl, _frame.packet, &drop);
if (err) {
if (drop) {
if (hdl->stream_ctrl) {
a2dp_stream_control_free_frame(hdl->stream_ctrl, &_frame);
} else {
a2dp_media_free_packet(hdl->file, _frame.packet);
}
hdl->frame_len = 0;
}
a2dp_tws_media_try_handshake_ack(0, hdl->seqn);
if (!hdl->wake_up_timer) {//快速唤醒数据流,加速tws时间戳交互的过程
hdl->ts_align_time = 0;
hdl->wake_up_timer = sys_hi_timer_add((void *)hdl, a2dp_source_direct_wake_jlstream_run, 4);
}
return NODE_STA_RUN | NODE_STA_SOURCE_NO_DATA;
}
if (hdl->wake_up_timer) {
sys_hi_timer_del(hdl->wake_up_timer);
hdl->wake_up_timer = 0;
}
int head_len = a2dp_media_get_rtp_header_len(hdl->media_type, _frame.packet, len);
struct stream_frame *frame;
int frame_len = len - head_len;
frame = jlstream_get_frame(hdl->node->oport, frame_len);
if (frame == NULL) {
return NODE_STA_RUN;
}
frame->len = frame_len;
frame->timestamp = _frame.clkn;
frame->flags |= (stream_error);
a2dp_frame_pack_timestamp(hdl, frame, _frame.packet + 4, //时间戳的地址
a2dp_get_packet_pcm_frames(hdl,
_frame.packet + head_len, frame_len));
a2dp_tws_media_try_handshake_ack(1, hdl->seqn);
memcpy(frame->data, _frame.packet + head_len, frame_len);
if (hdl->stream_ctrl) {
a2dp_stream_control_free_frame(hdl->stream_ctrl, &_frame);
} else {
a2dp_media_free_packet(hdl->file, _frame.packet);
}
hdl->frame_len = 0;
hdl->start = 1;
ASSERT(frame);
*pframe = frame;
return NODE_STA_RUN;
}
static void *a2dp_init(void *priv, struct stream_node *node)
{
struct a2dp_file_hdl *hdl = zalloc(sizeof(*hdl));
hdl->node = node;
u16 plug_uuid = get_source_node_plug_uuid(priv);
struct a2dp_file_params params = {0};
jlstream_read_node_data_by_cfg_index(plug_uuid, hdl->node->subid, 0, (void *)&params, NULL);
hdl->edr_to_local_time = params.edr_to_local_time;
return hdl;
}
static const u32 aac_sample_rates[] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000,
};
static const u16 sbc_sample_rates[] = {16000, 32000, 44100, 48000};
static const u32 ldac_sample_rates[] = {44100, 48000, 88200, 96000};
static int a2dp_ioc_get_fmt(struct a2dp_file_hdl *hdl, struct stream_fmt *fmt)
{
struct a2dp_media_frame _frame;
int type = a2dp_media_get_codec_type(hdl->file);
char *code_type;
switch (type) {
case A2DP_CODEC_SBC:
fmt->coding_type = AUDIO_CODING_SBC;
code_type = "SBC";
break;
#if (defined(TCFG_BT_SUPPORT_AAC) && TCFG_BT_SUPPORT_AAC)
case A2DP_CODEC_MPEG24:
fmt->coding_type = AUDIO_CODING_AAC;
code_type = "AAC";
break;
#endif
#if (defined(TCFG_BT_SUPPORT_LDAC) && TCFG_BT_SUPPORT_LDAC)
case A2DP_CODEC_LDAC:
fmt->coding_type = AUDIO_CODING_LDAC;
code_type = "LDAC";
break;
#endif
#if (defined(TCFG_BT_SUPPORT_LHDC) && TCFG_BT_SUPPORT_LHDC)
case A2DP_CODEC_LHDC: //LHDC 直接从蓝牙获取格式信息。
fmt->coding_type = AUDIO_CODING_LHDC;
fmt->sample_rate = a2dp_media_get_sample_rate(hdl->file);
fmt->dec_bit_wide = a2dp_media_get_bit_wide(hdl->file);
fmt->codec_version = a2dp_media_get_codec_version(hdl->file);
fmt->channel_mode = AUDIO_CH_LR;
hdl->media_type = type;
hdl->codec_version = fmt->codec_version;
hdl->sample_rate = fmt->sample_rate;
hdl->channel_num = (fmt->channel_mode == AUDIO_CH_LR) ? 2 : 1;
printf("a2dp format %s, sample_rate %d, bit_wide %d, codec_version %d\n",
"lhdc", hdl->sample_rate, fmt->bit_wide, fmt->codec_version);
return 0;
#endif
default:
code_type = "unknown";
break;
}
if (hdl->sample_rate) {
fmt->sample_rate = hdl->sample_rate;
fmt->channel_mode = hdl->channel_num == 2 ? AUDIO_CH_LR : AUDIO_CH_MIX;
return 0;
}
hdl->media_type = type;
__again:
int len = a2dp_media_try_get_packet(hdl->file, &_frame);
if (len <= 0) {
return -EAGAIN;
}
u8 *packet = _frame.packet;
int head_len = a2dp_media_get_rtp_header_len(type, packet, len);
if (head_len >= len) {
a2dp_media_free_packet(hdl->file, packet);
goto __again;
}
/*put_buf(packet, head_len + 8);*/
u8 *frame = packet + head_len;
if (frame[0] == 0x47) { //常见mux aac格式
#if (defined(TCFG_BT_SUPPORT_AAC) && TCFG_BT_SUPPORT_AAC)
u8 sr = (frame[5] & 0x3C) >> 2;
/* u8 ch = ((frame[5] & 0x3) << 2) | ((frame[6] & 0xC0) >> 6); */
fmt->channel_mode = AUDIO_CH_LR;
fmt->sample_rate = aac_sample_rates[sr];
} else if (frame[0] == 0x20) { //特殊LATM aac格式
u8 sr = ((frame[2] & 0x7) << 1) | ((frame[3] & 0x80) >> 7);
/* u8 ch = ((frame[3] & 0x78) >> 3) ; */
fmt->channel_mode = AUDIO_CH_LR;
fmt->sample_rate = aac_sample_rates[sr];
#endif
} else if (frame[0] == 0x9C) { //sbc 格式
/*
* 检查数据是否为AAC格式,
* 可以切换AAC和SBC格式的手机可能切换后数据格式和type不对应
*/
head_len = a2dp_media_get_rtp_header_len(A2DP_CODEC_MPEG24, packet, len);
if (head_len < len) {
if (packet[head_len] == 0x47 || packet[head_len] == 0x20) {
a2dp_media_free_packet(hdl->file, packet);
goto __again;
}
}
u8 sr = (frame[1] >> 6) & 0x3;
u8 ch = (frame[1] >> 2) & 0x3;
if (ch == 0) {
fmt->channel_mode = AUDIO_CH_MIX;
} else {
fmt->channel_mode = AUDIO_CH_LR;
}
fmt->sample_rate = sbc_sample_rates[sr];
#if (defined(TCFG_BT_SUPPORT_LDAC) && TCFG_BT_SUPPORT_LDAC)
} else if (frame[1] == 0xAA) {
u8 sr = (frame[2] >> (8 - 3)) & 0x7;
int chconfig_id = (frame[2] >> (8 - 5)) & 0x03;
fmt->channel_mode = AUDIO_CH_LR;
fmt ->sample_rate = ldac_sample_rates[sr];
fmt->chconfig_id = chconfig_id;
//printf(" %x %x %x\n",frame[0],frame[1],frame[2]);
//printf("sr:%d, sample_rate : %d chconfig_id : %d\n",sr,fmt->sample_rate,chconfig_id);
#endif
} else {
/*
* 小米8手机先播sbc,暂停后切成AAC格式点播放,有时第一包数据还是sbc格式
* 导致这里获取头信息错误
*/
a2dp_media_free_packet(hdl->file, packet);
goto __again;
}
a2dp_media_put_packet(hdl->file, packet);
hdl->sample_rate = fmt->sample_rate;
hdl->channel_num = (fmt->channel_mode == AUDIO_CH_LR) ? 2 : 1;
printf("a2dp %d, format %s\n", hdl->sample_rate, code_type);
return 0;
}
static int a2dp_ioc_set_bt_addr(struct a2dp_file_hdl *hdl, u8 *bt_addr)
{
hdl->file = a2dp_open_media_file(bt_addr);
if (!hdl->file) {
printf("open_file_faild\n");
put_buf(bt_addr, 6);
return -EINVAL;
}
memcpy(hdl->bt_addr, bt_addr, 6);
if (CONFIG_DONGLE_SPEAK_ENABLE) {
if (btstack_get_dev_type_for_addr(hdl->bt_addr) == REMOTE_DEV_DONGLE_SPEAK) {
hdl->link_jl_dongle = 1;
hdl->jl_dongle_latency = CONFIG_JL_DONGLE_PLAYBACK_LATENCY;
if (!CONFIG_JL_DONGLE_PLAYBACK_DYNAMIC_LATENCY_ENABLE) {
hdl->rtp_ts_en = 1;
}
}
}
return 0;
}
static void a2dp_ioc_stop(struct a2dp_file_hdl *hdl)
{
if (hdl->wake_up_timer) {
sys_hi_timer_del(hdl->wake_up_timer);
hdl->wake_up_timer = 0;
}
/*hdl->sample_rate = 0;*/
if (hdl->frame_len) {
if (hdl->stream_ctrl) {
a2dp_stream_control_free_frame(hdl->stream_ctrl, &hdl->frame);
} else {
a2dp_media_free_packet(hdl->file, hdl->frame.packet);
}
hdl->frame_len = 0;
}
a2dp_file_stop_abandon_data(hdl);
/*a2dp_media_clear_packet_before_seqn(hdl->file, 0);*/
a2dp_media_stop_play(hdl->file);
hdl->start = 0;
}
static int sbc_get_packet_pcm_frames(u8 *data, int len)
{
data++;
u8 ch = (data[0] >> 2) & 0x3;
u8 subbands = (data[0] & 0x01) ? 8 : 4;
u8 blocks = (((data[0] >> 4) & 0x03) + 1) * 4;
u8 channels = ch == 0x0 ? 1 : 2;
u8 joint = ch == 0x3 ? 1 : 0;
u8 bitpool = data[1] & 0xff;
int frame_len = 4 + ((4 * subbands * channels) >> 3);
if (ch >= 0x2) {
frame_len += (((joint ? subbands : 0) + blocks * bitpool) + 7) >> 3;
} else {
frame_len += ((blocks * channels * bitpool) + 7) >> 3;
}
return (len / frame_len) * (blocks * subbands);
}
static int lhdc_get_packet_pcm_frames(void *_hdl, u8 *data, int len, int unit)
{
struct a2dp_file_hdl *hdl = (struct a2dp_file_hdl *)_hdl;
int point = 0;
u8 frame_num = (data[0] & 0x3C) >> 2;
//目前测试LHDC 每帧输出点数是这样的。如果存在兼容性问题。这里需要同步兼容
if (hdl->codec_version == 400) { //lhdc_v4
point = 256;
} else if (hdl->codec_version == 500) {
/* if(hdl->sample_rate == 48000){ */
/* point = 240 ; */
/* }else if(hdl->sample_rate == 44100){ */
/* point = 220; */
/* } */
point = hdl->sample_rate / 1000 * 5; //5ms 的数据量
} else if (hdl->codec_version == 300) { //lhdc_v3
point = 256;
}
return frame_num * point * (unit);
}
static int a2dp_get_packet_pcm_frames(struct a2dp_file_hdl *hdl, u8 *data, int len)
{
u8 unit = 1;
u32 frames = 0;
switch (hdl->media_type) {
case A2DP_CODEC_SBC:
frames = sbc_get_packet_pcm_frames(data, len);//frame_num * 128 * (unit);
break;
case A2DP_CODEC_MPEG24:
u32 audio_mux_element = 0xffffffff;
memcpy(&audio_mux_element, data, len >= sizeof(audio_mux_element) ? sizeof(audio_mux_element) : len);
if (audio_mux_element == 0xFC47 || audio_mux_element == 0x10120020) {
frames = 1024 * (unit);
}
break;
#if (defined(TCFG_BT_SUPPORT_LHDC) && TCFG_BT_SUPPORT_LHDC)
case A2DP_CODEC_LHDC:
frames = lhdc_get_packet_pcm_frames(hdl, data, len, unit);//frame_num * point * (unit);
break;
#endif
#if (defined(TCFG_BT_SUPPORT_LDAC) && TCFG_BT_SUPPORT_LDAC)
case A2DP_CODEC_LDAC:
u8 frame_num = data[0] & 0xf;
/* printf("ldac : frame_num = %d\n",frame_num); */
if (hdl->sample_rate <= 48000) {
frames = frame_num * 128 * (unit);//frame_num * point * (unit);
} else {
frames = frame_num * 256 * (unit);
}
break;
#endif
default:
log_e("unsupport codec_type : 0x%x\n", hdl->media_type);
break;
}
/* printf("frames %d\n", frames); */
return frames;
}
static void a2dp_stream_control_open(struct a2dp_file_hdl *hdl)
{
/*
* 策略选择:
* 1、是否低延时
* 2、解码格式?
* 3、策略方案 - 默认0,其他为定制方案
*/
if (hdl->stream_ctrl) {
return;
}
if (hdl->link_jl_dongle) {
hdl->stream_ctrl = a2dp_stream_control_plan_select(hdl->file, a2dp_low_latency, hdl->media_type, A2DP_STREAM_JL_DONGLE_CONTROL);
} else {
hdl->stream_ctrl = a2dp_stream_control_plan_select(hdl->file, a2dp_low_latency, hdl->media_type, 0);
}
if (hdl->stream_ctrl) {
hdl->delay_time = a2dp_stream_control_delay_time(hdl->stream_ctrl);
a2dp_stream_control_set_underrun_callback(hdl->stream_ctrl, hdl, a2dp_source_wake_jlstream_run);
}
}
static void a2dp_stream_control_close(struct a2dp_file_hdl *hdl)
{
if (hdl->stream_ctrl) {
a2dp_stream_control_free(hdl->stream_ctrl);
hdl->stream_ctrl = NULL;
}
}
static u32 a2dp_stream_update_base_time(struct a2dp_file_hdl *hdl)
{
struct a2dp_media_frame frame;
int distance_time = 0;
int len = a2dp_media_try_get_packet(hdl->file, &frame);
if (len > 0) {
u32 base_clkn = frame.clkn;
/* if (CONFIG_BTCTLER_TWS_ENABLE && a2dp_low_latency) { */
/* base_clkn = bt_audio_reference_clock_time(0); */
/* } */
a2dp_media_put_packet(hdl->file, frame.packet);
u32 base_time = base_clkn + msecs_to_bt_time((hdl->delay_time < 100 ? 100 : hdl->delay_time));
if ((int)(base_time - bt_audio_reference_clock_time(0)) < msecs_to_bt_time(150)) {//启动过程耗时很长,此处为避免时间戳超时,加上150ms
base_time = bt_audio_reference_clock_time(0) + msecs_to_bt_time(150);
}
return base_time;
}
distance_time = a2dp_low_latency ? hdl->delay_time : (hdl->delay_time - a2dp_media_get_remain_play_time(hdl->file, 1));
if (!a2dp_low_latency) {
distance_time = hdl->delay_time;
} else if (distance_time < 100) {
distance_time = 100;
}
/*printf("distance time : %d, %d, %d\n", hdl->delay_time, a2dp_media_get_remain_play_time(hdl->file, 1), distance_time);*/
return bt_audio_reference_clock_time(0) + msecs_to_bt_time(distance_time);
}
void a2dp_ts_handle_create(struct a2dp_file_hdl *hdl)
{
if (!hdl || (hdl->rtp_ts_en)) {
return;
}
if (hdl->ts_handle) {
return;
}
#if A2DP_TIMESTAMP_ENABLE
if (!hdl->timestamp_enable) {
return;
}
hdl->base_time = a2dp_stream_update_base_time(hdl);
int check_diff = hdl->base_time - bt_audio_reference_clock_time(0);
if (check_diff < 0) {
printf("a2dp base_time is outdated: %d ms\n", (int)(check_diff * 0.625));
} else {
printf("a2dp features play time: after %d ms\n", (int)(check_diff * 0.625));
}
printf("a2dp timestamp base time : %d, %d\n", hdl->base_time, bt_audio_reference_clock_time(0));
hdl->ts_handle = a2dp_audio_timestamp_create(hdl->sample_rate, hdl->base_time, TIMESTAMP_US_DENOMINATOR);
if (hdl->edr_to_local_time) {
bt_edr_conn_system_clock_init(hdl->bt_addr, TIMESTAMP_US_DENOMINATOR);
/*printf("--[%s - %d] bt edr system clock init : %u, %lu--\n", __FUNCTION__, __LINE__, hdl->base_time, jiffies_usec());*/
}
hdl->sync_step = 0;
hdl->frame_len = 0;
hdl->dts = 0;
#endif
}
void a2dp_ts_handle_release(struct a2dp_file_hdl *hdl)
{
if (!hdl) {
return;
}
#if A2DP_TIMESTAMP_ENABLE
if (hdl->ts_handle) {
a2dp_audio_timestamp_close(hdl->ts_handle);
hdl->ts_handle = NULL;
a2dp_tws_audio_conn_offline();
}
#endif
}
static void a2dp_frame_pack_timestamp(struct a2dp_file_hdl *hdl, struct stream_frame *frame, u8 *data, int pcm_frames)
{
if (CONFIG_DONGLE_SPEAK_ENABLE) {
if (hdl->link_jl_dongle && hdl->rtp_ts_en) {
u32 ts = RB32(data);
frame->timestamp = ts + hdl->jl_dongle_latency * 1000 * 32;
frame->flags |= (FRAME_FLAG_TIMESTAMP_ENABLE | FRAME_FLAG_UPDATE_TIMESTAMP);
/* printf("ts : %u, %u, %u\n",ts,frame->timestamp, bt_audio_reference_clock_time(0)); */
return;
}
}
if (!hdl->ts_handle || pcm_frames == 0) {
frame->flags &= ~FRAME_FLAG_TIMESTAMP_ENABLE;
return;
}
if (CONFIG_BTCTLER_TWS_ENABLE && (frame->flags & FRAME_FLAG_RESET_TIMESTAMP_BIT)) {
/*printf("----stream error : resume----\n");*/
tws_a2dp_share_timestamp(hdl->ts_handle);
}
u32 timestamp = a2dp_audio_update_timestamp(hdl->ts_handle, hdl->seqn, hdl->dts);
int delay_time = hdl->stream_ctrl ? a2dp_stream_control_delay_time(hdl->stream_ctrl) : hdl->delay_time;
int frame_delay = (timestamp - (frame->timestamp * 625 * TIME_US_FACTOR)) / 1000 / TIME_US_FACTOR;
/*int distance_time = (int)(timestamp - (frame->timestamp * 625 * TIME_US_FACTOR)) / 1000 / TIME_US_FACTOR - delay_time;*/
int distance_time = frame_delay - delay_time;
a2dp_audio_delay_offset_update(hdl->ts_handle, distance_time);
frame->flags |= (FRAME_FLAG_TIMESTAMP_ENABLE | FRAME_FLAG_UPDATE_TIMESTAMP | FRAME_FLAG_UPDATE_DRIFT_SAMPLE_RATE);
if (hdl->edr_to_local_time) {
timestamp = bt_edr_conn_master_to_local_time(hdl->bt_addr, timestamp);
}
frame->timestamp = timestamp;
frame->d_sample_rate = a2dp_audio_sample_rate(hdl->ts_handle) - hdl->sample_rate;
/*printf("drift : %d\n", frame->d_sample_rate);*/
/*printf("-%u, %u, %u-\n", timestamp, bt_edr_conn_master_to_local_time(hdl->bt_addr, timestamp), local_time);*/
hdl->dts += pcm_frames;
a2dp_stream_mark_next_timestamp(hdl->stream_ctrl, timestamp + PCM_SAMPLE_TO_TIMESTAMP(pcm_frames, hdl->sample_rate));
a2dp_stream_bandwidth_detect_handler(hdl->stream_ctrl, pcm_frames, hdl->sample_rate);
}
static int a2dp_stream_ts_enable_detect(struct a2dp_file_hdl *hdl, u8 *packet, int *drop)
{
if (hdl->sync_step) {
return 0;
}
if (!drop) {
printf("wrong argument 'drop'!\n");
}
if (CONFIG_BTCTLER_TWS_ENABLE && hdl->ts_handle) {
if (hdl->tws_case != 1 && \
!a2dp_audio_timestamp_is_available(hdl->ts_handle, hdl->seqn, 0, drop)) {
if (*drop) {
hdl->base_time = a2dp_stream_update_base_time(hdl);
a2dp_audio_set_base_time(hdl->ts_handle, hdl->base_time);
}
return -EINVAL;
}
}
log_d(">>>>ts align time %d ms<<<<\n", hdl->ts_align_time);
hdl->sync_step = 2;
return 0;
}
static void a2dp_media_reference_time_setup(struct a2dp_file_hdl *hdl)
{
#if A2DP_TIMESTAMP_ENABLE
int err = stream_node_ioctl(hdl->node, NODE_UUID_BT_AUDIO_SYNC, NODE_IOC_SYNCTS, 0);
if (err) {
err = stream_node_ioctl(hdl->node, NODE_UUID_CAPTURE_SYNC, NODE_IOC_SYNCTS, 0);
if (err) {
return;
}
/* hdl->edr_to_local_time = 1; //由界面配置*/
}
if (CONFIG_BTCTLER_TWS_ENABLE) {
a2dp_tws_audio_conn_delete();//处理两边交流时主机吴判断从机离线,结束对齐时间戳的情况
}
hdl->timestamp_enable = 1;
if (!hdl->edr_to_local_time) {
hdl->reference = audio_reference_clock_select(hdl->bt_addr, 0);//0 - a2dp主机,1 - tws, 2 - BLE
}
#endif
}
static void a2dp_media_reference_time_close(struct a2dp_file_hdl *hdl)
{
#if A2DP_TIMESTAMP_ENABLE
if (!hdl->edr_to_local_time) {
audio_reference_clock_exit(hdl->reference);
}
#endif
}
static void a2dp_file_timestamp_setup(struct a2dp_file_hdl *hdl)
{
a2dp_stream_control_open(hdl);
a2dp_ts_handle_create(hdl);
}
static void a2dp_file_timestamp_close(struct a2dp_file_hdl *hdl)
{
a2dp_tws_media_handshake_exit(hdl);
a2dp_stream_control_close(hdl);
a2dp_ts_handle_release(hdl);
}
static int a2dp_ioctl(void *_hdl, int cmd, int arg)
{
int err = 0;
struct a2dp_file_hdl *hdl = (struct a2dp_file_hdl *)_hdl;
switch (cmd) {
case NODE_IOC_SET_BTADDR:
err = a2dp_ioc_set_bt_addr(hdl, (u8 *)arg);
break;
case NODE_IOC_GET_BTADDR:
memcpy((u8 *)arg, hdl->bt_addr, 6);
break;
case NODE_IOC_GET_FMT:
err = a2dp_ioc_get_fmt(hdl, (struct stream_fmt *)arg);
stream_node_ioctl(hdl->node, NODE_UUID_BT_AUDIO_SYNC, NODE_IOC_SET_SYNC_NETWORK, hdl->edr_to_local_time ? AUDIO_NETWORK_LOCAL : AUDIO_NETWORK_BT2_1);
break;
case NODE_IOC_SET_PRIV_FMT:
break;
case NODE_IOC_START:
a2dp_media_start_play(hdl->file);
a2dp_media_set_rx_notify(hdl->file, hdl, a2dp_source_wake_jlstream_run);
a2dp_file_stop_abandon_data(hdl);
a2dp_media_reference_time_setup(hdl);
break;
case NODE_IOC_SUSPEND:
/*hdl->sample_rate = 0;*/
a2dp_media_set_rx_notify(hdl->file, NULL, NULL);
a2dp_ioc_stop(hdl);
a2dp_file_timestamp_close(hdl);
a2dp_media_reference_time_close(hdl);
a2dp_file_start_abandon_data(hdl);
break;
case NODE_IOC_STOP:
a2dp_media_set_rx_notify(hdl->file, NULL, NULL);
a2dp_ioc_stop(hdl);
a2dp_file_timestamp_close(hdl);
a2dp_media_reference_time_close(hdl);
break;
}
return err;
}
static void a2dp_release(void *_hdl)
{
struct a2dp_file_hdl *hdl = (struct a2dp_file_hdl *)_hdl;
a2dp_close_media_file(hdl->file);
a2dp_file_stop_abandon_data(hdl);
free(hdl);
}
REGISTER_SOURCE_NODE_PLUG(a2dp_file_plug) = {
.uuid = NODE_UUID_A2DP_RX,
.frame_size = 1024,
.init = a2dp_init,
.get_frame = a2dp_get_frame,
.ioctl = a2dp_ioctl,
.release = a2dp_release,
};
#endif /* #if TCFG_USER_BT_CLASSIC_ENABLE */