mcu_hi3321_watch/tjd/ui/app/player/TjdUiBTA2dpEvent.cpp
2025-05-26 20:15:20 +08:00

245 lines
10 KiB
C++

/*----------------------------------------------------------------------------
* Copyright (c) TJD Technologies Co., Ltd. 2025. All rights reserved.
*
* Description: TjdUiBTA2dpSrcEvent.cpp
*
* Author: luziquan@ss-tjd.com
*
* Create: 2025-04-11
*--------------------------------------------------------------------------*/
#include "TjdPhoneAudio.h"
#include "TjdUiAppPlayerModel.h"
#include "audio_manager_c_wrapper.h"
#include "bt_audio_hal_interface.h"
#include "bts_a2dp_sink.h"
#include "bts_a2dp_source.h"
#include "graphic_service.h"
#include "sys_config.h"
namespace TJD {
#define ENABLE_PRINT_INFO 1
#define ENABLE_DEBUG 1
#if ENABLE_PRINT_INFO
#define static_print_info(...) sys_ui_log_i(__VA_ARGS__) // 一般信息打印宏控制
#define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) // 警告信息打印一般常开
#define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开
#if ENABLE_DEBUG
#define static_print_debug(...) sys_ui_log_d(__VA_ARGS__) // 调试信息打印一般常开
#else
#define static_print_debug(...)
#endif
#else
#define static_print_info(...)
#define static_print_warn(...)
#define static_print_error(...)
#endif
#define MEDIA_A2DP_SNK_INTERFACE 1
osal_timer g_a2dp_stream_accept_timer = {nullptr, nullptr, 0, 0};
#define A2DP_STREAM_ACCEPT_TIMER_PERIOD 500
AudioFormatConfig g_audio_format_config = {AUDIO_DEFAULT, 0, 0};
static a2dp_src_callbacks_t g_a2dp_src_callbacks{};
static a2dp_snk_callbacks_t g_a2dp_snk_callbacks = {};
static void ACLConnectionSuss(const bd_addr_t &bdAddr) {}
static void ACLConnectionFail(const bd_addr_t &bdAddr) {}
static void A2dpSrcConnectstateChanged(bd_addr_t *bdAddr, int connState)
{
static_print_debug("a2dp_src_connectStateChangedCallback addr: %02x%02x%02x%02x%02x%02x connState: %x",
bdAddr->addr[5], bdAddr->addr[4], bdAddr->addr[3], /* 5 4 3 idx */
bdAddr->addr[2], bdAddr->addr[1], bdAddr->addr[0], connState); /* 2 1 0 idx */
if ((gap_get_device_class(bdAddr) & 0x200) != 0) {
static_print_debug("a2dp_src_connectstateChangedCb: Mobile Phone Device");
return;
}
if (connState == PROFILE_STATE_CONNECTED) {
uint32_t ret = avrcp_ct_connect(bdAddr);
static_print_info("avrcp_ct_connect ret = 0x%x", ret);
// TjdPhoneAudioManagerSetDeviceConnState(OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_CONNECTED);
GraphicService::GetInstance()->PostGraphicEvent(std::bind(ACLConnectionSuss, *bdAddr));
}
if (connState == PROFILE_STATE_DISCONNECTED) {
// TjdPhoneAudioManagerSetDeviceConnState(OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_DISCONNECTED);
GraphicService::GetInstance()->PostGraphicEvent(std::bind(ACLConnectionFail, *bdAddr));
/* 实验室测试耳机回连场景,用户根据需要调整策略 */
bool ret = gap_br_set_bt_scan_mode(GAP_SCAN_MODE_CONNECTABLE_GENERAL_DISCOVERABLE, 60); // start scan
if (!ret) {
static_print_error("a2dp disc: gap_br_set_bt_scan_mode ret = 0x%x", ret);
}
}
}
static void A2dpSrcConfigureChanged(bd_addr_t *bdAddr, a2dp_codec_info_t *info)
{
static_print_debug("A2dpSrcConfigurationChangedCallback addr: %02x%02x%02x%02x%02x%02x ", bdAddr->addr[5],
bdAddr->addr[4], bdAddr->addr[3], /* 5 4 3 idx */
bdAddr->addr[2], bdAddr->addr[1], bdAddr->addr[0]); /* 2 1 0 idx */
static_print_debug(
"codec_priority: %04x codec_type: %04x sample_rate: %02x bits_per_sample: %02x channel_mode: %02x ",
info->codec_priority, info->codec_type, info->sample_rate, info->bits_per_sample, info->channel_mode);
static_print_debug("codec_specific1: %04x codec_specific2: %04x codec_specific3: %04x codec_specific4: %04x",
info->codec_specific1, info->codec_specific2, info->codec_specific3, info->codec_specific4);
}
static void A2dpSrcPlayingStateChanged(bd_addr_t *bdAddr, int playState)
{
static_print_debug("A2dpSrcPlayingStateChangedCallback addr: %02x%02x%02x%02x%02x%02x playState: %x",
bdAddr->addr[5], bdAddr->addr[4], bdAddr->addr[3], /* 5 4 3 idx */
bdAddr->addr[2], bdAddr->addr[1], bdAddr->addr[0], playState); /* 2 1 0 idx */
}
static void BtA2dpSnkAcceptTimerStop(void)
{
static_print_info("stop timer");
if (g_a2dp_stream_accept_timer.timer != nullptr) {
(void)osal_timer_stop(&g_a2dp_stream_accept_timer);
(void)osal_timer_destroy(&g_a2dp_stream_accept_timer);
g_a2dp_stream_accept_timer.timer = nullptr;
}
static_print_info("stop timer success!");
}
static void BtA2dpSnStartAcceptHandler(unsigned long data)
{
UNUSED(data);
bd_addr_t active_bd_addr = a2dp_snk_get_active_device();
a2dp_snk_start_accept(&active_bd_addr);
BtA2dpSnkAcceptTimerStop();
}
static errcode_t BtA2dpSnkStartAcceptTimer(void)
{
static_print_info("start timer");
if (g_a2dp_stream_accept_timer.timer != nullptr) {
static_print_error("timer is running");
return ERRCODE_SUCC;
}
g_a2dp_stream_accept_timer.handler = BtA2dpSnStartAcceptHandler;
g_a2dp_stream_accept_timer.interval = A2DP_STREAM_ACCEPT_TIMER_PERIOD;
int32_t timer_ret = osal_timer_init(&g_a2dp_stream_accept_timer);
if (timer_ret != EOK) {
static_print_error("create timer error! ret: %x", timer_ret);
BtA2dpSnkAcceptTimerStop();
return ERRCODE_FAIL;
}
timer_ret = osal_timer_start(&g_a2dp_stream_accept_timer);
if (timer_ret != EOK) {
static_print_error("start timer error! ret: %x", timer_ret);
BtA2dpSnkAcceptTimerStop();
return ERRCODE_FAIL;
}
return ERRCODE_SUCC;
}
static int32_t BtA2dpSnkAudioCreate()
{
#if MEDIA_A2DP_SNK_INTERFACE
static_print_info("audioFormat %d channelCount %d sampleRate %d ", g_audio_format_config.audioFormat,
g_audio_format_config.channelCount, g_audio_format_config.sampleRate);
int32_t ret = AudioManagerA2dpSinkSetParam(g_audio_format_config);
static_print_info("AudioManagerA2dpSinkSetParam ret %x", ret);
ret = AudioManagerA2dpSinkCreate();
static_print_info("AudioManagerA2dpSinkCreate ret %x", ret);
#endif
/* 起定时器接受音乐开始请求 */
(void)BtA2dpSnkStartAcceptTimer();
return 0;
}
static int32_t BtA2dpSnkAudioDestroy()
{
#if MEDIA_A2DP_SNK_INTERFACE
int32_t ret = AudioManagerA2dpSinkDestroy();
static_print_info("AudioManagerA2dpSinkDestroy ret %x", ret);
#endif
PlayerInterruptListener::StopPlayer();
return 0;
}
static void A2dpSnkConnectStateChangedCb(bd_addr_t *bd_addr, int conn_state)
{
static_print_info("addr: ****%02x%02x%02x%02x conn_state: %x", bd_addr->addr[3], bd_addr->addr[2], bd_addr->addr[1],
bd_addr->addr[0], conn_state); /* 3 2 1 0 idx */
}
static void A2dpSnkStartStreamReqCb(bd_addr_t *bd_addr)
{
static_print_info("addr: ****%02x%02x%02x%02x ", bd_addr->addr[3], bd_addr->addr[2], bd_addr->addr[1],
bd_addr->addr[0]); /* 3 2 1 0 idx */
BtA2dpSnkAudioCreate();
}
static void A2dpSnkPlayingStateChangedCb(bd_addr_t *bd_addr, int playing_state)
{
static_print_info("addr: ****%02x%02x%02x%02x playing_state: %x", bd_addr->addr[3], bd_addr->addr[2],
bd_addr->addr[1], bd_addr->addr[0], playing_state); /* 3 2 1 0 idx */
if (playing_state == A2DP_NOT_PLAYING) {
BtA2dpSnkAudioDestroy();
}
}
static void A2dpSnkConfigChangedCb(bd_addr_t *bd_addr, a2dp_snk_codec_info_t *info)
{
static_print_info("addr: ****%02x%02x%02x%02x ", bd_addr->addr[3], bd_addr->addr[2], bd_addr->addr[1],
bd_addr->addr[0]); /* 3 2 1 0 idx */
static_print_info(
"codec_priority: %04x codec_type: %04x sample_rate: %02x bits_per_sample: %02x channel_mode: %02x",
info->codec_priority, info->codec_type, info->sample_rate, info->bits_per_sample, info->channel_mode);
static_print_info("codec_specific1: %04x codec_specific2: %04x codec_specific3: %04x codec_specific4: %04x",
(unsigned int)info->codec_specific1, (unsigned int)info->codec_specific2,
(unsigned int)info->codec_specific3, (unsigned int)info->codec_specific4);
#if MEDIA_A2DP_SNK_INTERFACE
if (info->codec_type == A2DP_SNK_CODEC_TYPE_AAC) {
g_audio_format_config.audioFormat = AAC_LC;
} else {
g_audio_format_config.audioFormat = SBC;
}
/* channel count 1 or 2 */
g_audio_format_config.channelCount = (info->channel_mode == A2DP_SNK_CODEC_CHANNEL_MODE_NONE ? 1 : 2);
switch (info->sample_rate) {
case A2DP_SNK_CODEC_SAMPLE_RATE_48000:
g_audio_format_config.sampleRate = BT_AUDIO_A2DP_SMAPLE_RATE48000;
break;
case A2DP_SNK_CODEC_SAMPLE_RATE_88200:
g_audio_format_config.sampleRate = BT_AUDIO_A2DP_SMAPLE_RATE88200;
break;
case A2DP_SNK_CODEC_SAMPLE_RATE_96000:
g_audio_format_config.sampleRate = BT_AUDIO_A2DP_SMAPLE_RATE96000;
break;
default:
g_audio_format_config.sampleRate = BT_AUDIO_A2DP_SMAPLE_RATE44100;
break;
}
static_print_info("audioFormat %d channelCount %d sampleRate %d ", g_audio_format_config.audioFormat,
g_audio_format_config.channelCount, g_audio_format_config.sampleRate);
#endif
}
void TjdUiAppPlayerModel::InitBtA2dpSourceEvent()
{
g_a2dp_src_callbacks.connectstate_changed_cb = A2dpSrcConnectstateChanged;
g_a2dp_src_callbacks.configuration_changed_cb = A2dpSrcConfigureChanged;
g_a2dp_src_callbacks.playing_state_changed_cb = A2dpSrcPlayingStateChanged;
a2dp_src_register_callbacks(&g_a2dp_src_callbacks);
}
void TjdUiAppPlayerModel::InitBtA2dpSinkEvent()
{
g_a2dp_snk_callbacks.connectstate_changed_cb = A2dpSnkConnectStateChangedCb;
g_a2dp_snk_callbacks.start_stream_request_cb = A2dpSnkStartStreamReqCb;
g_a2dp_snk_callbacks.playing_state_changed_cb = A2dpSnkPlayingStateChangedCb;
g_a2dp_snk_callbacks.configuration_changed_cb = A2dpSnkConfigChangedCb;
a2dp_snk_register_callbacks(&g_a2dp_snk_callbacks);
}
} // namespace TJD