337 lines
8.6 KiB
C
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;
|
|
}
|
|
}
|