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