1 use crate::btif::{BluetoothInterface, BtStatus, RawAddress, ToggleableProfile}; 2 use crate::topstack::get_dispatchers; 3 4 use bitflags::bitflags; 5 use num_derive::{FromPrimitive, ToPrimitive}; 6 use num_traits::cast::FromPrimitive; 7 use std::convert::{TryFrom, TryInto}; 8 use std::sync::{Arc, Mutex}; 9 use topshim_macros::{cb_variant, profile_enabled_or}; 10 11 use log::warn; 12 13 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] 14 #[repr(u32)] 15 pub enum BthfConnectionState { 16 Disconnected = 0, 17 Connecting, 18 Connected, 19 SlcConnected, 20 Disconnecting, 21 } 22 23 impl From<u32> for BthfConnectionState { from(item: u32) -> Self24 fn from(item: u32) -> Self { 25 BthfConnectionState::from_u32(item).unwrap() 26 } 27 } 28 29 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd, Clone)] 30 #[repr(u32)] 31 pub enum BthfAudioState { 32 Disconnected = 0, 33 Connecting, 34 Connected, 35 Disconnecting, 36 } 37 38 impl From<u32> for BthfAudioState { from(item: u32) -> Self39 fn from(item: u32) -> Self { 40 BthfAudioState::from_u32(item).unwrap() 41 } 42 } 43 44 bitflags! { 45 #[derive(Default)] 46 pub struct HfpCodecCapability: i32 { 47 const UNSUPPORTED = 0b00; 48 const CVSD = 0b01; 49 const MSBC = 0b10; 50 const LC3 = 0b100; 51 } 52 } 53 54 impl TryInto<i32> for HfpCodecCapability { 55 type Error = (); try_into(self) -> Result<i32, Self::Error>56 fn try_into(self) -> Result<i32, Self::Error> { 57 Ok(self.bits()) 58 } 59 } 60 61 impl TryFrom<i32> for HfpCodecCapability { 62 type Error = (); try_from(val: i32) -> Result<Self, Self::Error>63 fn try_from(val: i32) -> Result<Self, Self::Error> { 64 Self::from_bits(val).ok_or(()) 65 } 66 } 67 68 #[cxx::bridge(namespace = bluetooth::topshim::rust)] 69 pub mod ffi { 70 unsafe extern "C++" { 71 include!("gd/rust/topshim/common/type_alias.h"); 72 type RawAddress = crate::btif::RawAddress; 73 } 74 75 #[derive(Debug, Copy, Clone)] 76 pub struct TelephonyDeviceStatus { 77 network_available: bool, 78 roaming: bool, 79 signal_strength: i32, 80 battery_level: i32, 81 } 82 83 #[derive(Debug, Copy, Clone)] 84 pub enum CallState { 85 Idle, 86 Incoming, 87 Dialing, 88 Alerting, 89 Active, // Only used by CLCC response 90 Held, // Only used by CLCC response 91 } 92 93 #[derive(Debug, Clone)] 94 pub struct CallInfo { 95 index: i32, 96 dir_incoming: bool, 97 state: CallState, 98 number: String, 99 } 100 101 #[derive(Debug, Copy, Clone)] 102 pub struct PhoneState { 103 num_active: i32, 104 num_held: i32, 105 state: CallState, 106 } 107 108 #[derive(Debug, Copy, Clone)] 109 pub enum CallHoldCommand { 110 ReleaseHeld, 111 ReleaseActiveAcceptHeld, 112 HoldActiveAcceptHeld, 113 // We don't support it in our telephony stack because it's not necessary for qualification. 114 // But still inform the stack about this event. 115 AddHeldToConf, 116 } 117 118 unsafe extern "C++" { 119 include!("hfp/hfp_shim.h"); 120 121 type HfpIntf; 122 GetHfpProfile(btif: *const u8) -> UniquePtr<HfpIntf>123 unsafe fn GetHfpProfile(btif: *const u8) -> UniquePtr<HfpIntf>; 124 init(self: Pin<&mut HfpIntf>) -> i32125 fn init(self: Pin<&mut HfpIntf>) -> i32; connect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32126 fn connect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32; connect_audio( self: Pin<&mut HfpIntf>, bt_addr: RawAddress, sco_offload: bool, force_cvsd: bool, ) -> i32127 fn connect_audio( 128 self: Pin<&mut HfpIntf>, 129 bt_addr: RawAddress, 130 sco_offload: bool, 131 force_cvsd: bool, 132 ) -> i32; set_active_device(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32133 fn set_active_device(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32; set_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> i32134 fn set_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> i32; disconnect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32135 fn disconnect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32; disconnect_audio(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32136 fn disconnect_audio(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32; device_status_notification( self: Pin<&mut HfpIntf>, status: TelephonyDeviceStatus, addr: RawAddress, ) -> u32137 fn device_status_notification( 138 self: Pin<&mut HfpIntf>, 139 status: TelephonyDeviceStatus, 140 addr: RawAddress, 141 ) -> u32; indicator_query_response( self: Pin<&mut HfpIntf>, device_status: TelephonyDeviceStatus, phone_state: PhoneState, addr: RawAddress, ) -> u32142 fn indicator_query_response( 143 self: Pin<&mut HfpIntf>, 144 device_status: TelephonyDeviceStatus, 145 phone_state: PhoneState, 146 addr: RawAddress, 147 ) -> u32; current_calls_query_response( self: Pin<&mut HfpIntf>, call_list: &Vec<CallInfo>, addr: RawAddress, ) -> u32148 fn current_calls_query_response( 149 self: Pin<&mut HfpIntf>, 150 call_list: &Vec<CallInfo>, 151 addr: RawAddress, 152 ) -> u32; phone_state_change( self: Pin<&mut HfpIntf>, phone_state: PhoneState, number: &String, addr: RawAddress, ) -> u32153 fn phone_state_change( 154 self: Pin<&mut HfpIntf>, 155 phone_state: PhoneState, 156 number: &String, 157 addr: RawAddress, 158 ) -> u32; simple_at_response(self: Pin<&mut HfpIntf>, ok: bool, addr: RawAddress) -> u32159 fn simple_at_response(self: Pin<&mut HfpIntf>, ok: bool, addr: RawAddress) -> u32; cleanup(self: Pin<&mut HfpIntf>)160 fn cleanup(self: Pin<&mut HfpIntf>); 161 162 } 163 extern "Rust" { hfp_connection_state_callback(state: u32, addr: RawAddress)164 fn hfp_connection_state_callback(state: u32, addr: RawAddress); hfp_audio_state_callback(state: u32, addr: RawAddress)165 fn hfp_audio_state_callback(state: u32, addr: RawAddress); hfp_volume_update_callback(volume: u8, addr: RawAddress)166 fn hfp_volume_update_callback(volume: u8, addr: RawAddress); hfp_battery_level_update_callback(battery_level: u8, addr: RawAddress)167 fn hfp_battery_level_update_callback(battery_level: u8, addr: RawAddress); hfp_wbs_caps_update_callback(wbs_supported: bool, addr: RawAddress)168 fn hfp_wbs_caps_update_callback(wbs_supported: bool, addr: RawAddress); hfp_swb_caps_update_callback(swb_supported: bool, addr: RawAddress)169 fn hfp_swb_caps_update_callback(swb_supported: bool, addr: RawAddress); hfp_indicator_query_callback(addr: RawAddress)170 fn hfp_indicator_query_callback(addr: RawAddress); hfp_current_calls_query_callback(addr: RawAddress)171 fn hfp_current_calls_query_callback(addr: RawAddress); hfp_answer_call_callback(addr: RawAddress)172 fn hfp_answer_call_callback(addr: RawAddress); hfp_hangup_call_callback(addr: RawAddress)173 fn hfp_hangup_call_callback(addr: RawAddress); hfp_dial_call_callback(number: String, addr: RawAddress)174 fn hfp_dial_call_callback(number: String, addr: RawAddress); hfp_call_hold_callback(chld: CallHoldCommand, addr: RawAddress)175 fn hfp_call_hold_callback(chld: CallHoldCommand, addr: RawAddress); 176 } 177 } 178 179 pub type TelephonyDeviceStatus = ffi::TelephonyDeviceStatus; 180 181 impl TelephonyDeviceStatus { new() -> Self182 pub fn new() -> Self { 183 TelephonyDeviceStatus { 184 network_available: true, 185 roaming: false, 186 signal_strength: 5, 187 battery_level: 5, 188 } 189 } 190 } 191 192 pub type CallState = ffi::CallState; 193 pub type CallInfo = ffi::CallInfo; 194 pub type PhoneState = ffi::PhoneState; 195 pub type CallHoldCommand = ffi::CallHoldCommand; 196 197 #[derive(Clone, Debug)] 198 pub enum HfpCallbacks { 199 ConnectionState(BthfConnectionState, RawAddress), 200 AudioState(BthfAudioState, RawAddress), 201 VolumeUpdate(u8, RawAddress), 202 BatteryLevelUpdate(u8, RawAddress), 203 WbsCapsUpdate(bool, RawAddress), 204 SwbCapsUpdate(bool, RawAddress), 205 IndicatorQuery(RawAddress), 206 CurrentCallsQuery(RawAddress), 207 AnswerCall(RawAddress), 208 HangupCall(RawAddress), 209 DialCall(String, RawAddress), 210 CallHold(CallHoldCommand, RawAddress), 211 } 212 213 pub struct HfpCallbacksDispatcher { 214 pub dispatch: Box<dyn Fn(HfpCallbacks) + Send>, 215 } 216 217 type HfpCb = Arc<Mutex<HfpCallbacksDispatcher>>; 218 219 cb_variant!( 220 HfpCb, 221 hfp_connection_state_callback -> HfpCallbacks::ConnectionState, 222 u32 -> BthfConnectionState, RawAddress); 223 224 cb_variant!( 225 HfpCb, 226 hfp_audio_state_callback -> HfpCallbacks::AudioState, 227 u32 -> BthfAudioState, RawAddress); 228 229 cb_variant!( 230 HfpCb, 231 hfp_volume_update_callback -> HfpCallbacks::VolumeUpdate, 232 u8, RawAddress); 233 234 cb_variant!( 235 HfpCb, 236 hfp_battery_level_update_callback -> HfpCallbacks::BatteryLevelUpdate, 237 u8, RawAddress); 238 239 cb_variant!( 240 HfpCb, 241 hfp_wbs_caps_update_callback -> HfpCallbacks::WbsCapsUpdate, 242 bool, RawAddress); 243 244 cb_variant!( 245 HfpCb, 246 hfp_swb_caps_update_callback -> HfpCallbacks::SwbCapsUpdate, 247 bool, RawAddress); 248 249 cb_variant!( 250 HfpCb, 251 hfp_indicator_query_callback -> HfpCallbacks::IndicatorQuery, 252 RawAddress); 253 254 cb_variant!( 255 HfpCb, 256 hfp_current_calls_query_callback -> HfpCallbacks::CurrentCallsQuery, 257 RawAddress); 258 259 cb_variant!( 260 HfpCb, 261 hfp_answer_call_callback -> HfpCallbacks::AnswerCall, 262 RawAddress); 263 264 cb_variant!( 265 HfpCb, 266 hfp_hangup_call_callback -> HfpCallbacks::HangupCall, 267 RawAddress); 268 269 cb_variant!( 270 HfpCb, 271 hfp_dial_call_callback -> HfpCallbacks::DialCall, 272 String, RawAddress); 273 274 cb_variant!( 275 HfpCb, 276 hfp_call_hold_callback -> HfpCallbacks::CallHold, 277 CallHoldCommand, RawAddress); 278 279 pub struct Hfp { 280 internal: cxx::UniquePtr<ffi::HfpIntf>, 281 _is_init: bool, 282 _is_enabled: bool, 283 } 284 285 // For *const u8 opaque btif 286 unsafe impl Send for Hfp {} 287 288 impl ToggleableProfile for Hfp { is_enabled(&self) -> bool289 fn is_enabled(&self) -> bool { 290 self._is_enabled 291 } 292 enable(&mut self) -> bool293 fn enable(&mut self) -> bool { 294 self.internal.pin_mut().init(); 295 self._is_enabled = true; 296 true 297 } 298 299 #[profile_enabled_or(false)] disable(&mut self) -> bool300 fn disable(&mut self) -> bool { 301 self.internal.pin_mut().cleanup(); 302 self._is_enabled = false; 303 true 304 } 305 } 306 307 impl Hfp { new(intf: &BluetoothInterface) -> Hfp308 pub fn new(intf: &BluetoothInterface) -> Hfp { 309 let hfpif: cxx::UniquePtr<ffi::HfpIntf>; 310 unsafe { 311 hfpif = ffi::GetHfpProfile(intf.as_raw_ptr()); 312 } 313 314 Hfp { internal: hfpif, _is_init: false, _is_enabled: false } 315 } 316 is_initialized(&self) -> bool317 pub fn is_initialized(&self) -> bool { 318 self._is_init 319 } 320 initialize(&mut self, callbacks: HfpCallbacksDispatcher) -> bool321 pub fn initialize(&mut self, callbacks: HfpCallbacksDispatcher) -> bool { 322 if get_dispatchers().lock().unwrap().set::<HfpCb>(Arc::new(Mutex::new(callbacks))) { 323 panic!("Tried to set dispatcher for HFP callbacks while it already exists"); 324 } 325 self._is_init = true; 326 true 327 } 328 329 #[profile_enabled_or(BtStatus::NotReady)] connect(&mut self, addr: RawAddress) -> BtStatus330 pub fn connect(&mut self, addr: RawAddress) -> BtStatus { 331 BtStatus::from(self.internal.pin_mut().connect(addr)) 332 } 333 334 #[profile_enabled_or(BtStatus::NotReady.into())] connect_audio(&mut self, addr: RawAddress, sco_offload: bool, force_cvsd: bool) -> i32335 pub fn connect_audio(&mut self, addr: RawAddress, sco_offload: bool, force_cvsd: bool) -> i32 { 336 self.internal.pin_mut().connect_audio(addr, sco_offload, force_cvsd) 337 } 338 339 #[profile_enabled_or(BtStatus::NotReady.into())] set_active_device(&mut self, addr: RawAddress) -> i32340 pub fn set_active_device(&mut self, addr: RawAddress) -> i32 { 341 self.internal.pin_mut().set_active_device(addr) 342 } 343 344 #[profile_enabled_or(BtStatus::NotReady.into())] set_volume(&mut self, volume: i8, addr: RawAddress) -> i32345 pub fn set_volume(&mut self, volume: i8, addr: RawAddress) -> i32 { 346 self.internal.pin_mut().set_volume(volume, addr) 347 } 348 349 #[profile_enabled_or(BtStatus::NotReady)] disconnect(&mut self, addr: RawAddress) -> BtStatus350 pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus { 351 BtStatus::from(self.internal.pin_mut().disconnect(addr)) 352 } 353 354 #[profile_enabled_or(BtStatus::NotReady.into())] disconnect_audio(&mut self, addr: RawAddress) -> i32355 pub fn disconnect_audio(&mut self, addr: RawAddress) -> i32 { 356 self.internal.pin_mut().disconnect_audio(addr) 357 } 358 359 #[profile_enabled_or(BtStatus::NotReady)] device_status_notification( &mut self, status: TelephonyDeviceStatus, addr: RawAddress, ) -> BtStatus360 pub fn device_status_notification( 361 &mut self, 362 status: TelephonyDeviceStatus, 363 addr: RawAddress, 364 ) -> BtStatus { 365 BtStatus::from(self.internal.pin_mut().device_status_notification(status, addr)) 366 } 367 368 #[profile_enabled_or(BtStatus::NotReady)] indicator_query_response( &mut self, device_status: TelephonyDeviceStatus, phone_state: PhoneState, addr: RawAddress, ) -> BtStatus369 pub fn indicator_query_response( 370 &mut self, 371 device_status: TelephonyDeviceStatus, 372 phone_state: PhoneState, 373 addr: RawAddress, 374 ) -> BtStatus { 375 BtStatus::from(self.internal.pin_mut().indicator_query_response( 376 device_status, 377 phone_state, 378 addr, 379 )) 380 } 381 382 #[profile_enabled_or(BtStatus::NotReady)] current_calls_query_response( &mut self, call_list: &Vec<CallInfo>, addr: RawAddress, ) -> BtStatus383 pub fn current_calls_query_response( 384 &mut self, 385 call_list: &Vec<CallInfo>, 386 addr: RawAddress, 387 ) -> BtStatus { 388 BtStatus::from(self.internal.pin_mut().current_calls_query_response(call_list, addr)) 389 } 390 391 #[profile_enabled_or(BtStatus::NotReady)] phone_state_change( &mut self, phone_state: PhoneState, number: &String, addr: RawAddress, ) -> BtStatus392 pub fn phone_state_change( 393 &mut self, 394 phone_state: PhoneState, 395 number: &String, 396 addr: RawAddress, 397 ) -> BtStatus { 398 BtStatus::from(self.internal.pin_mut().phone_state_change(phone_state, number, addr)) 399 } 400 401 #[profile_enabled_or(BtStatus::NotReady)] simple_at_response(&mut self, ok: bool, addr: RawAddress) -> BtStatus402 pub fn simple_at_response(&mut self, ok: bool, addr: RawAddress) -> BtStatus { 403 BtStatus::from(self.internal.pin_mut().simple_at_response(ok, addr)) 404 } 405 406 #[profile_enabled_or(false)] cleanup(&mut self) -> bool407 pub fn cleanup(&mut self) -> bool { 408 self.internal.pin_mut().cleanup(); 409 true 410 } 411 } 412