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