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 #pragma once
18 
19 #include <cstdint>
20 #include <functional>
21 #include <optional>
22 
23 #include "hci/address.h"
24 
25 namespace rootcanal {
26 
27 using ::bluetooth::hci::Address;
28 using TaskId = uint32_t;
29 
30 /*
31  * Notes about SCO / eSCO connection establishment:
32  *
33  * - Connections will always be established if possible as eSCO connections.
34  * The LMP parameter negotiation is skipped, instead the required parameters
35  * are directly sent to the peer.
36  *
37  * - If an synchronous connection setup fails with eSCO parameter negotiation,
38  * it is _not_ retried with SCO parameter negotiation.
39  *
40  * - If the parameters are compatible with the values returned from
41  * HCI Accept Synchronous Connection Request on the peer,
42  * the peer selects a valid link configuration which it returns
43  * in response.
44  */
45 
46 struct ScoLinkParameters {
47   uint8_t transmission_interval;
48   uint8_t retransmission_window;
49   uint16_t rx_packet_length;
50   uint16_t tx_packet_length;
51   uint8_t air_mode;
52   bool extended;
53 };
54 
55 struct ScoConnectionParameters {
56   uint32_t transmit_bandwidth;
57   uint32_t receive_bandwidth;
58   uint16_t max_latency;  // 0-3 reserved, 0xFFFF = don't care
59   uint16_t voice_setting;
60   uint8_t retransmission_effort;
61   uint16_t packet_type;
62 
63   // Return true if packet_type enables extended SCO packets.
64   bool IsExtended() const;
65 
66   // Return the link parameters for these connection parameters, if the
67   // parameters are coherent, none otherwise.
68   std::optional<ScoLinkParameters> GetLinkParameters() const;
69 };
70 
71 enum ScoState {
72   SCO_STATE_CLOSED = 0,
73   SCO_STATE_PENDING,
74   SCO_STATE_SENT_ESCO_CONNECTION_REQUEST,
75   SCO_STATE_SENT_SCO_CONNECTION_REQUEST,
76   SCO_STATE_OPENED,
77 };
78 
79 enum ScoDatapath {
80   NORMAL = 0,   // data is provided by the host over HCI
81   SPOOFED = 1,  // rootcanal generates data itself
82 };
83 
84 class ScoConnection {
85 public:
ScoConnection(Address address,ScoConnectionParameters const & parameters,ScoState state,ScoDatapath datapath,bool legacy)86   ScoConnection(Address address, ScoConnectionParameters const& parameters, ScoState state,
87                 ScoDatapath datapath, bool legacy)
88       : address_(address),
89         parameters_(parameters),
90         link_parameters_(),
91         state_(state),
92         datapath_(datapath),
93         legacy_(legacy) {}
94 
95   ~ScoConnection();
96 
IsLegacy()97   bool IsLegacy() const { return legacy_; }
GetAddress()98   Address GetAddress() const { return address_; }
GetState()99   ScoState GetState() const { return state_; }
SetState(ScoState state)100   void SetState(ScoState state) { state_ = state; }
101 
102   void StartStream(std::function<TaskId()> startStream);
103   void StopStream(std::function<void(TaskId)> stopStream);
104 
GetConnectionParameters()105   ScoConnectionParameters GetConnectionParameters() const { return parameters_; }
GetLinkParameters()106   ScoLinkParameters GetLinkParameters() const { return link_parameters_; }
SetLinkParameters(ScoLinkParameters const & parameters)107   void SetLinkParameters(ScoLinkParameters const& parameters) { link_parameters_ = parameters; }
108 
109   // Negotiate the connection parameters.
110   // Update the local connection parameters with negotiated values.
111   // Return true if the negotiation was successful, false otherwise.
112   bool NegotiateLinkParameters(ScoConnectionParameters const& peer);
113 
GetDatapath()114   ScoDatapath GetDatapath() const { return datapath_; }
115 
116 private:
117   Address address_;
118   ScoConnectionParameters parameters_;
119   ScoLinkParameters link_parameters_;
120   ScoState state_;
121 
122   // whether we use HCI, spoof the data, or potential future datapaths
123   ScoDatapath datapath_;
124 
125   // The handle of the async task managing the SCO stream, used to simulate
126   // offloaded input. None if HCI is used for input packets.
127   std::optional<TaskId> stream_handle_{};
128 
129   // Mark connections opened with the HCI command Add SCO Connection.
130   // The connection status is reported with HCI Connection Complete event
131   // rather than HCI Synchronous Connection Complete event.
132   bool legacy_;
133 };
134 
135 }  // namespace rootcanal
136