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