• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 #include "sco_connection.h"
18 
19 #include <hci/hci_packets.h>
20 #include <log.h>
21 
22 #include <vector>
23 
24 using namespace rootcanal;
25 using namespace bluetooth::hci;
26 
IsExtended()27 bool ScoConnectionParameters::IsExtended() {
28   uint16_t legacy = (uint16_t)SynchronousPacketTypeBits::HV1_ALLOWED |
29                     (uint16_t)SynchronousPacketTypeBits::HV2_ALLOWED |
30                     (uint16_t)SynchronousPacketTypeBits::HV3_ALLOWED;
31   uint16_t edr = (uint16_t)SynchronousPacketTypeBits::NO_2_EV3_ALLOWED |
32                  (uint16_t)SynchronousPacketTypeBits::NO_3_EV3_ALLOWED |
33                  (uint16_t)SynchronousPacketTypeBits::NO_2_EV5_ALLOWED |
34                  (uint16_t)SynchronousPacketTypeBits::NO_3_EV5_ALLOWED;
35   return ((packet_type ^ edr) & ~legacy) != 0;
36 }
37 
GetLinkParameters()38 std::optional<ScoLinkParameters> ScoConnectionParameters::GetLinkParameters() {
39   // Coding conversion.
40   uint8_t air_coding_to_air_mode[] = {
41       0x02,  // CVSD
42       0x00,  // u-law
43       0x01,  // A-law
44       0x03,  // transparent data
45   };
46 
47   // Prioritize eSCO connections.
48   // Packets HV1, HV2, HV3 are tested in a second phase.
49   struct Packet {
50     unsigned length;
51     unsigned slots;
52 
53     Packet(unsigned length, unsigned slots) : length(length), slots(slots) {}
54   };
55 
56   std::vector<Packet> accepted_packets;
57   accepted_packets.push_back(Packet(0, 1));  // POLL/NULL
58 
59   if (packet_type & (uint16_t)SynchronousPacketTypeBits::EV3_ALLOWED)
60     accepted_packets.push_back(Packet(30, 1));
61   if (packet_type & (uint16_t)SynchronousPacketTypeBits::EV4_ALLOWED)
62     accepted_packets.push_back(Packet(120, 3));
63   if (packet_type & (uint16_t)SynchronousPacketTypeBits::EV5_ALLOWED)
64     accepted_packets.push_back(Packet(180, 3));
65   if ((packet_type & (uint16_t)SynchronousPacketTypeBits::NO_2_EV3_ALLOWED) ==
66       0)
67     accepted_packets.push_back(Packet(60, 1));
68   if ((packet_type & (uint16_t)SynchronousPacketTypeBits::NO_3_EV3_ALLOWED) ==
69       0)
70     accepted_packets.push_back(Packet(360, 3));
71   if ((packet_type & (uint16_t)SynchronousPacketTypeBits::NO_2_EV5_ALLOWED) ==
72       0)
73     accepted_packets.push_back(Packet(90, 1));
74   if ((packet_type & (uint16_t)SynchronousPacketTypeBits::NO_3_EV5_ALLOWED) ==
75       0)
76     accepted_packets.push_back(Packet(540, 3));
77 
78   // Ignore empty bandwidths for now.
79   if (transmit_bandwidth == 0 || receive_bandwidth == 0) {
80     LOG_WARN("eSCO transmissions with null bandwidths are not supported");
81     return {};
82   }
83 
84   // Bandwidth usage of the optimal selection.
85   double best_bandwidth_usage = 1.0;
86   std::optional<ScoLinkParameters> best_parameters = {};
87 
88   // Explore all packet combinations, select the valid one
89   // with smallest actual bandwidth usage.
90   for (auto tx : accepted_packets) {
91     if (tx.length == 0) continue;
92 
93     unsigned tx_max_interval = (1600 * tx.length) / transmit_bandwidth;
94 
95     for (auto rx : accepted_packets) {
96       if (rx.length == 0) continue;
97 
98       LOG_INFO("Testing combination %u/%u : %u/%u", tx.length, tx.slots,
99                rx.length, rx.slots);
100 
101       unsigned rx_max_interval = (1600 * rx.length) / receive_bandwidth;
102 
103       // Choose the best interval satisfying both.
104       unsigned transmission_interval =
105           std::min(tx_max_interval, rx_max_interval);
106       transmission_interval -= transmission_interval % 2;
107       transmission_interval = std::min(transmission_interval, 254u);
108 
109       LOG_INFO("Transmission interval: %u slots", transmission_interval);
110 
111       // Compute retransmission window.
112       unsigned retransmission_window =
113           retransmission_effort ==
114                   (uint8_t)RetransmissionEffort::NO_RETRANSMISSION
115               ? 0
116           : retransmission_effort ==
117                   (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_POWER
118               ? rx.slots + tx.slots
119           : retransmission_effort ==
120                   (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_LINK_QUALITY
121               ? 2 * (rx.slots + tx.slots)
122               : 0;
123 
124       LOG_INFO("Retransmission window: %u slots", retransmission_window);
125 
126       // Compute transmission window and validate latency.
127       unsigned transmission_window =
128           tx.slots + rx.slots + retransmission_window;
129 
130       // Validate window.
131       if (transmission_window > transmission_interval)
132         // Oops
133         continue;
134 
135       // Compute and validate latency.
136       unsigned latency = (transmission_window * 1250) / 2;
137 
138       LOG_INFO("Latency: %u us (max %u us)", latency, max_latency * 1000u);
139 
140       if (latency > (1000 * max_latency))
141         // Oops
142         continue;
143 
144       // We got a valid configuration.
145       // Evaluate the actual bandwidth usage.
146       double bandwidth_usage =
147           (double)transmission_window / (double)transmission_interval;
148 
149       if (bandwidth_usage <= best_bandwidth_usage) {
150         LOG_INFO("Valid combination!");
151 
152         uint16_t tx_packet_length =
153             (transmit_bandwidth * transmission_interval + 1600 - 1) / 1600;
154         uint16_t rx_packet_length =
155             (receive_bandwidth * transmission_interval + 1600 - 1) / 1600;
156         uint8_t air_coding = voice_setting & 0x3;
157 
158         best_bandwidth_usage = bandwidth_usage;
159         best_parameters = {
160             (uint8_t)transmission_interval,
161             (uint8_t)retransmission_window,
162             rx_packet_length,
163             tx_packet_length,
164             air_coding_to_air_mode[air_coding],
165             true,
166         };
167       }
168     }
169   }
170 
171   if (best_parameters.has_value()) {
172     return best_parameters;
173   }
174 
175   // Parameter negotiation for SCO connections:
176   // Check packet types and validate bandwidth and latency requirements.
177 
178   if (retransmission_effort ==
179           (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_POWER ||
180       retransmission_effort ==
181           (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_LINK_QUALITY) {
182     LOG_WARN("SCO Retransmission effort must be None or Don't care");
183     return {};
184   }
185 
186   uint8_t transmission_interval;
187   uint16_t packet_length;
188   uint8_t air_coding = voice_setting & 0x3;
189 
190   if (packet_type & (uint16_t)SynchronousPacketTypeBits::HV3_ALLOWED) {
191     transmission_interval = 6;
192     packet_length = 30;
193   } else if (packet_type & (uint16_t)SynchronousPacketTypeBits::HV2_ALLOWED) {
194     transmission_interval = 4;
195     packet_length = 20;
196   } else if (packet_type & (uint16_t)SynchronousPacketTypeBits::HV1_ALLOWED) {
197     transmission_interval = 2;
198     packet_length = 10;
199   } else {
200     LOG_WARN("No SCO packet type enabled");
201     return {};
202   }
203 
204   best_parameters = {
205       transmission_interval,
206       0,
207       packet_length,
208       packet_length,
209       air_coding_to_air_mode[air_coding],
210       false,
211   };
212   return best_parameters;
213 }
214 
NegotiateLinkParameters(ScoConnectionParameters const & peer)215 bool ScoConnection::NegotiateLinkParameters(
216     ScoConnectionParameters const& peer) {
217   if (peer.transmit_bandwidth != 0xffff &&
218       peer.transmit_bandwidth != parameters_.receive_bandwidth) {
219     LOG_WARN("Transmit bandwidth requirements cannot be met");
220     return false;
221   }
222 
223   if (state_ == SCO_STATE_SENT_ESCO_CONNECTION_REQUEST &&
224       peer.receive_bandwidth != 0xffff &&
225       peer.receive_bandwidth != parameters_.transmit_bandwidth) {
226     LOG_WARN("Receive bandwidth requirements cannot be met");
227     return false;
228   }
229 
230   // mask out the air coding format bits before comparison, as per 5.3 Vol
231   // 4E 6.12
232   if ((peer.voice_setting & ~0x3) != (parameters_.voice_setting & ~0x3)) {
233     LOG_WARN("Voice setting requirements cannot be met");
234     LOG_WARN("Remote voice setting: 0x%04x",
235              static_cast<unsigned>(parameters_.voice_setting));
236     LOG_WARN("Local voice setting: 0x%04x",
237              static_cast<unsigned>(peer.voice_setting));
238     return false;
239   }
240 
241   uint16_t packet_type = (peer.packet_type & parameters_.packet_type) & 0x3f;
242   packet_type |= (peer.packet_type | parameters_.packet_type) & 0x3c0;
243 
244   if (packet_type == 0x3c0) {
245     LOG_WARN("Packet type requirements cannot be met");
246     LOG_WARN("Remote packet type: 0x%04x",
247              static_cast<unsigned>(parameters_.packet_type));
248     LOG_WARN("Local packet type: 0x%04x",
249              static_cast<unsigned>(peer.packet_type));
250     return false;
251   }
252 
253   uint16_t max_latency =
254       peer.max_latency == 0xffff ? parameters_.max_latency
255       : parameters_.max_latency == 0xffff
256           ? peer.max_latency
257           : std::min(peer.max_latency, parameters_.max_latency);
258 
259   uint8_t retransmission_effort;
260   if (state_ == SCO_STATE_SENT_SCO_CONNECTION_REQUEST)
261     retransmission_effort = (uint8_t)RetransmissionEffort::NO_RETRANSMISSION;
262   else if (peer.retransmission_effort == parameters_.retransmission_effort ||
263            peer.retransmission_effort ==
264                (uint8_t)RetransmissionEffort::DO_NOT_CARE)
265     retransmission_effort = parameters_.retransmission_effort;
266   else if (parameters_.retransmission_effort ==
267            (uint8_t)RetransmissionEffort::DO_NOT_CARE)
268     retransmission_effort = peer.retransmission_effort;
269   else if (peer.retransmission_effort ==
270                (uint8_t)RetransmissionEffort::NO_RETRANSMISSION ||
271            parameters_.retransmission_effort ==
272                (uint8_t)RetransmissionEffort::NO_RETRANSMISSION) {
273     LOG_WARN("Retransmission effort requirements cannot be met");
274     LOG_WARN("Remote retransmission effort: 0x%02x",
275              static_cast<unsigned>(parameters_.retransmission_effort));
276     LOG_WARN("Local retransmission effort: 0x%04x",
277              static_cast<unsigned>(peer.retransmission_effort));
278     return false;
279   } else {
280     retransmission_effort = (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_POWER;
281   }
282 
283   ScoConnectionParameters negotiated_parameters = {
284       parameters_.transmit_bandwidth,
285       parameters_.receive_bandwidth,
286       max_latency,
287       parameters_.voice_setting,
288       retransmission_effort,
289       packet_type};
290 
291   auto link_parameters = negotiated_parameters.GetLinkParameters();
292   if (link_parameters.has_value()) {
293     link_parameters_ = link_parameters.value();
294     LOG_INFO("Negotiated link parameters for SCO connection:");
295     LOG_INFO("  Transmission interval: %u slots",
296              static_cast<unsigned>(link_parameters_.transmission_interval));
297     LOG_INFO("  Retransmission window: %u slots",
298              static_cast<unsigned>(link_parameters_.retransmission_window));
299     LOG_INFO("  RX packet length: %u bytes",
300              static_cast<unsigned>(link_parameters_.rx_packet_length));
301     LOG_INFO("  TX packet length: %u bytes",
302              static_cast<unsigned>(link_parameters_.tx_packet_length));
303     LOG_INFO("  Air mode: %u",
304              static_cast<unsigned>(link_parameters_.air_mode));
305   } else {
306     LOG_WARN("Failed to derive link parameters");
307   }
308   return link_parameters.has_value();
309 }
310 
StartStream(std::function<AsyncTaskId ()> startStream)311 void ScoConnection::StartStream(std::function<AsyncTaskId()> startStream) {
312   ASSERT(!stream_handle_.has_value());
313   if (datapath_ == ScoDatapath::SPOOFED) {
314     stream_handle_ = startStream();
315   }
316 }
317 
StopStream(std::function<void (AsyncTaskId)> stopStream)318 void ScoConnection::StopStream(std::function<void(AsyncTaskId)> stopStream) {
319   if (stream_handle_.has_value()) {
320     stopStream(*stream_handle_);
321   }
322   stream_handle_ = std::nullopt;
323 }
324