1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "bluetooth-a2dp"
18 
19 #include "btif/include/bta_av_co_peer.h"
20 
21 #include <bluetooth/log.h>
22 
23 #include "bta/include/bta_av_api.h"
24 
25 using namespace bluetooth;
26 
27 // Macro to convert BTA AV audio handle to index and vice versa
28 #define BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle) \
29   (((bta_av_handle) & (~BTA_AV_CHNL_MSK)) - 1)
30 #define BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(index) \
31   (((index) + 1) | BTA_AV_CHNL_AUDIO)
32 
BtaAvCoPeer()33 BtaAvCoPeer::BtaAvCoPeer()
34     : addr(RawAddress::kEmpty),
35       num_sinks(0),
36       num_sources(0),
37       num_seps(0),
38       num_rx_sinks(0),
39       num_rx_sources(0),
40       num_sup_sinks(0),
41       num_sup_sources(0),
42       p_sink(nullptr),
43       p_source(nullptr),
44       codec_config{},
45       acceptor(false),
46       reconfig_needed(false),
47       opened(false),
48       mtu(0),
49       uuid_to_connect(0),
50       bta_av_handle_(0),
51       codecs_(nullptr),
52       content_protect_active_(false) {
53   Reset(0);
54 }
55 
Init(const std::vector<btav_a2dp_codec_config_t> & codec_priorities)56 void BtaAvCoPeer::Init(
57     const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
58   Reset(bta_av_handle_);
59   // Reset the current config
60   codecs_ = new A2dpCodecs(codec_priorities);
61   codecs_->init();
62   A2DP_InitDefaultCodec(codec_config);
63 }
64 
Reset(tBTA_AV_HNDL bta_av_handle)65 void BtaAvCoPeer::Reset(tBTA_AV_HNDL bta_av_handle) {
66   addr = RawAddress::kEmpty;
67   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sinks); i++) {
68     BtaAvCoSep& sink = sinks[i];
69     sink.Reset();
70   }
71   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sources); i++) {
72     BtaAvCoSep& source = sources[i];
73     source.Reset();
74   }
75   num_sinks = 0;
76   num_sources = 0;
77   num_seps = 0;
78   num_rx_sinks = 0;
79   num_rx_sources = 0;
80   num_sup_sinks = 0;
81   num_sup_sources = 0;
82   p_sink = nullptr;
83   p_source = nullptr;
84   memset(codec_config, 0, sizeof(codec_config));
85   acceptor = false;
86   reconfig_needed = false;
87   opened = false;
88   mtu = 0;
89   uuid_to_connect = 0;
90 
91   bta_av_handle_ = bta_av_handle;
92   delete codecs_;
93   codecs_ = nullptr;
94   content_protect_active_ = false;
95 }
96 
Init(const std::vector<btav_a2dp_codec_config_t> & codec_priorities,std::vector<btav_a2dp_codec_info_t> * supported_codecs)97 void BtaAvCoPeerCache::Init(
98     const std::vector<btav_a2dp_codec_config_t>& codec_priorities,
99     std::vector<btav_a2dp_codec_info_t>* supported_codecs) {
100   std::lock_guard<std::recursive_mutex> lock(codec_lock_);
101 
102   codec_priorities_ = codec_priorities;
103 
104   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
105     BtaAvCoPeer* p_peer = &peers_[i];
106     p_peer->Init(codec_priorities);
107   }
108 }
109 
Reset()110 void BtaAvCoPeerCache::Reset() {
111   codec_priorities_.clear();
112 
113   // Reset the peers and initialize the handles
114   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
115     BtaAvCoPeer* p_peer = &peers_[i];
116     p_peer->Reset(BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(i));
117   }
118 }
119 
FindPeer(const RawAddress & peer_address)120 BtaAvCoPeer* BtaAvCoPeerCache::FindPeer(const RawAddress& peer_address) {
121   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
122     BtaAvCoPeer* p_peer = &peers_[i];
123     if (p_peer->addr == peer_address) {
124       return p_peer;
125     }
126   }
127   return nullptr;
128 }
129 
FindPeerSource(BtaAvCoPeer * p_peer,btav_a2dp_codec_index_t codec_index,const uint8_t content_protect_flag)130 BtaAvCoSep* BtaAvCoPeerCache::FindPeerSource(
131     BtaAvCoPeer* p_peer, btav_a2dp_codec_index_t codec_index,
132     const uint8_t content_protect_flag) {
133   if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
134     log::warn("invalid codec index for peer {}", p_peer->addr);
135     return nullptr;
136   }
137 
138   // Find the peer Source for the codec
139   for (size_t index = 0; index < p_peer->num_sup_sources; index++) {
140     BtaAvCoSep* p_source = &p_peer->sources[index];
141     btav_a2dp_codec_index_t peer_codec_index =
142         A2DP_SinkCodecIndex(p_source->codec_caps);
143     if (peer_codec_index != codec_index) {
144       continue;
145     }
146     if (!AudioSepHasContentProtection(p_source, content_protect_flag)) {
147       log::verbose(
148           "peer Source for codec {} does not support Content Protection",
149           A2DP_CodecIndexStr(codec_index));
150       continue;
151     }
152     return p_source;
153   }
154   return nullptr;
155 }
156 
FindPeerSink(BtaAvCoPeer * p_peer,btav_a2dp_codec_index_t codec_index,const uint8_t content_protect_flag)157 BtaAvCoSep* BtaAvCoPeerCache::FindPeerSink(BtaAvCoPeer* p_peer,
158                                            btav_a2dp_codec_index_t codec_index,
159                                            const uint8_t content_protect_flag) {
160   if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
161     log::warn("invalid codec index for peer {}", p_peer->addr);
162     return nullptr;
163   }
164 
165   // Find the peer Sink for the codec
166   for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
167     BtaAvCoSep* p_sink = &p_peer->sinks[index];
168     btav_a2dp_codec_index_t peer_codec_index =
169         A2DP_SourceCodecIndex(p_sink->codec_caps);
170     if (peer_codec_index != codec_index) {
171       continue;
172     }
173     if (!AudioSepHasContentProtection(p_sink, content_protect_flag)) {
174       log::warn("invalid codec index for peer {}", p_peer->addr);
175       continue;
176     }
177     return p_sink;
178   }
179   return nullptr;
180 }
181 
FindPeer(tBTA_AV_HNDL bta_av_handle)182 BtaAvCoPeer* BtaAvCoPeerCache::FindPeer(tBTA_AV_HNDL bta_av_handle) {
183   uint8_t index;
184 
185   index = BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle);
186 
187   log::verbose("bta_av_handle = 0x{:x} index = {}", bta_av_handle, index);
188 
189   // Sanity check
190   if (index >= BTA_AV_CO_NUM_ELEMENTS(peers_)) {
191     log::error("peer index {} for BTA AV handle 0x{:x} is out of bounds", index,
192                bta_av_handle);
193     return nullptr;
194   }
195 
196   return &peers_[index];
197 }
198 
FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle,const RawAddress & peer_address)199 BtaAvCoPeer* BtaAvCoPeerCache::FindPeerAndUpdate(
200     tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address) {
201   log::verbose("peer {} bta_av_handle = 0x{:x}", peer_address, bta_av_handle);
202 
203   BtaAvCoPeer* p_peer = FindPeer(bta_av_handle);
204   if (p_peer == nullptr) {
205     log::error("peer entry for BTA AV handle 0x{:x} peer {} not found",
206                bta_av_handle, peer_address);
207     return nullptr;
208   }
209 
210   log::verbose("peer {} bta_av_handle = 0x{:x} previous address {}",
211                peer_address, bta_av_handle, p_peer->addr);
212   p_peer->addr = peer_address;
213   return p_peer;
214 }
215 
FindPeerUuid(tBTA_AV_HNDL bta_av_handle)216 uint16_t BtaAvCoPeerCache::FindPeerUuid(tBTA_AV_HNDL bta_av_handle) {
217   BtaAvCoPeer* p_peer = FindPeer(bta_av_handle);
218   if (p_peer == nullptr) {
219     return 0;
220   }
221   return p_peer->uuid_to_connect;
222 }
223 
ContentProtectIsScmst(const uint8_t * p_protect_info)224 bool ContentProtectIsScmst(const uint8_t* p_protect_info) {
225   log::verbose("");
226 
227   if (*p_protect_info >= AVDT_CP_LOSC) {
228     uint16_t cp_id;
229     p_protect_info++;
230     STREAM_TO_UINT16(cp_id, p_protect_info);
231     if (cp_id == AVDT_CP_SCMS_T_ID) {
232       log::verbose("SCMS-T found");
233       return true;
234     }
235   }
236   return false;
237 }
238 
AudioProtectHasScmst(uint8_t num_protect,const uint8_t * p_protect_info)239 bool AudioProtectHasScmst(uint8_t num_protect, const uint8_t* p_protect_info) {
240   log::verbose("");
241   while (num_protect--) {
242     if (ContentProtectIsScmst(p_protect_info)) return true;
243     // Move to the next Content Protect schema
244     p_protect_info += *p_protect_info + 1;
245   }
246   log::verbose("SCMS-T not found");
247   return false;
248 }
249 
AudioSepHasContentProtection(const BtaAvCoSep * p_sep,const uint8_t content_protect_flag)250 bool AudioSepHasContentProtection(const BtaAvCoSep* p_sep,
251                                   const uint8_t content_protect_flag) {
252   log::verbose("");
253 
254   // Check if content protection is enabled for this stream
255   if (content_protect_flag != AVDT_CP_SCMS_COPY_FREE) {
256     return AudioProtectHasScmst(p_sep->num_protect, p_sep->protect_info);
257   }
258 
259   log::verbose("not required");
260   return true;
261 }
262