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 "common/init_flags.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 PHY_UPDATE_RETRY_LIMIT =
45     bluetooth::common::init_flags::get_asha_phy_update_retry_limit();
46 
47 /** Implementations of HearingAid will also implement this interface */
48 class HearingAidAudioReceiver {
49  public:
50   virtual ~HearingAidAudioReceiver() = default;
51   virtual void OnAudioDataReady(const std::vector<uint8_t>& data) = 0;
52 
53   // API to stop our feeding timer, and notify hearing aid devices that the
54   // streaming would stop, too.
55   //
56   // @param stop_audio_ticks a callable function calls out to stop the media
57   // timer for reading data.
58   virtual void OnAudioSuspend(
59       const std::function<void()>& stop_audio_ticks) = 0;
60 
61   // To notify hearing aid devices to be ready for streaming, and start the
62   // media timer to feed the audio data.
63   //
64   // @param start_audio_ticks a callable function calls out to start a periodic
65   // timer for feeding data from the audio HAL.
66   virtual void OnAudioResume(
67       const std::function<void()>& start_audio_ticks) = 0;
68 };
69 
70 // Number of rssi reads to attempt when requested
71 constexpr int READ_RSSI_NUM_TRIES = 10;
72 constexpr int PERIOD_TO_READ_RSSI_IN_INTERVALS = 5;
73 // Depth of RSSI History in DumpSys
74 constexpr int MAX_RSSI_HISTORY = 15;
75 
76 struct rssi_log {
77   struct timespec timestamp;
78   std::vector<int8_t> rssi;
79 };
80 
81 struct AudioStats {
82   size_t trigger_drop_count;
83   size_t packet_drop_count;
84   size_t packet_send_count;
85   size_t packet_flush_count;
86   size_t frame_send_count;
87   size_t frame_flush_count;
88   std::deque<rssi_log> rssi_history;
89 
AudioStatsAudioStats90   AudioStats() { Reset(); }
91 
ResetAudioStats92   void Reset() {
93     trigger_drop_count = 0;
94     packet_drop_count = 0;
95     packet_send_count = 0;
96     packet_flush_count = 0;
97     frame_send_count = 0;
98     frame_flush_count = 0;
99   }
100 };
101 
102 /** Possible states for the Connection Update status */
103 typedef enum {
104   NONE,      // Not Connected
105   AWAITING,  // Waiting for start the Connection Update operation
106   STARTED,   // Connection Update has started
107   COMPLETED  // Connection Update is completed successfully
108 } connection_update_status_t;
109 
110 struct HearingDevice {
111   RawAddress address;
112   /* This is true only during first connection to profile, until we store the
113    * device */
114   bool first_connection;
115   bool service_changed_rcvd;
116 
117   /* we are making active attempt to connect to this device, 'direct connect'.
118    */
119   bool connecting_actively;
120 
121   bool switch_to_background_connection_after_failure;
122 
123   /* For two hearing aids, you must update their parameters one after another,
124    * not simulteanously, to ensure start of connection events for both devices
125    * are far from each other. This status tracks whether this device is waiting
126    * for update of parameters, that should happen after "LE Connection Update
127    * Complete" event
128    */
129   connection_update_status_t connection_update_status;
130   uint16_t requested_connection_interval;
131 
132   /* if true, we are connected, L2CAP socket is open, we can stream audio.
133      However, the actual audio stream also depends on whether the
134      Audio Service has resumed.
135    */
136   bool accepting_audio;
137 
138   uint16_t conn_id;
139   uint16_t gap_handle;
140   uint16_t audio_control_point_handle;
141   uint16_t audio_status_handle;
142   uint16_t audio_status_ccc_handle;
143   uint16_t service_changed_ccc_handle;
144   uint16_t volume_handle;
145   uint16_t read_psm_handle;
146 
147   uint8_t capabilities;
148   uint64_t hi_sync_id;
149   uint16_t render_delay;
150   uint16_t preparation_delay;
151   uint16_t codecs;
152 
153   AudioStats audio_stats;
154   /* Keep tracks of whether the "Start Cmd" has been send to this device. When
155      the "Stop Cmd" is send or when this device disconnects, then this flag is
156      cleared. Please note that the "Start Cmd" is not send during device
157      connection in the case when the audio is suspended. */
158   bool playback_started;
159   /* This tracks whether the last command to Hearing Aids device is
160    * ACKnowledged. */
161   bool command_acked;
162 
163   /* When read_rssi_count is > 0, then read the rssi. The interval between rssi
164      reads is tracked by num_intervals_since_last_rssi_read. */
165   int read_rssi_count;
166   int num_intervals_since_last_rssi_read;
167 
168   bool gap_opened;
169 
170   int phy_update_retry_remain;
171 
HearingDeviceHearingDevice172   HearingDevice(const RawAddress& address, uint8_t capabilities,
173                 uint16_t codecs, uint16_t audio_control_point_handle,
174                 uint16_t audio_status_handle, uint16_t audio_status_ccc_handle,
175                 uint16_t service_changed_ccc_handle, uint16_t volume_handle,
176                 uint16_t read_psm_handle, uint64_t hiSyncId,
177                 uint16_t render_delay, uint16_t preparation_delay)
178       : address(address),
179         first_connection(false),
180         service_changed_rcvd(false),
181         connecting_actively(false),
182         switch_to_background_connection_after_failure(false),
183         connection_update_status(NONE),
184         accepting_audio(false),
185         conn_id(0),
186         gap_handle(GAP_INVALID_HANDLE),
187         audio_control_point_handle(audio_control_point_handle),
188         audio_status_handle(audio_status_handle),
189         audio_status_ccc_handle(audio_status_ccc_handle),
190         service_changed_ccc_handle(service_changed_ccc_handle),
191         volume_handle(volume_handle),
192         read_psm_handle(read_psm_handle),
193         capabilities(capabilities),
194         hi_sync_id(hiSyncId),
195         render_delay(render_delay),
196         preparation_delay(preparation_delay),
197         codecs(codecs),
198         playback_started(false),
199         command_acked(false),
200         read_rssi_count(0),
201         gap_opened(false),
202         phy_update_retry_remain(PHY_UPDATE_RETRY_LIMIT) {}
203 
HearingDeviceHearingDevice204   HearingDevice(const RawAddress& address, bool first_connection)
205       : address(address),
206         first_connection(first_connection),
207         service_changed_rcvd(false),
208         connecting_actively(first_connection),
209         switch_to_background_connection_after_failure(false),
210         connection_update_status(NONE),
211         accepting_audio(false),
212         conn_id(0),
213         gap_handle(GAP_INVALID_HANDLE),
214         audio_status_handle(0),
215         audio_status_ccc_handle(0),
216         service_changed_ccc_handle(0),
217         read_psm_handle(0),
218         capabilities(0),
219         hi_sync_id(0),
220         render_delay(0),
221         preparation_delay(0),
222         codecs(0),
223         playback_started(false),
224         command_acked(false),
225         read_rssi_count(0),
226         gap_opened(false),
227         phy_update_retry_remain(PHY_UPDATE_RETRY_LIMIT) {}
228 
HearingDeviceHearingDevice229   HearingDevice() : HearingDevice(RawAddress::kEmpty, false) {}
230 
231   /* return true if this device represents left Hearing Aid. Returned value is
232    * valid only after capabilities are discovered */
isLeftHearingDevice233   bool isLeft() const { return !(capabilities & CAPABILITY_SIDE); }
234 };
235 
236 class HearingAid {
237  public:
238   virtual ~HearingAid() = default;
239 
240   static void Initialize(bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
241                          base::Closure initCb);
242   static void CleanUp();
243   static bool IsHearingAidRunning();
244   static void DebugDump(int fd);
245 
246   static void AddFromStorage(const HearingDevice& dev_info,
247                              bool is_acceptlisted);
248 
249   static int GetDeviceCount();
250 
251   static void Connect(const RawAddress& address);
252   static void Disconnect(const RawAddress& address);
253   static void AddToAcceptlist(const RawAddress& address);
254   static void SetVolume(int8_t volume);
255 };
256 
257 /* Represents configuration of audio codec, as exchanged between hearing aid and
258  * phone.
259  * It can also be passed to the audio source to configure its parameters.
260  */
261 struct CodecConfiguration {
262   /** sampling rate that the codec expects to receive from audio framework */
263   uint32_t sample_rate;
264 
265   /** bitrate that codec expects to receive from audio framework in bits per
266    * channel */
267   uint32_t bit_rate;
268 
269   /** Data interval determines how often we send samples to the remote. This
270    * should match how often we grab data from audio source, optionally we can
271    * grab data every 2 or 3 intervals, but this would increase latency.
272    *
273    * Value is provided in ms, must be divisable by 1.25 to make sure the
274    * connection interval is integer.
275    */
276   uint16_t data_interval_ms;
277 };
278 
279 /** Represents source of audio for hearing aids */
280 class HearingAidAudioSource {
281  public:
282   static void Start(const CodecConfiguration& codecConfiguration,
283                     HearingAidAudioReceiver* audioReceiver,
284                     uint16_t remote_delay_ms);
285   static void Stop();
286   static void Initialize();
287   static void CleanUp();
288   static void DebugDump(int fd);
289 };
290 
291 namespace fmt {
292 template <>
293 struct formatter<connection_update_status_t>
294     : enum_formatter<connection_update_status_t> {};
295 }  // namespace fmt
296