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