1 /******************************************************************************
2  *
3  *  Copyright 2018 The Android Open Source Project
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #pragma once
20 
21 #include <base/functional/callback_forward.h>
22 #include <bluetooth/log.h>
23 #include <hardware/bt_hearing_aid.h>
24 
25 #include <cstdint>
26 #include <deque>
27 #include <functional>
28 #include <vector>
29 
30 #include "stack/include/btm_ble_api_types.h"
31 #include "stack/include/gap_api.h"
32 #include "types/raw_address.h"
33 
34 constexpr uint16_t HA_INTERVAL_10_MS = 10;
35 constexpr uint16_t HA_INTERVAL_20_MS = 20;
36 
37 // Masks for checking capability support
38 constexpr uint8_t CAPABILITY_SIDE = 0x01;
39 constexpr uint8_t CAPABILITY_BINAURAL = 0x02;
40 constexpr uint8_t CAPABILITY_CSIS = 0x04;
41 constexpr uint8_t CAPABILITY_RESERVED = 0xF8;
42 
43 // Number of retry for phy update. This targets to reduce phy update collision.
44 const static uint8_t kPhyUpdateRetryLimit = 5;
45 
46 /** Implementations of HearingAid will also implement this interface */
47 class HearingAidAudioReceiver {
48 public:
49   virtual ~HearingAidAudioReceiver() = default;
50   virtual void OnAudioDataReady(const std::vector<uint8_t>& data) = 0;
51 
52   // API to stop our feeding timer, and notify hearing aid devices that the
53   // streaming would stop, too.
54   //
55   // @param stop_audio_ticks a callable function calls out to stop the media
56   // timer for reading data.
57   virtual void OnAudioSuspend(const std::function<void()>& stop_audio_ticks) = 0;
58 
59   // To notify hearing aid devices to be ready for streaming, and start the
60   // media timer to feed the audio data.
61   //
62   // @param start_audio_ticks a callable function calls out to start a periodic
63   // timer for feeding data from the audio HAL.
64   virtual void OnAudioResume(const std::function<void()>& start_audio_ticks) = 0;
65 };
66 
67 // Number of rssi reads to attempt when requested
68 constexpr int READ_RSSI_NUM_TRIES = 10;
69 constexpr int PERIOD_TO_READ_RSSI_IN_INTERVALS = 5;
70 // Depth of RSSI History in DumpSys
71 constexpr int MAX_RSSI_HISTORY = 15;
72 
73 struct rssi_log {
74   struct timespec timestamp;
75   std::vector<int8_t> rssi;
76 };
77 
78 struct AudioStats {
79   size_t trigger_drop_count;
80   size_t packet_drop_count;
81   size_t packet_send_count;
82   size_t packet_flush_count;
83   size_t frame_send_count;
84   size_t frame_flush_count;
85   std::deque<rssi_log> rssi_history;
86 
AudioStatsAudioStats87   AudioStats() { Reset(); }
88 
ResetAudioStats89   void Reset() {
90     trigger_drop_count = 0;
91     packet_drop_count = 0;
92     packet_send_count = 0;
93     packet_flush_count = 0;
94     frame_send_count = 0;
95     frame_flush_count = 0;
96   }
97 };
98 
99 /** Possible states for the Connection Update status */
100 typedef enum {
101   NONE,      // Not Connected
102   AWAITING,  // Waiting for start the Connection Update operation
103   STARTED,   // Connection Update has started
104   COMPLETED  // Connection Update is completed successfully
105 } connection_update_status_t;
106 
107 struct HearingDevice {
108   RawAddress address;
109   /* This is true only during first connection to profile, until we store the
110    * device */
111   bool first_connection;
112   bool service_changed_rcvd;
113 
114   /* we are making active attempt to connect to this device, 'direct connect'.
115    */
116   bool connecting_actively;
117 
118   bool switch_to_background_connection_after_failure;
119 
120   /* For two hearing aids, you must update their parameters one after another,
121    * not simulteanously, to ensure start of connection events for both devices
122    * are far from each other. This status tracks whether this device is waiting
123    * for update of parameters, that should happen after "LE Connection Update
124    * Complete" event
125    */
126   connection_update_status_t connection_update_status;
127   uint16_t requested_connection_interval;
128 
129   /* if true, we are connected, L2CAP socket is open, we can stream audio.
130      However, the actual audio stream also depends on whether the
131      Audio Service has resumed.
132    */
133   bool accepting_audio;
134 
135   tCONN_ID conn_id;
136   uint16_t gap_handle;
137   uint16_t audio_control_point_handle;
138   uint16_t audio_status_handle;
139   uint16_t audio_status_ccc_handle;
140   uint16_t service_changed_ccc_handle;
141   uint16_t volume_handle;
142   uint16_t read_psm_handle;
143 
144   uint8_t capabilities;
145   uint64_t hi_sync_id;
146   uint16_t render_delay;
147   uint16_t preparation_delay;
148   uint16_t codecs;
149 
150   AudioStats audio_stats;
151   /* Keep tracks of whether the "Start Cmd" has been send to this device. When
152      the "Stop Cmd" is send or when this device disconnects, then this flag is
153      cleared. Please note that the "Start Cmd" is not send during device
154      connection in the case when the audio is suspended. */
155   bool playback_started;
156   /* This tracks whether the last command to Hearing Aids device is
157    * ACKnowledged. */
158   bool command_acked;
159 
160   /* When read_rssi_count is > 0, then read the rssi. The interval between rssi
161      reads is tracked by num_intervals_since_last_rssi_read. */
162   int read_rssi_count;
163   int num_intervals_since_last_rssi_read;
164 
165   bool gap_opened;
166 
167   int phy_update_retry_remain;
168 
HearingDeviceHearingDevice169   HearingDevice(const RawAddress& address, uint8_t capabilities, uint16_t codecs,
170                 uint16_t audio_control_point_handle, uint16_t audio_status_handle,
171                 uint16_t audio_status_ccc_handle, uint16_t service_changed_ccc_handle,
172                 uint16_t volume_handle, uint16_t read_psm_handle, uint64_t hiSyncId,
173                 uint16_t render_delay, uint16_t preparation_delay)
174       : address(address),
175         first_connection(false),
176         service_changed_rcvd(false),
177         connecting_actively(false),
178         switch_to_background_connection_after_failure(false),
179         connection_update_status(NONE),
180         accepting_audio(false),
181         conn_id(0),
182         gap_handle(GAP_INVALID_HANDLE),
183         audio_control_point_handle(audio_control_point_handle),
184         audio_status_handle(audio_status_handle),
185         audio_status_ccc_handle(audio_status_ccc_handle),
186         service_changed_ccc_handle(service_changed_ccc_handle),
187         volume_handle(volume_handle),
188         read_psm_handle(read_psm_handle),
189         capabilities(capabilities),
190         hi_sync_id(hiSyncId),
191         render_delay(render_delay),
192         preparation_delay(preparation_delay),
193         codecs(codecs),
194         playback_started(false),
195         command_acked(false),
196         read_rssi_count(0),
197         gap_opened(false),
198         phy_update_retry_remain(kPhyUpdateRetryLimit) {}
199 
HearingDeviceHearingDevice200   HearingDevice(const RawAddress& address, bool first_connection)
201       : address(address),
202         first_connection(first_connection),
203         service_changed_rcvd(false),
204         connecting_actively(first_connection),
205         switch_to_background_connection_after_failure(false),
206         connection_update_status(NONE),
207         accepting_audio(false),
208         conn_id(0),
209         gap_handle(GAP_INVALID_HANDLE),
210         audio_status_handle(0),
211         audio_status_ccc_handle(0),
212         service_changed_ccc_handle(0),
213         read_psm_handle(0),
214         capabilities(0),
215         hi_sync_id(0),
216         render_delay(0),
217         preparation_delay(0),
218         codecs(0),
219         playback_started(false),
220         command_acked(false),
221         read_rssi_count(0),
222         gap_opened(false),
223         phy_update_retry_remain(kPhyUpdateRetryLimit) {}
224 
HearingDeviceHearingDevice225   HearingDevice() : HearingDevice(RawAddress::kEmpty, false) {}
226 
227   /* return true if this device represents left Hearing Aid. Returned value is
228    * valid only after capabilities are discovered */
isLeftHearingDevice229   bool isLeft() const { return !(capabilities & CAPABILITY_SIDE); }
230 };
231 
232 class HearingAid {
233 public:
234   virtual ~HearingAid() = default;
235 
236   static void Initialize(bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
237                          base::Closure initCb);
238   static void CleanUp();
239   static bool IsHearingAidRunning();
240   static void DebugDump(int fd);
241 
242   static void AddFromStorage(const HearingDevice& dev_info, bool is_acceptlisted);
243 
244   static int GetDeviceCount();
245 
246   static void Connect(const RawAddress& address);
247   static void Disconnect(const RawAddress& address);
248   static void AddToAcceptlist(const RawAddress& address);
249   static void SetVolume(int8_t volume);
250 };
251 
252 /* Represents configuration of audio codec, as exchanged between hearing aid and
253  * phone.
254  * It can also be passed to the audio source to configure its parameters.
255  */
256 struct CodecConfiguration {
257   /** sampling rate that the codec expects to receive from audio framework */
258   uint32_t sample_rate;
259 
260   /** bitrate that codec expects to receive from audio framework in bits per
261    * channel */
262   uint32_t bit_rate;
263 
264   /** Data interval determines how often we send samples to the remote. This
265    * should match how often we grab data from audio source, optionally we can
266    * grab data every 2 or 3 intervals, but this would increase latency.
267    *
268    * Value is provided in ms, must be divisable by 1.25 to make sure the
269    * connection interval is integer.
270    */
271   uint16_t data_interval_ms;
272 };
273 
274 /** Represents source of audio for hearing aids */
275 class HearingAidAudioSource {
276 public:
277   static void Start(const CodecConfiguration& codecConfiguration,
278                     HearingAidAudioReceiver* audioReceiver, uint16_t remote_delay_ms);
279   static void Stop();
280   static void Initialize();
281   static void CleanUp();
282   static void DebugDump(int fd);
283 };
284 
285 namespace std {
286 template <>
287 struct formatter<connection_update_status_t> : enum_formatter<connection_update_status_t> {};
288 }  // namespace std
289