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