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