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