diff --git a/system/btif/co/bta_av_co.cc b/system/btif/co/bta_av_co.cc index bcf155df253d4b73649f57d55d32fab5d80f8fa5..f68656584f83bee3cd246276d9237a4c11c537b6 100644 --- a/system/btif/co/bta_av_co.cc +++ b/system/btif/co/bta_av_co.cc @@ -35,6 +35,7 @@ #include "audio_hal_interface/a2dp_encoding.h" #include "bta/include/bta_av_api.h" #include "bta/include/bta_av_ci.h" +#include "btif/include/bta_av_co_peer.h" #include "btif/include/btif_a2dp_source.h" #include "btif/include/btif_av.h" #include "device/include/device_iot_config.h" @@ -52,15 +53,6 @@ #include "stack/include/bt_uuid16.h" #include "types/raw_address.h" -// Macro to retrieve the number of elements in a statically allocated array -#define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a) / sizeof((__a)[0])) - -// Macro to convert BTA AV audio handle to index and vice versa -#define BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle) \ - (((bta_av_handle) & (~BTA_AV_CHNL_MSK)) - 1) -#define BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(index) \ - (((index) + 1) | BTA_AV_CHNL_AUDIO) - using namespace bluetooth; // SCMS-T protect info @@ -68,28 +60,24 @@ const uint8_t bta_av_co_cp_scmst[AVDT_CP_INFO_LEN] = {0x02, 0x02, 0x00}; // Control block instance static const bool kContentProtectEnabled = false; -static BtaAvCo bta_av_co_cb(kContentProtectEnabled); +static BtaAvCo bta_av_co_cb(kContentProtectEnabled, new BtaAvCoPeerCache()); void BtaAvCo::Init( const std::vector<btav_a2dp_codec_config_t>& codec_priorities, std::vector<btav_a2dp_codec_info_t>* supported_codecs) { log::verbose(""); - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); // Reset the control block Reset(); - codec_priorities_ = codec_priorities; - - for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { - BtaAvCoPeer* p_peer = &peers_[i]; - p_peer->Init(codec_priorities); - } + peer_cache_->Init(codec_priorities, supported_codecs); // Gather the supported codecs from the first peer context; // all contexes should be identical. supported_codecs->clear(); - for (auto* codec_config : peers_[0].GetCodecs()->orderedSourceCodecs()) { + for (auto* codec_config : + peer_cache_->peers_[0].GetCodecs()->orderedSourceCodecs()) { auto& codec_info = supported_codecs->emplace_back(); codec_info.codec_type = codec_config->codecIndex(); codec_info.codec_id = codec_config->codecId(); @@ -98,7 +86,6 @@ void BtaAvCo::Init( } void BtaAvCo::Reset() { - codec_priorities_.clear(); active_peer_ = nullptr; content_protect_flag_ = 0; memset(codec_config_, 0, sizeof(codec_config_)); @@ -109,17 +96,13 @@ void BtaAvCo::Reset() { SetContentProtectFlag(AVDT_CP_SCMS_COPY_FREE); } - // Reset the peers and initialize the handles - for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { - BtaAvCoPeer* p_peer = &peers_[i]; - p_peer->Reset(BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(i)); - } + peer_cache_->Reset(); } bool BtaAvCo::IsSupportedCodec(btav_a2dp_codec_index_t codec_index) { // All peer state is initialized with the same local codec config, // hence we check only the first peer. - A2dpCodecs* codecs = peers_[0].GetCodecs(); + A2dpCodecs* codecs = peer_cache_->peers_[0].GetCodecs(); if (codecs == nullptr) { log::error("Peer codecs is set to null"); return false; @@ -128,7 +111,7 @@ bool BtaAvCo::IsSupportedCodec(btav_a2dp_codec_index_t codec_index) { } A2dpCodecConfig* BtaAvCo::GetActivePeerCurrentCodec() { - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); if (active_peer_ == nullptr || active_peer_->GetCodecs() == nullptr) { return nullptr; @@ -137,69 +120,15 @@ A2dpCodecConfig* BtaAvCo::GetActivePeerCurrentCodec() { } A2dpCodecConfig* BtaAvCo::GetPeerCurrentCodec(const RawAddress& peer_address) { - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); - BtaAvCoPeer* peer = FindPeer(peer_address); + BtaAvCoPeer* peer = peer_cache_->FindPeer(peer_address); if (peer == nullptr || peer->GetCodecs() == nullptr) { return nullptr; } return peer->GetCodecs()->getCurrentCodecConfig(); } -BtaAvCoPeer* BtaAvCo::FindPeer(const RawAddress& peer_address) { - for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { - BtaAvCoPeer* p_peer = &peers_[i]; - if (p_peer->addr == peer_address) { - return p_peer; - } - } - return nullptr; -} - -BtaAvCoPeer* BtaAvCo::FindPeer(tBTA_AV_HNDL bta_av_handle) { - uint8_t index; - - index = BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle); - - log::verbose("bta_av_handle = 0x{:x} index = {}", bta_av_handle, index); - - // Sanity check - if (index >= BTA_AV_CO_NUM_ELEMENTS(peers_)) { - log::error("peer index {} for BTA AV handle 0x{:x} is out of bounds", index, - bta_av_handle); - return nullptr; - } - - return &peers_[index]; -} - -BtaAvCoPeer* BtaAvCo::FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle, - const RawAddress& peer_address) { - log::verbose("peer {} bta_av_handle = 0x{:x}", - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); - - BtaAvCoPeer* p_peer = FindPeer(bta_av_handle); - if (p_peer == nullptr) { - log::error("peer entry for BTA AV handle 0x{:x} peer {} not found", - bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); - return nullptr; - } - - log::verbose("peer {} bta_av_handle = 0x{:x} previous address {}", - ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); - p_peer->addr = peer_address; - return p_peer; -} - -uint16_t BtaAvCo::FindPeerUuid(tBTA_AV_HNDL bta_av_handle) { - BtaAvCoPeer* p_peer = FindPeer(bta_av_handle); - if (p_peer == nullptr) { - return 0; - } - return p_peer->uuid_to_connect; -} - void BtaAvCo::ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, uint8_t num_seps, uint8_t num_sinks, @@ -210,7 +139,8 @@ void BtaAvCo::ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle, num_sinks, num_sources); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle 0x{:x} peer {}", bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -258,7 +188,8 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( log::verbose("codec: {}", A2DP_CodecInfoString(p_codec_info)); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle 0x{:x} peer {}", bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -317,8 +248,9 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( UpdateAllSelectableSourceCodecs(p_peer); if (p_peer->p_sink == nullptr) { // Update the selected codec - p_peer->p_sink = - FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_peer->codec_config)); + p_peer->p_sink = peer_cache_->FindPeerSink( + p_peer, A2DP_SourceCodecIndex(p_peer->codec_config), + ContentProtectFlag()); } p_sink = p_peer->p_sink; if (p_sink == nullptr) { @@ -329,7 +261,8 @@ tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( } else { if (btif_av_peer_prefers_mandatory_codec(p_peer->addr)) { // Apply user preferred codec directly before first codec selected. - p_sink = FindPeerSink(p_peer, BTAV_A2DP_CODEC_INDEX_SOURCE_SBC); + p_sink = peer_cache_->FindPeerSink( + p_peer, BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, ContentProtectFlag()); if (p_sink != nullptr) { log::verbose("mandatory codec preferred for peer {}", ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); @@ -399,7 +332,7 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, uint8_t* p_sep_info_idx, uint8_t seid, uint8_t* p_num_protect, uint8_t* p_protect_info) { - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); log::verbose("peer {} bta_av_handle:0x{:x} codec:{} seid:{}", ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, @@ -410,7 +343,8 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, log::verbose("codec: {}", A2DP_CodecInfoString(p_codec_info)); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle 0x{:x} peer {}", bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -459,8 +393,9 @@ tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, UpdateAllSelectableSinkCodecs(p_peer); if (p_peer->p_source == nullptr) { // Update the selected codec - p_peer->p_source = - FindPeerSource(p_peer, A2DP_SinkCodecIndex(p_peer->codec_config)); + p_peer->p_source = peer_cache_->FindPeerSource( + p_peer, A2DP_SinkCodecIndex(p_peer->codec_config), + ContentProtectFlag()); } p_source = p_peer->p_source; if (p_source == nullptr) { @@ -528,7 +463,8 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, log::verbose("codec: {}", A2DP_CodecInfoString(p_codec_info)); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle 0x{:x} peer {}", bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -551,8 +487,7 @@ void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, if (num_protect != 0) { if (ContentProtectEnabled()) { - if ((num_protect != 1) || - !BtaAvCo::ContentProtectIsScmst(p_protect_info)) { + if ((num_protect != 1) || !ContentProtectIsScmst(p_protect_info)) { log::error("wrong CP configuration for peer {}", ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); status = A2DP_BAD_CP_TYPE; @@ -633,7 +568,8 @@ void BtaAvCo::ProcessOpen(tBTA_AV_HNDL bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, mtu); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle 0x{:x} peer {}", bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -655,7 +591,8 @@ void BtaAvCo::ProcessClose(tBTA_AV_HNDL bta_av_handle, btif_av_reset_audio_delay(); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle 0x{:x} peer {}", bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -666,7 +603,7 @@ void BtaAvCo::ProcessClose(tBTA_AV_HNDL bta_av_handle, active_peer_ = nullptr; } // Mark the peer closed and clean the peer info - p_peer->Init(codec_priorities_); + p_peer->Init(peer_cache_->codec_priorities_); } void BtaAvCo::ProcessStart(tBTA_AV_HNDL bta_av_handle, @@ -676,7 +613,8 @@ void BtaAvCo::ProcessStart(tBTA_AV_HNDL bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle 0x{:x} peer {}", bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); @@ -762,7 +700,8 @@ void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle, ADDRESS_TO_LOGGABLE_STR(peer_address), loghex(bta_av_handle), mtu); // Find the peer - BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); + BtaAvCoPeer* p_peer = + peer_cache_->FindPeerAndUpdate(bta_av_handle, peer_address); if (p_peer == nullptr) { log::error("could not find peer entry for bta_av_handle {} peer {}", loghex(bta_av_handle), ADDRESS_TO_LOGGABLE_STR(peer_address)); @@ -774,7 +713,7 @@ void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle, bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) { log::info("peer_address={}", ADDRESS_TO_LOGGABLE_STR(peer_address)); - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); if (peer_address.IsEmpty()) { // Reset the active peer; @@ -784,7 +723,7 @@ bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) { } // Find the peer - BtaAvCoPeer* p_peer = FindPeer(peer_address); + BtaAvCoPeer* p_peer = peer_cache_->FindPeer(peer_address); if (p_peer == nullptr) { return false; } @@ -808,11 +747,11 @@ void BtaAvCo::GetPeerEncoderParameters( CHECK(p_peer_params != nullptr) << "Peer address " << ADDRESS_TO_LOGGABLE_STR(peer_address); - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); // Compute the MTU - for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { - const BtaAvCoPeer* p_peer = &peers_[i]; + for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peer_cache_->peers_); i++) { + const BtaAvCoPeer* p_peer = &peer_cache_->peers_[i]; if (!p_peer->opened) continue; if (p_peer->addr != peer_address) continue; if (p_peer->mtu < min_mtu) min_mtu = p_peer->mtu; @@ -829,7 +768,7 @@ void BtaAvCo::GetPeerEncoderParameters( } const tA2DP_ENCODER_INTERFACE* BtaAvCo::GetSourceEncoderInterface() { - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); return A2DP_GetEncoderInterface(codec_config_); } @@ -850,7 +789,7 @@ bool BtaAvCo::SetCodecUserConfig( *p_restart_output = false; - BtaAvCoPeer* p_peer = FindPeer(peer_address); + BtaAvCoPeer* p_peer = peer_cache_->FindPeer(peer_address); if (p_peer == nullptr) { log::error("cannot find peer {} to configure", ADDRESS_TO_LOGGABLE_STR(peer_address)); @@ -869,7 +808,8 @@ bool BtaAvCo::SetCodecUserConfig( // Find the peer SEP codec to use if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) { - p_sink = FindPeerSink(p_peer, codec_user_config.codec_type); + p_sink = peer_cache_->FindPeerSink(p_peer, codec_user_config.codec_type, + ContentProtectFlag()); } else { // Use the current sink codec p_sink = p_peer->p_sink; @@ -994,7 +934,7 @@ bool BtaAvCo::SetCodecAudioConfig( } int BtaAvCo::GetSourceEncoderEffectiveFrameSize() { - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); return A2DP_GetEecoderEffectiveFrameSize(codec_config_); } @@ -1044,7 +984,7 @@ bool BtaAvCo::ReportSinkCodecState(BtaAvCoPeer* p_peer) { } void BtaAvCo::DebugDump(int fd) { - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); // // Active peer codec-specific stats @@ -1062,8 +1002,8 @@ void BtaAvCo::DebugDump(int fd) { ? ADDRESS_TO_LOGGABLE_CSTR(active_peer_->addr) : "null"); - for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { - const BtaAvCoPeer& peer = peers_[i]; + for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peer_cache_->peers_); i++) { + const BtaAvCoPeer& peer = peer_cache_->peers_[i]; if (peer.addr.IsEmpty()) { continue; } @@ -1085,46 +1025,6 @@ void BtaAvCo::DebugDump(int fd) { } } -bool BtaAvCo::ContentProtectIsScmst(const uint8_t* p_protect_info) { - log::verbose(""); - - if (*p_protect_info >= AVDT_CP_LOSC) { - uint16_t cp_id; - p_protect_info++; - STREAM_TO_UINT16(cp_id, p_protect_info); - if (cp_id == AVDT_CP_SCMS_T_ID) { - log::verbose("SCMS-T found"); - return true; - } - } - return false; -} - -bool BtaAvCo::AudioProtectHasScmst(uint8_t num_protect, - const uint8_t* p_protect_info) { - log::verbose(""); - while (num_protect--) { - if (BtaAvCo::ContentProtectIsScmst(p_protect_info)) return true; - // Move to the next Content Protect schema - p_protect_info += *p_protect_info + 1; - } - log::verbose("SCMS-T not found"); - return false; -} - -bool BtaAvCo::AudioSepHasContentProtection(const BtaAvCoSep* p_sep) { - log::verbose(""); - - // Check if content protection is enabled for this stream - if (ContentProtectFlag() != AVDT_CP_SCMS_COPY_FREE) { - return BtaAvCo::AudioProtectHasScmst(p_sep->num_protect, - p_sep->protect_info); - } - - log::verbose("not required"); - return true; -} - std::optional<::bluetooth::audio::a2dp::provider::a2dp_configuration> BtaAvCo::GetProviderCodecConfiguration(BtaAvCoPeer* p_peer) { // Gather peer codec capabilities. @@ -1158,8 +1058,9 @@ BtaAvCoSep* BtaAvCo::SelectProviderCodecConfiguration( log::info("Configuration={}", provider_codec_config.toString()); // Identify the selected sink. - auto* p_sink = - FindPeerSink(p_peer, provider_codec_config.codec_parameters.codec_type); + auto* p_sink = peer_cache_->FindPeerSink( + p_peer, provider_codec_config.codec_parameters.codec_type, + ContentProtectFlag()); ASSERT_LOG(p_sink != nullptr, "Unable to find the selected codec config"); // Identify the selected codec. @@ -1203,7 +1104,8 @@ const BtaAvCoSep* BtaAvCo::SelectSourceCodec(BtaAvCoPeer* p_peer) { // Find the peer Sink for the codec uint8_t new_codec_config[AVDT_CODEC_SIZE]; - const BtaAvCoSep* p_sink = FindPeerSink(p_peer, iter->codecIndex()); + const BtaAvCoSep* p_sink = peer_cache_->FindPeerSink( + p_peer, iter->codecIndex(), ContentProtectFlag()); if (p_sink == nullptr) { log::verbose("peer Sink for codec {} not found", iter->name()); @@ -1264,59 +1166,6 @@ const BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) { return p_source; } -BtaAvCoSep* BtaAvCo::FindPeerSink(BtaAvCoPeer* p_peer, - btav_a2dp_codec_index_t codec_index) { - if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { - log::warn("invalid codec index for peer {}", - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); - return nullptr; - } - - // Find the peer Sink for the codec - for (size_t index = 0; index < p_peer->num_sup_sinks; index++) { - BtaAvCoSep* p_sink = &p_peer->sinks[index]; - btav_a2dp_codec_index_t peer_codec_index = - A2DP_SourceCodecIndex(p_sink->codec_caps); - if (peer_codec_index != codec_index) { - continue; - } - if (!AudioSepHasContentProtection(p_sink)) { - log::verbose("peer Sink for codec {} does not support Content Protection", - A2DP_CodecIndexStr(codec_index)); - continue; - } - return p_sink; - } - return nullptr; -} - -BtaAvCoSep* BtaAvCo::FindPeerSource(BtaAvCoPeer* p_peer, - btav_a2dp_codec_index_t codec_index) { - if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { - log::warn("invalid codec index for peer {}", - ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); - return nullptr; - } - - // Find the peer Source for the codec - for (size_t index = 0; index < p_peer->num_sup_sources; index++) { - BtaAvCoSep* p_source = &p_peer->sources[index]; - btav_a2dp_codec_index_t peer_codec_index = - A2DP_SinkCodecIndex(p_source->codec_caps); - if (peer_codec_index != codec_index) { - continue; - } - if (!AudioSepHasContentProtection(p_source)) { - log::verbose( - "peer Source for codec {} does not support Content Protection", - A2DP_CodecIndexStr(codec_index)); - continue; - } - return p_source; - } - return nullptr; -} - const BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection( const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) { uint8_t new_codec_config[AVDT_CODEC_SIZE]; @@ -1324,7 +1173,8 @@ const BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection( log::verbose(""); // Find the peer Sink for the codec - BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex()); + BtaAvCoSep* p_sink = peer_cache_->FindPeerSink( + p_peer, codec_config.codecIndex(), ContentProtectFlag()); if (p_sink == nullptr) { log::verbose("peer Sink for codec {} not found", codec_config.name()); return nullptr; @@ -1350,7 +1200,8 @@ const BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection( log::verbose(""); // Find the peer Source for the codec - BtaAvCoSep* p_source = FindPeerSource(p_peer, codec_config.codecIndex()); + BtaAvCoSep* p_source = peer_cache_->FindPeerSource( + p_peer, codec_config.codecIndex(), ContentProtectFlag()); if (p_source == nullptr) { log::verbose("peer Source for codec {} not found", codec_config.name()); return nullptr; @@ -1387,7 +1238,8 @@ bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config, log::verbose("peer {}", ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); // Find the peer Sink for the codec - const BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex()); + const BtaAvCoSep* p_sink = peer_cache_->FindPeerSink( + p_peer, codec_config.codecIndex(), ContentProtectFlag()); if (p_sink == nullptr) { // The peer Sink device does not support this codec return false; @@ -1419,8 +1271,8 @@ bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config, log::verbose("peer {}", ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); // Find the peer Source for the codec - const BtaAvCoSep* p_source = - FindPeerSource(p_peer, codec_config.codecIndex()); + const BtaAvCoSep* p_source = peer_cache_->FindPeerSource( + p_peer, codec_config.codecIndex(), ContentProtectFlag()); if (p_source == nullptr) { // The peer Source device does not support this codec return false; @@ -1442,14 +1294,14 @@ void BtaAvCo::SaveNewCodecConfig(BtaAvCoPeer* p_peer, log::verbose("peer {}", ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); log::verbose("codec: {}", A2DP_CodecInfoString(new_codec_config)); - std::lock_guard<std::recursive_mutex> lock(codec_lock_); + std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_); memcpy(codec_config_, new_codec_config, sizeof(codec_config_)); memcpy(p_peer->codec_config, new_codec_config, AVDT_CODEC_SIZE); if (ContentProtectEnabled()) { // Check if this Sink supports SCMS - bool cp_active = BtaAvCo::AudioProtectHasScmst(num_protect, p_protect_info); + bool cp_active = AudioProtectHasScmst(num_protect, p_protect_info); p_peer->SetContentProtectActive(cp_active); } } @@ -1470,8 +1322,8 @@ bool BtaAvCo::SetCodecOtaConfig(BtaAvCoPeer* p_peer, *p_restart_output = false; // Find the peer SEP codec to use - const BtaAvCoSep* p_sink = - FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_ota_codec_config)); + const BtaAvCoSep* p_sink = peer_cache_->FindPeerSink( + p_peer, A2DP_SourceCodecIndex(p_ota_codec_config), ContentProtectFlag()); if ((p_peer->num_sup_sinks > 0) && (p_sink == nullptr)) { // There are no peer SEPs if we didn't do the discovery procedure yet. // We have all the information we need from the peer, so we can @@ -1613,7 +1465,7 @@ tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL bta_av_handle, uint8_t* p_sep_info_idx, uint8_t seid, uint8_t* p_num_protect, uint8_t* p_protect_info) { - uint16_t peer_uuid = bta_av_co_cb.FindPeerUuid(bta_av_handle); + uint16_t peer_uuid = bta_av_co_cb.peer_cache_->FindPeerUuid(bta_av_handle); log::verbose("peer {} bta_av_handle=0x{:x} peer_uuid=0x{:x}", ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, @@ -1724,7 +1576,7 @@ int bta_av_co_get_encoder_effective_frame_size() { btav_a2dp_scmst_info_t bta_av_co_get_scmst_info( const RawAddress& peer_address) { - BtaAvCoPeer* p_peer = bta_av_co_cb.FindPeer(peer_address); + BtaAvCoPeer* p_peer = bta_av_co_cb.peer_cache_->FindPeer(peer_address); CHECK(p_peer != nullptr); btav_a2dp_scmst_info_t scmst_info{}; scmst_info.enable_status = BTAV_A2DP_SCMST_DISABLED; diff --git a/system/btif/co/bta_av_co_peer.cc b/system/btif/co/bta_av_co_peer.cc index 76e1b41e9d3dca4ff717ac716095a92d64ea244b..3cfbb3b1489adb09bf1d93bbb77df25282c79383 100644 --- a/system/btif/co/bta_av_co_peer.cc +++ b/system/btif/co/bta_av_co_peer.cc @@ -15,11 +15,13 @@ */ #include "btif/include/bta_av_co_peer.h" -#include <base/logging.h> +#include <bluetooth/log.h> #include "bta/include/bta_av_api.h" #include "include/check.h" +using namespace bluetooth; + // Macro to convert BTA AV audio handle to index and vice versa #define BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle) \ (((bta_av_handle) & (~BTA_AV_CHNL_MSK)) - 1) @@ -89,3 +91,174 @@ void BtaAvCoPeer::Reset(tBTA_AV_HNDL bta_av_handle) { codecs_ = nullptr; content_protect_active_ = false; } + +void BtaAvCoPeerCache::Init( + const std::vector<btav_a2dp_codec_config_t>& codec_priorities, + std::vector<btav_a2dp_codec_info_t>* supported_codecs) { + std::lock_guard<std::recursive_mutex> lock(codec_lock_); + + codec_priorities_ = codec_priorities; + + for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { + BtaAvCoPeer* p_peer = &peers_[i]; + p_peer->Init(codec_priorities); + } +} + +void BtaAvCoPeerCache::Reset() { + codec_priorities_.clear(); + + // Reset the peers and initialize the handles + for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { + BtaAvCoPeer* p_peer = &peers_[i]; + p_peer->Reset(BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(i)); + } +} + +BtaAvCoPeer* BtaAvCoPeerCache::FindPeer(const RawAddress& peer_address) { + for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { + BtaAvCoPeer* p_peer = &peers_[i]; + if (p_peer->addr == peer_address) { + return p_peer; + } + } + return nullptr; +} + +BtaAvCoSep* BtaAvCoPeerCache::FindPeerSource( + BtaAvCoPeer* p_peer, btav_a2dp_codec_index_t codec_index, + const uint8_t content_protect_flag) { + if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { + log::warn("invalid codec index for peer {}", + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + return nullptr; + } + + // Find the peer Source for the codec + for (size_t index = 0; index < p_peer->num_sup_sources; index++) { + BtaAvCoSep* p_source = &p_peer->sources[index]; + btav_a2dp_codec_index_t peer_codec_index = + A2DP_SinkCodecIndex(p_source->codec_caps); + if (peer_codec_index != codec_index) { + continue; + } + if (!AudioSepHasContentProtection(p_source, content_protect_flag)) { + log::verbose( + "peer Source for codec {} does not support Content Protection", + A2DP_CodecIndexStr(codec_index)); + continue; + } + return p_source; + } + return nullptr; +} + +BtaAvCoSep* BtaAvCoPeerCache::FindPeerSink(BtaAvCoPeer* p_peer, + btav_a2dp_codec_index_t codec_index, + const uint8_t content_protect_flag) { + if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { + log::warn("invalid codec index for peer {}", + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + return nullptr; + } + + // Find the peer Sink for the codec + for (size_t index = 0; index < p_peer->num_sup_sinks; index++) { + BtaAvCoSep* p_sink = &p_peer->sinks[index]; + btav_a2dp_codec_index_t peer_codec_index = + A2DP_SourceCodecIndex(p_sink->codec_caps); + if (peer_codec_index != codec_index) { + continue; + } + if (!AudioSepHasContentProtection(p_sink, content_protect_flag)) { + log::warn("invalid codec index for peer {}", + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + continue; + } + return p_sink; + } + return nullptr; +} + +BtaAvCoPeer* BtaAvCoPeerCache::FindPeer(tBTA_AV_HNDL bta_av_handle) { + uint8_t index; + + index = BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle); + + log::verbose("bta_av_handle = 0x{:x} index = {}", bta_av_handle, index); + + // Sanity check + if (index >= BTA_AV_CO_NUM_ELEMENTS(peers_)) { + log::error("peer index {} for BTA AV handle 0x{:x} is out of bounds", index, + bta_av_handle); + return nullptr; + } + + return &peers_[index]; +} + +BtaAvCoPeer* BtaAvCoPeerCache::FindPeerAndUpdate( + tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address) { + log::verbose("peer {} bta_av_handle = 0x{:x}", + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle); + + BtaAvCoPeer* p_peer = FindPeer(bta_av_handle); + if (p_peer == nullptr) { + log::error("peer entry for BTA AV handle 0x{:x} peer {} not found", + bta_av_handle, ADDRESS_TO_LOGGABLE_CSTR(peer_address)); + return nullptr; + } + + log::verbose("peer {} bta_av_handle = 0x{:x} previous address {}", + ADDRESS_TO_LOGGABLE_CSTR(peer_address), bta_av_handle, + ADDRESS_TO_LOGGABLE_CSTR(p_peer->addr)); + p_peer->addr = peer_address; + return p_peer; +} + +uint16_t BtaAvCoPeerCache::FindPeerUuid(tBTA_AV_HNDL bta_av_handle) { + BtaAvCoPeer* p_peer = FindPeer(bta_av_handle); + if (p_peer == nullptr) { + return 0; + } + return p_peer->uuid_to_connect; +} + +bool ContentProtectIsScmst(const uint8_t* p_protect_info) { + log::verbose(""); + + if (*p_protect_info >= AVDT_CP_LOSC) { + uint16_t cp_id; + p_protect_info++; + STREAM_TO_UINT16(cp_id, p_protect_info); + if (cp_id == AVDT_CP_SCMS_T_ID) { + log::verbose("SCMS-T found"); + return true; + } + } + return false; +} + +bool AudioProtectHasScmst(uint8_t num_protect, const uint8_t* p_protect_info) { + log::verbose(""); + while (num_protect--) { + if (ContentProtectIsScmst(p_protect_info)) return true; + // Move to the next Content Protect schema + p_protect_info += *p_protect_info + 1; + } + log::verbose("SCMS-T not found"); + return false; +} + +bool AudioSepHasContentProtection(const BtaAvCoSep* p_sep, + const uint8_t content_protect_flag) { + log::verbose(""); + + // Check if content protection is enabled for this stream + if (content_protect_flag != AVDT_CP_SCMS_COPY_FREE) { + return AudioProtectHasScmst(p_sep->num_protect, p_sep->protect_info); + } + + log::verbose("not required"); + return true; +} diff --git a/system/btif/include/bta_av_co.h b/system/btif/include/bta_av_co.h index e266767fd2f6ab0a5517494e94757776b7fd3bc7..7571bc12e3561da88d5a1f8c5b4fae6545e18206 100644 --- a/system/btif/include/bta_av_co.h +++ b/system/btif/include/bta_av_co.h @@ -22,14 +22,17 @@ class BtaAvCo { public: - BtaAvCo(bool content_protect_enabled) - : active_peer_(nullptr), + BtaAvCo(bool content_protect_enabled, BtaAvCoPeerCache* bta_av_co_peer_bank) + : peer_cache_(bta_av_co_peer_bank), + active_peer_(nullptr), codec_config_{}, content_protect_enabled_(content_protect_enabled), content_protect_flag_(0) { Reset(); } + virtual ~BtaAvCo() = default; + /** * Initialize the state. * @@ -62,14 +65,6 @@ class BtaAvCo { */ A2dpCodecConfig* GetPeerCurrentCodec(const RawAddress& peer_address); - /** - * Find the peer UUID for a given BTA AV handle. - * - * @param bta_av_handle the BTA AV handle to use - * @return the peer UUID if found, otherwise 0 - */ - uint16_t FindPeerUuid(tBTA_AV_HNDL bta_av_handle); - /** * Process the AVDTP discovery result: number of Stream End Points (SEP) * found during the AVDTP stream discovery process. @@ -152,7 +147,7 @@ class BtaAvCo { * @param seid stream endpoint ID of stream initiating the operation * @param peer_address the peer address * @param num_protect the peer SEP number of content protection elements - * @param p_protect_info the peer SEP conntent protection info + * @param p_protect_info the peer SEP content protection info * @param t_local_sep the local SEP: AVDT_TSEP_SRC or AVDT_TSEP_SNK * @param avdt_handle the AVDTP handle */ @@ -351,32 +346,9 @@ class BtaAvCo { void DebugDump(int fd); /** - * Find the peer entry for a given peer address. - * - * @param peer_address the peer address to use - * @return the peer entry if found, otherwise nullptr + * Access peer data via cache. */ - BtaAvCoPeer* FindPeer(const RawAddress& peer_address); - - /** - * Find the peer Sink SEP entry for a given codec index. - * - * @param p_peer the peer to use - * @param codec_index the codec index to use - * @return the peer Sink SEP for the codec index if found, otherwise nullptr - */ - BtaAvCoSep* FindPeerSink(BtaAvCoPeer* p_peer, - btav_a2dp_codec_index_t codec_index); - - /** - * Find the peer Source SEP entry for a given codec index. - * - * @param p_peer the peer to use - * @param codec_config the codec index to use - * @return the peer Source SEP for the codec index if found, otherwise nullptr - */ - BtaAvCoSep* FindPeerSource(BtaAvCoPeer* p_peer, - btav_a2dp_codec_index_t codec_index); + BtaAvCoPeerCache* peer_cache_; private: /** @@ -384,25 +356,6 @@ class BtaAvCo { */ void Reset(); - /** - * Find the peer entry for a given BTA AV handle. - * - * @param bta_av_handle the BTA AV handle to use - * @return the peer entry if found, otherwise nullptr - */ - BtaAvCoPeer* FindPeer(tBTA_AV_HNDL bta_av_handle); - - /** - * Find the peer entry for a given BTA AV handle and update it with the - * peer address. - * - * @param bta_av_handle the BTA AV handle to use - * @param peer_address the peer address - * @return the peer entry if found, otherwise nullptr - */ - BtaAvCoPeer* FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle, - const RawAddress& peer_address); - /** * Select the Source codec configuration based on peer codec support. * @@ -540,39 +493,9 @@ class BtaAvCo { const ::bluetooth::audio::a2dp::provider::a2dp_configuration& provider_codec_config); - /** - * Check if a peer SEP has content protection enabled. - * - * @param p_sep the peer SEP to check - * @return true if the peer SEP has content protection enabled, - * otherwise false - */ - bool AudioSepHasContentProtection(const BtaAvCoSep* p_sep); - - /** - * Check if a content protection service is SCMS-T. - * - * @param p_orotect_info the content protection info to check - * @return true if the Contention Protection in @param p_protect_info - * is SCMS-T, otherwise false - */ - static bool ContentProtectIsScmst(const uint8_t* p_protect_info); - - /** - * Check if audio protect info contains SCMS-T Content Protection. - * - * @param num_protect number of protect schemes - * @param p_protect_info the protect info to check - * @return true if @param p_protect_info contains SCMS-T, otherwise false - */ - static bool AudioProtectHasScmst(uint8_t num_protect, - const uint8_t* p_protect_info); - bool ContentProtectEnabled() const { return content_protect_enabled_; } - std::recursive_mutex codec_lock_; // Protect access to the codec state - std::vector<btav_a2dp_codec_config_t> codec_priorities_; // Configured - BtaAvCoPeer peers_[BTA_AV_NUM_STRS]; // Connected peer information + // TODO: Remove active peer once no longer needed. BtaAvCoPeer* active_peer_; // The current active peer uint8_t codec_config_[AVDT_CODEC_SIZE]; // Current codec configuration const bool content_protect_enabled_; // True if Content Protect is enabled diff --git a/system/btif/include/bta_av_co_peer.h b/system/btif/include/bta_av_co_peer.h index 4b269c07edc049392837af1a770c27afdd19610f..7703c3033b4f32f41e08769f7380d195063fc136 100644 --- a/system/btif/include/bta_av_co_peer.h +++ b/system/btif/include/bta_av_co_peer.h @@ -50,6 +50,9 @@ class BtaAvCoSep { class BtaAvCoPeer { public: + /** + * Default constructor to initialize the state of the member variables. + */ BtaAvCoPeer(); /** @@ -78,7 +81,7 @@ class BtaAvCoPeer { * * @return the A2DP codecs */ - A2dpCodecs* GetCodecs() { return codecs_; } + A2dpCodecs* GetCodecs() const { return codecs_; } bool ContentProtectActive() const { return content_protect_active_; } void SetContentProtectActive(bool cp_active) { @@ -109,3 +112,115 @@ class BtaAvCoPeer { A2dpCodecs* codecs_; // Locally supported codecs bool content_protect_active_; // True if Content Protect is active }; + +/** + * Cache to store all the peer and codec information. + * It provides different APIs to retrieve the peer and update the peer data. + */ +class BtaAvCoPeerCache { + public: + BtaAvCoPeerCache() = default; + std::recursive_mutex codec_lock_; // Protect access to the codec state + std::vector<btav_a2dp_codec_config_t> codec_priorities_; // Configured + BtaAvCoPeer peers_[BTA_AV_NUM_STRS]; // Connected peer information + + /** + * Inits the cache with the appropriate data. + * @param codec_priorities codec priorities. + * @param supported_codecs supported codecs by the stack. + */ + void Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities, + std::vector<btav_a2dp_codec_info_t>* supported_codecs); + + /** + * Resets the cache and the peer data. + */ + void Reset(); + + /** + * Find the peer entry for a given peer address. + * + * @param peer_address the peer address to use + * @return the peer entry if found, otherwise nullptr + */ + BtaAvCoPeer* FindPeer(const RawAddress& peer_address); + + /** + * Find the peer Source SEP entry for a given codec index. + * + * @param p_peer the peer to use + * @param codec_config the codec index to use + * @return the peer Source SEP for the codec index if found, otherwise nullptr + */ + BtaAvCoSep* FindPeerSource(BtaAvCoPeer* p_peer, + btav_a2dp_codec_index_t codec_index, + const uint8_t content_protect_flag); + + /** + * Find the peer Sink SEP entry for a given codec index. + * + * @param p_peer the peer to use + * @param codec_index the codec index to use + * @return the peer Sink SEP for the codec index if found, otherwise nullptr + */ + BtaAvCoSep* FindPeerSink(BtaAvCoPeer* p_peer, + btav_a2dp_codec_index_t codec_index, + const uint8_t content_protect_flag); + + /** + * Find the peer entry for a given BTA AV handle. + * + * @param bta_av_handle the BTA AV handle to use + * @return the peer entry if found, otherwise nullptr + */ + BtaAvCoPeer* FindPeer(tBTA_AV_HNDL bta_av_handle); + + /** + * Find the peer entry for a given BTA AV handle and update it with the + * peer address. + * + * @param bta_av_handle the BTA AV handle to use + * @param peer_address the peer address + * @return the peer entry if found, otherwise nullptr + */ + BtaAvCoPeer* FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle, + const RawAddress& peer_address); + + /** + * Find the peer UUID for a given BTA AV handle. + * + * @param bta_av_handle the BTA AV handle to use + * @return the peer UUID if found, otherwise 0 + */ + uint16_t FindPeerUuid(tBTA_AV_HNDL bta_av_handle); +}; + +/** + * Check if a content protection service is SCMS-T. + * + * @param p_orotect_info the content protection info to check + * @return true if the Contention Protection in @param p_protect_info + * is SCMS-T, otherwise false + */ +bool ContentProtectIsScmst(const uint8_t* p_protect_info); + +/** + * Check if audio protect info contains SCMS-T Content Protection. + * + * @param num_protect number of protect schemes + * @param p_protect_info the protect info to check + * @return true if @param p_protect_info contains SCMS-T, otherwise false + */ +bool AudioProtectHasScmst(uint8_t num_protect, const uint8_t* p_protect_info); + +/** + * Check if a peer SEP has content protection enabled. + * + * @param p_sep the peer SEP to check + * @param content_protect_flag flag to check if content protect is enabled or + * not. + * @return true if the peer SEP has content protection enabled, + * otherwise false + */ +bool AudioSepHasContentProtection(const BtaAvCoSep* p_sep, + const uint8_t content_protect_flag); diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index 4b5fdd513f12207786aeade3a63c8efc05a3568e..2ce600ef145d2c4e9d82f87b26beb7962196c87d 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -20,6 +20,7 @@ #include "btif/include/btif_av.h" +#include <android_bluetooth_flags.h> #include <android_bluetooth_sysprop.h> #include <base/functional/bind.h> #include <base/logging.h>