/*---------------------------------------------------------------------------- * 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