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 <cstddef>
24 #include <cstdint>
25 #include <cstring>
26 #include <mutex>
27 #include <vector>
28 
29 #include "bta/include/bta_av_api.h"
30 #include "hardware/bt_av.h"
31 #include "stack/include/a2dp_codec_api.h"
32 #include "stack/include/avdt_api.h"
33 #include "stack/include/bt_types.h"
34 #include "types/raw_address.h"
35 
36 using namespace bluetooth;
37 
38 // Macro to convert BTA AV audio handle to index and vice versa
39 #define BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle) (((bta_av_handle) & (~BTA_AV_CHNL_MSK)) - 1)
40 #define BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(index) (((index) + 1) | BTA_AV_CHNL_AUDIO)
41 
BtaAvCoPeer()42 BtaAvCoPeer::BtaAvCoPeer()
43     : addr(RawAddress::kEmpty),
44       num_sinks(0),
45       num_sources(0),
46       num_seps(0),
47       num_rx_sinks(0),
48       num_rx_sources(0),
49       num_sup_sinks(0),
50       num_sup_sources(0),
51       p_sink(nullptr),
52       p_source(nullptr),
53       codec_config{},
54       acceptor(false),
55       reconfig_needed(false),
56       opened(false),
57       mtu(0),
58       uuid_to_connect(0),
59       bta_av_handle_(0),
60       codecs_(nullptr),
61       content_protect_active_(false) {
62   Reset(0);
63 }
64 
Init(const std::vector<btav_a2dp_codec_config_t> & codec_priorities)65 void BtaAvCoPeer::Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
66   Reset(bta_av_handle_);
67   // Reset the current config
68   codecs_ = new A2dpCodecs(codec_priorities);
69   codecs_->init();
70   A2DP_InitDefaultCodec(codec_config);
71 }
72 
Reset(tBTA_AV_HNDL bta_av_handle)73 void BtaAvCoPeer::Reset(tBTA_AV_HNDL bta_av_handle) {
74   addr = RawAddress::kEmpty;
75   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sinks); i++) {
76     BtaAvCoSep& sink = sinks[i];
77     sink.Reset();
78   }
79   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sources); i++) {
80     BtaAvCoSep& source = sources[i];
81     source.Reset();
82   }
83   num_sinks = 0;
84   num_sources = 0;
85   num_seps = 0;
86   num_rx_sinks = 0;
87   num_rx_sources = 0;
88   num_sup_sinks = 0;
89   num_sup_sources = 0;
90   p_sink = nullptr;
91   p_source = nullptr;
92   memset(codec_config, 0, sizeof(codec_config));
93   acceptor = false;
94   reconfig_needed = false;
95   opened = false;
96   mtu = 0;
97   uuid_to_connect = 0;
98 
99   bta_av_handle_ = bta_av_handle;
100   delete codecs_;
101   codecs_ = nullptr;
102   content_protect_active_ = false;
103 }
104 
getCodecConfig()105 uint8_t* BtaAvCoPeer::getCodecConfig() { return codec_config; }
106 
setCodecConfig(const uint8_t * new_codec_config)107 void BtaAvCoPeer::setCodecConfig(const uint8_t* new_codec_config) {
108   memcpy(codec_config, new_codec_config, AVDT_CODEC_SIZE);
109 }
110 
Init(const std::vector<btav_a2dp_codec_config_t> & codec_priorities)111 void BtaAvCoPeerCache::Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
112   std::lock_guard<std::recursive_mutex> lock(codec_lock_);
113 
114   codec_priorities_ = codec_priorities;
115 
116   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
117     BtaAvCoPeer* p_peer = &peers_[i];
118     p_peer->Init(codec_priorities);
119   }
120 }
121 
Reset()122 void BtaAvCoPeerCache::Reset() {
123   codec_priorities_.clear();
124 
125   // Reset the peers and initialize the handles
126   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
127     BtaAvCoPeer* p_peer = &peers_[i];
128     p_peer->Reset(BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(i));
129   }
130 }
131 
FindPeer(const RawAddress & peer_address)132 BtaAvCoPeer* BtaAvCoPeerCache::FindPeer(const RawAddress& peer_address) {
133   for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) {
134     BtaAvCoPeer* p_peer = &peers_[i];
135     if (p_peer->addr == peer_address) {
136       return p_peer;
137     }
138   }
139   return nullptr;
140 }
141 
FindPeerSource(BtaAvCoPeer * p_peer,btav_a2dp_codec_index_t codec_index,const uint8_t content_protect_flag)142 BtaAvCoSep* BtaAvCoPeerCache::FindPeerSource(BtaAvCoPeer* p_peer,
143                                              btav_a2dp_codec_index_t codec_index,
144                                              const uint8_t content_protect_flag) {
145   if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
146     log::warn("invalid codec index for peer {}", p_peer->addr);
147     return nullptr;
148   }
149 
150   // Find the peer Source for the codec
151   for (size_t index = 0; index < p_peer->num_sup_sources; index++) {
152     BtaAvCoSep* p_source = &p_peer->sources[index];
153     btav_a2dp_codec_index_t peer_codec_index = A2DP_SinkCodecIndex(p_source->codec_caps);
154     if (peer_codec_index != codec_index) {
155       continue;
156     }
157     if (!AudioSepHasContentProtection(p_source, content_protect_flag)) {
158       log::verbose("peer Source for codec {} does not support Content Protection",
159                    A2DP_CodecIndexStr(codec_index));
160       continue;
161     }
162     return p_source;
163   }
164   return nullptr;
165 }
166 
FindPeerSink(BtaAvCoPeer * p_peer,btav_a2dp_codec_index_t codec_index,const uint8_t content_protect_flag)167 BtaAvCoSep* BtaAvCoPeerCache::FindPeerSink(BtaAvCoPeer* p_peer, btav_a2dp_codec_index_t codec_index,
168                                            const uint8_t content_protect_flag) {
169   if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
170     log::warn("invalid codec index for peer {}", p_peer->addr);
171     return nullptr;
172   }
173 
174   // Find the peer Sink for the codec
175   for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
176     BtaAvCoSep* p_sink = &p_peer->sinks[index];
177     btav_a2dp_codec_index_t peer_codec_index = A2DP_SourceCodecIndex(p_sink->codec_caps);
178     if (peer_codec_index != codec_index) {
179       continue;
180     }
181     if (!AudioSepHasContentProtection(p_sink, content_protect_flag)) {
182       log::warn("invalid codec index for peer {}", p_peer->addr);
183       continue;
184     }
185     return p_sink;
186   }
187   return nullptr;
188 }
189 
FindPeer(tBTA_AV_HNDL bta_av_handle)190 BtaAvCoPeer* BtaAvCoPeerCache::FindPeer(tBTA_AV_HNDL bta_av_handle) {
191   uint8_t index;
192 
193   index = BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle);
194 
195   log::verbose("bta_av_handle = 0x{:x} index = {}", bta_av_handle, index);
196 
197   // Sanity check
198   if (index >= BTA_AV_CO_NUM_ELEMENTS(peers_)) {
199     log::error("peer index {} for BTA AV handle 0x{:x} is out of bounds", index, bta_av_handle);
200     return nullptr;
201   }
202 
203   return &peers_[index];
204 }
205 
FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle,const RawAddress & peer_address)206 BtaAvCoPeer* BtaAvCoPeerCache::FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle,
207                                                  const RawAddress& peer_address) {
208   log::verbose("peer {} bta_av_handle = 0x{:x}", peer_address, bta_av_handle);
209 
210   BtaAvCoPeer* p_peer = FindPeer(bta_av_handle);
211   if (p_peer == nullptr) {
212     log::error("peer entry for BTA AV handle 0x{:x} peer {} not found", bta_av_handle,
213                peer_address);
214     return nullptr;
215   }
216 
217   log::verbose("peer {} bta_av_handle = 0x{:x} previous address {}", peer_address, bta_av_handle,
218                p_peer->addr);
219   p_peer->addr = peer_address;
220   return p_peer;
221 }
222 
FindPeerUuid(tBTA_AV_HNDL bta_av_handle)223 uint16_t BtaAvCoPeerCache::FindPeerUuid(tBTA_AV_HNDL bta_av_handle) {
224   BtaAvCoPeer* p_peer = FindPeer(bta_av_handle);
225   if (p_peer == nullptr) {
226     return 0;
227   }
228   return p_peer->uuid_to_connect;
229 }
230 
ContentProtectIsScmst(const uint8_t * p_protect_info)231 bool ContentProtectIsScmst(const uint8_t* p_protect_info) {
232   log::verbose("");
233 
234   if (*p_protect_info >= AVDT_CP_LOSC) {
235     uint16_t cp_id;
236     p_protect_info++;
237     STREAM_TO_UINT16(cp_id, p_protect_info);
238     if (cp_id == AVDT_CP_SCMS_T_ID) {
239       log::verbose("SCMS-T found");
240       return true;
241     }
242   }
243   return false;
244 }
245 
AudioProtectHasScmst(uint8_t num_protect,const uint8_t * p_protect_info)246 bool AudioProtectHasScmst(uint8_t num_protect, const uint8_t* p_protect_info) {
247   log::verbose("");
248   while (num_protect--) {
249     if (ContentProtectIsScmst(p_protect_info)) {
250       return true;
251     }
252     // Move to the next Content Protect schema
253     p_protect_info += *p_protect_info + 1;
254   }
255   log::verbose("SCMS-T not found");
256   return false;
257 }
258 
AudioSepHasContentProtection(const BtaAvCoSep * p_sep,const uint8_t content_protect_flag)259 bool AudioSepHasContentProtection(const BtaAvCoSep* p_sep, const uint8_t content_protect_flag) {
260   log::verbose("");
261 
262   // Check if content protection is enabled for this stream
263   if (content_protect_flag != AVDT_CP_SCMS_COPY_FREE) {
264     return AudioProtectHasScmst(p_sep->num_protect, p_sep->protect_info);
265   }
266 
267   log::verbose("not required");
268   return true;
269 }
270