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