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