245 lines
10 KiB
C++
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
|