Files
AC707N/SDK/audio/interface/player/a2dp_player.c
T
2025-12-03 11:12:34 +08:00

337 lines
8.6 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".a2dp_player.data.bss")
#pragma data_seg(".a2dp_player.data")
#pragma const_seg(".a2dp_player.text.const")
#pragma code_seg(".a2dp_player.text")
#endif
#include "jlstream.h"
#include "classic/tws_api.h"
#include "media/audio_base.h"
#include "a2dp_player.h"
#include "btstack/a2dp_media_codec.h"
#include "media/bt_audio_timestamp.h"
#include "effects/audio_pitchspeed.h"
#include "app_config.h"
#include "effects/audio_vbass.h"
#include "audio_config_def.h"
#if TCFG_AUDIO_DUT_ENABLE
#include "audio_dut_control.h"
#endif/*TCFG_AUDIO_DUT_ENABLE*/
#if (defined TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE) && TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
#include "icsd_adt_app.h"
#endif
#if TCFG_SMART_VOICE_ENABLE
#include "smart_voice/smart_voice.h"
#endif
extern struct audio_dac_hdl dac_hdl;
struct a2dp_player {
u8 bt_addr[6];
u16 retry_timer;
s8 a2dp_pitch_mode;
struct jlstream *stream;
};
extern void dac_try_power_on_task_delete();
static struct a2dp_player *g_a2dp_player = NULL;
extern const int CONFIG_BTCTLER_TWS_ENABLE;
static void a2dp_player_callback(void *private_data, int event)
{
struct a2dp_player *player = g_a2dp_player;
printf("a2dp_callback: %d\n", event);
switch (event) {
case STREAM_EVENT_START:
#if AUDIO_VBASS_LINK_VOLUME
vbass_link_volume();
#endif
break;
}
}
static void a2dp_player_set_audio_channel(struct a2dp_player *player)
{
int channel = AUDIO_CH_MIX;
if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
}
jlstream_ioctl(player->stream, NODE_IOC_SET_CHANNEL, channel);
}
void a2dp_player_tws_event_handler(int *msg)
{
struct tws_event *evt = (struct tws_event *)msg;
u8 state = evt->args[1];
switch (evt->event) {
case TWS_EVENT_MONITOR_START:
if (!(state & TWS_STA_SBC_OPEN)) {
break;
}
case TWS_EVENT_CONNECTION_DETACH:
case TWS_EVENT_REMOVE_PAIRS:
if (g_a2dp_player) {
a2dp_player_set_audio_channel(g_a2dp_player);
}
break;
default:
break;
}
a2dp_tws_timestamp_event_handler(evt->event, evt->args);
}
static int a2dp_player_create(u8 *btaddr)
{
int uuid;
struct a2dp_player *player = g_a2dp_player;
uuid = jlstream_event_notify(STREAM_EVENT_GET_PIPELINE_UUID, (int)"a2dp");
if (player) {
if (player->stream) {
if (!memcmp(player->bt_addr, btaddr, 6)) {
return -EEXIST;
}
puts("a2dp_player_busy\n");
return -EBUSY;
}
if (player->retry_timer) {
sys_timer_del(player->retry_timer);
player->retry_timer = 0;
}
} else {
player = zalloc(sizeof(*player));
if (!player) {
return -ENOMEM;
}
g_a2dp_player = player;
}
memcpy(player->bt_addr, btaddr, 6);
player->stream = jlstream_pipeline_parse(uuid, NODE_UUID_A2DP_RX);
if (!player->stream) {
printf("create a2dp stream faild\n");
return -EFAULT;
}
return 0;
}
void a2dp_player_low_latency_enable(u8 enable)
{
#if TCFG_USER_BT_CLASSIC_ENABLE
a2dp_file_low_latency_enable(enable);
#endif /* #if TCFG_USER_BT_CLASSIC_ENABLE */
}
static void retry_open_a2dp_player(void *p)
{
if (g_a2dp_player && !g_a2dp_player->stream) {
a2dp_player_open(g_a2dp_player->bt_addr);
}
}
static void retry_start_a2dp_player(void *p)
{
if (g_a2dp_player && g_a2dp_player->stream) {
int err = jlstream_start(g_a2dp_player->stream);
if (err == 0) {
dac_try_power_on_task_delete();
sys_timer_del(g_a2dp_player->retry_timer);
g_a2dp_player->retry_timer = 0;
}
}
}
int a2dp_player_open(u8 *btaddr)
{
int err;
#if (defined TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE) && TCFG_AUDIO_SPEAK_TO_CHAT_ENABLE
if (get_speak_to_chat_state() == AUDIO_ADT_CHAT) {
audio_speak_to_char_sync_suspend();
}
#endif
err = a2dp_player_create(btaddr);
if (err) {
if (err == -EFAULT) {
g_a2dp_player->retry_timer = sys_timer_add(NULL, retry_open_a2dp_player, 200);
}
return err;
}
struct a2dp_player *player = g_a2dp_player;
player->a2dp_pitch_mode = PITCH_0; //默认打开是原声调
jlstream_set_callback(player->stream, NULL, a2dp_player_callback);
jlstream_set_scene(player->stream, STREAM_SCENE_A2DP);
if (CONFIG_BTCTLER_TWS_ENABLE) {
if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
int channel = tws_api_get_local_channel() == 'L' ? AUDIO_CH_L : AUDIO_CH_R;
jlstream_ioctl(player->stream, NODE_IOC_SET_CHANNEL, channel);
}
}
err = jlstream_node_ioctl(player->stream, NODE_UUID_SOURCE,
NODE_IOC_SET_BTADDR, (int)player->bt_addr);
if (err == 0) {
err = jlstream_start(player->stream);
if (err) {
g_a2dp_player->retry_timer = sys_timer_add(NULL, retry_start_a2dp_player, 200);
return 0;
} else {
dac_try_power_on_task_delete();
}
}
if (err) {
jlstream_release(player->stream);
free(player);
g_a2dp_player = NULL;
return err;
}
#if (TCFG_SMART_VOICE_ENABLE && TCFG_SMART_VOICE_USE_AEC)
audio_smart_voice_aec_open();
#endif
puts("a2dp_open_dec_file_suss\n");
return 0;
}
int a2dp_player_runing()
{
return g_a2dp_player ? 1 : 0;
}
int a2dp_player_get_btaddr(u8 *btaddr)
{
if (g_a2dp_player) {
memcpy(btaddr, g_a2dp_player->bt_addr, 6);
return 1;
}
return 0;
}
bool a2dp_player_is_playing(u8 *bt_addr)
{
if (g_a2dp_player && memcmp(bt_addr, g_a2dp_player->bt_addr, 6) == 0) {
return 1;
}
return 0;
}
int a2dp_player_start_slience_detect(u8 *btaddr, void (*handler)(u8 *, bool), int msec)
{
if (!g_a2dp_player || memcmp(g_a2dp_player->bt_addr, btaddr, 6)) {
return -EINVAL;
}
return 0;
}
void a2dp_player_close(u8 *btaddr)
{
struct a2dp_player *player = g_a2dp_player;
if (!player) {
return;
}
if (memcmp(player->bt_addr, btaddr, 6)) {
return;
}
if (player->retry_timer) {
sys_timer_del(player->retry_timer);
player->retry_timer = 0;
}
if (player->stream) {
jlstream_stop(player->stream, 100);
jlstream_release(player->stream);
}
free(player);
g_a2dp_player = NULL;
jlstream_event_notify(STREAM_EVENT_CLOSE_PLAYER, (int)"a2dp");
#if (TCFG_SMART_VOICE_ENABLE && TCFG_SMART_VOICE_USE_AEC)
audio_smart_voice_aec_close();
#endif
}
//复位当前的数据流
void a2dp_player_reset(void)
{
u8 bt_addr[6];
if (g_a2dp_player) {
memcpy(bt_addr, g_a2dp_player->bt_addr, 6);
a2dp_player_close(bt_addr);
a2dp_player_open(bt_addr);
}
}
//变调接口
int a2dp_file_pitch_up()
{
struct a2dp_player *player = g_a2dp_player;
if (!player) {
return -1;
}
float pitch_param_table[] = {-12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12};
player->a2dp_pitch_mode++;
if (player->a2dp_pitch_mode > ARRAY_SIZE(pitch_param_table) - 1) {
player->a2dp_pitch_mode = ARRAY_SIZE(pitch_param_table) - 1;
}
printf("play pitch up+++%d\n", player->a2dp_pitch_mode);
int ret = a2dp_file_set_pitch(player->a2dp_pitch_mode);
ret = (ret == true) ? player->a2dp_pitch_mode : -1;
return ret;
}
int a2dp_file_pitch_down()
{
struct a2dp_player *player = g_a2dp_player;
if (!player) {
return -1;
}
player->a2dp_pitch_mode--;
if (player->a2dp_pitch_mode < 0) {
player->a2dp_pitch_mode = 0;
}
printf("play pitch down---%d\n", player->a2dp_pitch_mode);
int ret = a2dp_file_set_pitch(player->a2dp_pitch_mode);
ret = (ret == true) ? player->a2dp_pitch_mode : -1;
return ret;
}
int a2dp_file_set_pitch(enum _pitch_level pitch_mode)
{
struct a2dp_player *player = g_a2dp_player;
float pitch_param_table[] = {-12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12};
if (pitch_mode > ARRAY_SIZE(pitch_param_table) - 1) {
pitch_mode = ARRAY_SIZE(pitch_param_table) - 1;
}
pitch_speed_param_tool_set pitch_param = {
.pitch = pitch_param_table[pitch_mode],
.speed = 1,
};
if (player) {
player->a2dp_pitch_mode = pitch_mode;
return jlstream_node_ioctl(player->stream, NODE_UUID_PITCH_SPEED, NODE_IOC_SET_PARAM, (int)&pitch_param);
}
return -1;
}
void a2dp_file_pitch_mode_init(enum _pitch_level pitch_mode)
{
struct a2dp_player *player = g_a2dp_player;
if (player) {
player->a2dp_pitch_mode = pitch_mode;
}
}