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