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(u8)]
15 pub enum HfpCodecId {
16 NONE = 0x00,
17 CVSD = 0x01,
18 MSBC = 0x02,
19 LC3 = 0x03,
20 }
21
22 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)]
23 #[repr(u8)]
24 pub enum EscoCodingFormat {
25 ULAW = 0x00,
26 ALAW = 0x01,
27 CVSD = 0x02,
28 TRANSPARENT = 0x03,
29 LINEAR = 0x04,
30 MSBC = 0x05,
31 LC3 = 0x06,
32 G729A = 0x07,
33 VENDOR = 0xff,
34 }
35
36 impl From<u8> for EscoCodingFormat {
from(item: u8) -> Self37 fn from(item: u8) -> Self {
38 EscoCodingFormat::from_u8(item).unwrap()
39 }
40 }
41
42 impl From<EscoCodingFormat> for u8 {
from(item: EscoCodingFormat) -> Self43 fn from(item: EscoCodingFormat) -> Self {
44 item as u8
45 }
46 }
47
48 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)]
49 #[repr(u32)]
50 pub enum BthfConnectionState {
51 Disconnected = 0,
52 Connecting,
53 Connected,
54 SlcConnected,
55 Disconnecting,
56 }
57
58 impl From<u32> for BthfConnectionState {
from(item: u32) -> Self59 fn from(item: u32) -> Self {
60 BthfConnectionState::from_u32(item).unwrap()
61 }
62 }
63
64 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd, Clone)]
65 #[repr(u32)]
66 pub enum BthfAudioState {
67 Disconnected = 0,
68 Connecting,
69 Connected,
70 Disconnecting,
71 }
72
73 impl From<u32> for BthfAudioState {
from(item: u32) -> Self74 fn from(item: u32) -> Self {
75 BthfAudioState::from_u32(item).unwrap()
76 }
77 }
78
79 // This is used for codec-negotiation related methods that do not
80 // concern with the coding format. Do not confuse this with |HfpCodecFormat|.
81 bitflags! {
82 #[derive(Clone, Debug, Default)]
83 pub struct HfpCodecBitId: i32 {
84 const NONE = 0b000;
85 const CVSD = 0b001;
86 const MSBC = 0b010;
87 const LC3 = 0b100;
88 }
89 }
90
91 impl TryInto<u8> for HfpCodecBitId {
92 type Error = ();
try_into(self) -> Result<u8, Self::Error>93 fn try_into(self) -> Result<u8, Self::Error> {
94 Ok(self.bits().try_into().unwrap())
95 }
96 }
97
98 impl TryInto<i32> for HfpCodecBitId {
99 type Error = ();
try_into(self) -> Result<i32, Self::Error>100 fn try_into(self) -> Result<i32, Self::Error> {
101 Ok(self.bits())
102 }
103 }
104
105 impl TryFrom<i32> for HfpCodecBitId {
106 type Error = ();
try_from(val: i32) -> Result<Self, Self::Error>107 fn try_from(val: i32) -> Result<Self, Self::Error> {
108 Self::from_bits(val).ok_or(())
109 }
110 }
111
112 bitflags! {
113 #[derive(Clone, Copy, Debug, Default, PartialEq)]
114 pub struct HfpCodecFormat: i32 {
115 const NONE = 0b0000;
116 const CVSD = 0b0001;
117 const MSBC_TRANSPARENT = 0b0010;
118 const MSBC = 0b0100;
119 const LC3_TRANSPARENT = 0b1000;
120 }
121 }
122
123 impl TryInto<i32> for HfpCodecFormat {
124 type Error = ();
try_into(self) -> Result<i32, Self::Error>125 fn try_into(self) -> Result<i32, Self::Error> {
126 Ok(self.bits())
127 }
128 }
129
130 impl TryFrom<i32> for HfpCodecFormat {
131 type Error = ();
try_from(val: i32) -> Result<Self, Self::Error>132 fn try_from(val: i32) -> Result<Self, Self::Error> {
133 Self::from_bits(val).ok_or(())
134 }
135 }
136
137 #[cxx::bridge(namespace = bluetooth::topshim::rust)]
138 pub mod ffi {
139 unsafe extern "C++" {
140 include!("types/raw_address.h");
141 #[namespace = ""]
142 type RawAddress = crate::btif::RawAddress;
143 }
144
145 #[derive(Debug, Copy, Clone)]
146 pub struct TelephonyDeviceStatus {
147 network_available: bool,
148 roaming: bool,
149 signal_strength: i32,
150 battery_level: i32,
151 }
152
153 #[derive(Debug, Copy, Clone)]
154 pub enum CallState {
155 Idle,
156 Incoming,
157 Dialing,
158 Alerting,
159 Active, // Only used by CLCC response
160 Held, // Only used by CLCC response
161 }
162
163 #[derive(Debug, Clone)]
164 pub struct CallInfo {
165 index: i32,
166 dir_incoming: bool,
167 state: CallState,
168 number: String,
169 }
170
171 #[derive(Debug, Copy, Clone)]
172 pub struct PhoneState {
173 num_active: i32,
174 num_held: i32,
175 state: CallState,
176 }
177
178 #[derive(Debug, Copy, Clone)]
179 pub enum CallHoldCommand {
180 ReleaseHeld,
181 ReleaseActiveAcceptHeld,
182 HoldActiveAcceptHeld,
183 // We don't support it in our telephony stack because it's not necessary for qualification.
184 // But still inform the stack about this event.
185 AddHeldToConf,
186 }
187
188 unsafe extern "C++" {
189 include!("hfp/hfp_shim.h");
190
191 type HfpIntf;
192
GetHfpProfile(btif: *const u8) -> UniquePtr<HfpIntf>193 unsafe fn GetHfpProfile(btif: *const u8) -> UniquePtr<HfpIntf>;
interop_insert_call_when_sco_start(bt_addr: RawAddress) -> bool194 unsafe fn interop_insert_call_when_sco_start(bt_addr: RawAddress) -> bool;
init(self: Pin<&mut HfpIntf>) -> i32195 fn init(self: Pin<&mut HfpIntf>) -> i32;
connect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32196 fn connect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32;
connect_audio( self: Pin<&mut HfpIntf>, bt_addr: RawAddress, sco_offload: bool, disabled_codecs: i32, ) -> i32197 fn connect_audio(
198 self: Pin<&mut HfpIntf>,
199 bt_addr: RawAddress,
200 sco_offload: bool,
201 disabled_codecs: i32,
202 ) -> i32;
set_active_device(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32203 fn set_active_device(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32;
set_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> i32204 fn set_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> i32;
set_mic_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> u32205 fn set_mic_volume(self: Pin<&mut HfpIntf>, volume: i8, bt_addr: RawAddress) -> u32;
disconnect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32206 fn disconnect(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> u32;
disconnect_audio(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32207 fn disconnect_audio(self: Pin<&mut HfpIntf>, bt_addr: RawAddress) -> i32;
device_status_notification( self: Pin<&mut HfpIntf>, status: TelephonyDeviceStatus, addr: RawAddress, ) -> u32208 fn device_status_notification(
209 self: Pin<&mut HfpIntf>,
210 status: TelephonyDeviceStatus,
211 addr: RawAddress,
212 ) -> u32;
indicator_query_response( self: Pin<&mut HfpIntf>, device_status: TelephonyDeviceStatus, phone_state: PhoneState, addr: RawAddress, ) -> u32213 fn indicator_query_response(
214 self: Pin<&mut HfpIntf>,
215 device_status: TelephonyDeviceStatus,
216 phone_state: PhoneState,
217 addr: RawAddress,
218 ) -> u32;
current_calls_query_response( self: Pin<&mut HfpIntf>, call_list: &Vec<CallInfo>, addr: RawAddress, ) -> u32219 fn current_calls_query_response(
220 self: Pin<&mut HfpIntf>,
221 call_list: &Vec<CallInfo>,
222 addr: RawAddress,
223 ) -> u32;
phone_state_change( self: Pin<&mut HfpIntf>, phone_state: PhoneState, number: &String, addr: RawAddress, ) -> u32224 fn phone_state_change(
225 self: Pin<&mut HfpIntf>,
226 phone_state: PhoneState,
227 number: &String,
228 addr: RawAddress,
229 ) -> u32;
simple_at_response(self: Pin<&mut HfpIntf>, ok: bool, addr: RawAddress) -> u32230 fn simple_at_response(self: Pin<&mut HfpIntf>, ok: bool, addr: RawAddress) -> u32;
debug_dump(self: Pin<&mut HfpIntf>)231 fn debug_dump(self: Pin<&mut HfpIntf>);
cleanup(self: Pin<&mut HfpIntf>)232 fn cleanup(self: Pin<&mut HfpIntf>);
233
234 }
235 extern "Rust" {
hfp_connection_state_callback(state: u32, addr: RawAddress)236 fn hfp_connection_state_callback(state: u32, addr: RawAddress);
hfp_audio_state_callback(state: u32, addr: RawAddress)237 fn hfp_audio_state_callback(state: u32, addr: RawAddress);
hfp_volume_update_callback(volume: u8, addr: RawAddress)238 fn hfp_volume_update_callback(volume: u8, addr: RawAddress);
hfp_mic_volume_update_callback(volume: u8, addr: RawAddress)239 fn hfp_mic_volume_update_callback(volume: u8, addr: RawAddress);
hfp_vendor_specific_at_command_callback(at_string: String, addr: RawAddress)240 fn hfp_vendor_specific_at_command_callback(at_string: String, addr: RawAddress);
hfp_battery_level_update_callback(battery_level: u8, addr: RawAddress)241 fn hfp_battery_level_update_callback(battery_level: u8, addr: RawAddress);
hfp_wbs_caps_update_callback(wbs_supported: bool, addr: RawAddress)242 fn hfp_wbs_caps_update_callback(wbs_supported: bool, addr: RawAddress);
hfp_swb_caps_update_callback(swb_supported: bool, addr: RawAddress)243 fn hfp_swb_caps_update_callback(swb_supported: bool, addr: RawAddress);
hfp_indicator_query_callback(addr: RawAddress)244 fn hfp_indicator_query_callback(addr: RawAddress);
hfp_current_calls_query_callback(addr: RawAddress)245 fn hfp_current_calls_query_callback(addr: RawAddress);
hfp_answer_call_callback(addr: RawAddress)246 fn hfp_answer_call_callback(addr: RawAddress);
hfp_hangup_call_callback(addr: RawAddress)247 fn hfp_hangup_call_callback(addr: RawAddress);
hfp_dial_call_callback(number: String, addr: RawAddress)248 fn hfp_dial_call_callback(number: String, addr: RawAddress);
hfp_call_hold_callback(chld: CallHoldCommand, addr: RawAddress)249 fn hfp_call_hold_callback(chld: CallHoldCommand, addr: RawAddress);
hfp_debug_dump_callback( active: bool, codec_id: u16, total_num_decoded_frames: i32, pkt_loss_ratio: f64, begin_ts: u64, end_ts: u64, pkt_status_in_hex: String, pkt_status_in_binary: String, )250 fn hfp_debug_dump_callback(
251 active: bool,
252 codec_id: u16,
253 total_num_decoded_frames: i32,
254 pkt_loss_ratio: f64,
255 begin_ts: u64,
256 end_ts: u64,
257 pkt_status_in_hex: String,
258 pkt_status_in_binary: String,
259 );
260 }
261 }
262
interop_insert_call_when_sco_start(bt_addr: RawAddress) -> bool263 pub fn interop_insert_call_when_sco_start(bt_addr: RawAddress) -> bool {
264 //Call an unsafe function in c++. This is necessary for bridge C++ interop API with floss(rust).
265 unsafe { return ffi::interop_insert_call_when_sco_start(bt_addr) }
266 }
267
268 pub type TelephonyDeviceStatus = ffi::TelephonyDeviceStatus;
269
270 impl TelephonyDeviceStatus {
new() -> Self271 pub fn new() -> Self {
272 TelephonyDeviceStatus {
273 network_available: true,
274 roaming: false,
275 signal_strength: 5,
276 battery_level: 5,
277 }
278 }
279 }
280
281 pub type CallState = ffi::CallState;
282 pub type CallInfo = ffi::CallInfo;
283 pub type PhoneState = ffi::PhoneState;
284 pub type CallHoldCommand = ffi::CallHoldCommand;
285
286 // CallState (non-primitive) cannot be directly cast to u8.
287 impl From<CallState> for u8 {
from(state: CallState) -> u8288 fn from(state: CallState) -> u8 {
289 match state {
290 CallState::Idle => 0,
291 CallState::Incoming => 1,
292 CallState::Dialing => 2,
293 CallState::Alerting => 3,
294 CallState::Active => 4,
295 CallState::Held => 5,
296 CallState { repr: 6_u8..=u8::MAX } => todo!(),
297 }
298 }
299 }
300
301 #[derive(Clone, Debug)]
302 pub enum HfpCallbacks {
303 ConnectionState(BthfConnectionState, RawAddress),
304 AudioState(BthfAudioState, RawAddress),
305 VolumeUpdate(u8, RawAddress),
306 MicVolumeUpdate(u8, RawAddress),
307 VendorSpecificAtCommand(String, RawAddress),
308 BatteryLevelUpdate(u8, RawAddress),
309 WbsCapsUpdate(bool, RawAddress),
310 SwbCapsUpdate(bool, RawAddress),
311 IndicatorQuery(RawAddress),
312 CurrentCallsQuery(RawAddress),
313 AnswerCall(RawAddress),
314 HangupCall(RawAddress),
315 DialCall(String, RawAddress),
316 CallHold(CallHoldCommand, RawAddress),
317 DebugDump(bool, u16, i32, f64, u64, u64, String, String),
318 }
319
320 pub struct HfpCallbacksDispatcher {
321 pub dispatch: Box<dyn Fn(HfpCallbacks) + Send>,
322 }
323
324 type HfpCb = Arc<Mutex<HfpCallbacksDispatcher>>;
325
326 cb_variant!(
327 HfpCb,
328 hfp_connection_state_callback -> HfpCallbacks::ConnectionState,
329 u32 -> BthfConnectionState, RawAddress);
330
331 cb_variant!(
332 HfpCb,
333 hfp_audio_state_callback -> HfpCallbacks::AudioState,
334 u32 -> BthfAudioState, RawAddress);
335
336 cb_variant!(
337 HfpCb,
338 hfp_volume_update_callback -> HfpCallbacks::VolumeUpdate,
339 u8, RawAddress);
340
341 cb_variant!(
342 HfpCb,
343 hfp_mic_volume_update_callback -> HfpCallbacks::MicVolumeUpdate,
344 u8, RawAddress);
345
346 cb_variant!(
347 HfpCb,
348 hfp_vendor_specific_at_command_callback -> HfpCallbacks::VendorSpecificAtCommand,
349 String, RawAddress);
350
351 cb_variant!(
352 HfpCb,
353 hfp_battery_level_update_callback -> HfpCallbacks::BatteryLevelUpdate,
354 u8, RawAddress);
355
356 cb_variant!(
357 HfpCb,
358 hfp_wbs_caps_update_callback -> HfpCallbacks::WbsCapsUpdate,
359 bool, RawAddress);
360
361 cb_variant!(
362 HfpCb,
363 hfp_swb_caps_update_callback -> HfpCallbacks::SwbCapsUpdate,
364 bool, RawAddress);
365
366 cb_variant!(
367 HfpCb,
368 hfp_indicator_query_callback -> HfpCallbacks::IndicatorQuery,
369 RawAddress);
370
371 cb_variant!(
372 HfpCb,
373 hfp_current_calls_query_callback -> HfpCallbacks::CurrentCallsQuery,
374 RawAddress);
375
376 cb_variant!(
377 HfpCb,
378 hfp_answer_call_callback -> HfpCallbacks::AnswerCall,
379 RawAddress);
380
381 cb_variant!(
382 HfpCb,
383 hfp_hangup_call_callback -> HfpCallbacks::HangupCall,
384 RawAddress);
385
386 cb_variant!(
387 HfpCb,
388 hfp_dial_call_callback -> HfpCallbacks::DialCall,
389 String, RawAddress);
390
391 cb_variant!(
392 HfpCb,
393 hfp_call_hold_callback -> HfpCallbacks::CallHold,
394 CallHoldCommand, RawAddress);
395
396 cb_variant!(
397 HfpCb,
398 hfp_debug_dump_callback -> HfpCallbacks::DebugDump,
399 bool, u16, i32, f64, u64, u64, String, String);
400
401 pub struct Hfp {
402 internal: cxx::UniquePtr<ffi::HfpIntf>,
403 _is_init: bool,
404 _is_enabled: bool,
405 }
406
407 // For *const u8 opaque btif
408 unsafe impl Send for Hfp {}
409
410 impl ToggleableProfile for Hfp {
is_enabled(&self) -> bool411 fn is_enabled(&self) -> bool {
412 self._is_enabled
413 }
414
enable(&mut self) -> bool415 fn enable(&mut self) -> bool {
416 self.internal.pin_mut().init();
417 self._is_enabled = true;
418 true
419 }
420
421 #[profile_enabled_or(false)]
disable(&mut self) -> bool422 fn disable(&mut self) -> bool {
423 self.internal.pin_mut().cleanup();
424 self._is_enabled = false;
425 true
426 }
427 }
428
429 impl Hfp {
new(intf: &BluetoothInterface) -> Hfp430 pub fn new(intf: &BluetoothInterface) -> Hfp {
431 let hfpif: cxx::UniquePtr<ffi::HfpIntf>;
432 unsafe {
433 hfpif = ffi::GetHfpProfile(intf.as_raw_ptr());
434 }
435
436 Hfp { internal: hfpif, _is_init: false, _is_enabled: false }
437 }
438
is_initialized(&self) -> bool439 pub fn is_initialized(&self) -> bool {
440 self._is_init
441 }
442
initialize(&mut self, callbacks: HfpCallbacksDispatcher) -> bool443 pub fn initialize(&mut self, callbacks: HfpCallbacksDispatcher) -> bool {
444 if get_dispatchers().lock().unwrap().set::<HfpCb>(Arc::new(Mutex::new(callbacks))) {
445 panic!("Tried to set dispatcher for HFP callbacks while it already exists");
446 }
447 self._is_init = true;
448 true
449 }
450
451 #[profile_enabled_or(BtStatus::NotReady)]
connect(&mut self, addr: RawAddress) -> BtStatus452 pub fn connect(&mut self, addr: RawAddress) -> BtStatus {
453 BtStatus::from(self.internal.pin_mut().connect(addr))
454 }
455
456 #[profile_enabled_or(BtStatus::NotReady.into())]
connect_audio( &mut self, addr: RawAddress, sco_offload: bool, disabled_codecs: i32, ) -> i32457 pub fn connect_audio(
458 &mut self,
459 addr: RawAddress,
460 sco_offload: bool,
461 disabled_codecs: i32,
462 ) -> i32 {
463 self.internal.pin_mut().connect_audio(addr, sco_offload, disabled_codecs)
464 }
465
466 #[profile_enabled_or(BtStatus::NotReady.into())]
set_active_device(&mut self, addr: RawAddress) -> i32467 pub fn set_active_device(&mut self, addr: RawAddress) -> i32 {
468 self.internal.pin_mut().set_active_device(addr)
469 }
470
471 #[profile_enabled_or(BtStatus::NotReady.into())]
set_volume(&mut self, volume: i8, addr: RawAddress) -> i32472 pub fn set_volume(&mut self, volume: i8, addr: RawAddress) -> i32 {
473 self.internal.pin_mut().set_volume(volume, addr)
474 }
475
476 #[profile_enabled_or(BtStatus::NotReady.into())]
set_mic_volume(&mut self, volume: i8, addr: RawAddress) -> BtStatus477 pub fn set_mic_volume(&mut self, volume: i8, addr: RawAddress) -> BtStatus {
478 BtStatus::from(self.internal.pin_mut().set_mic_volume(volume, addr))
479 }
480
481 #[profile_enabled_or(BtStatus::NotReady)]
disconnect(&mut self, addr: RawAddress) -> BtStatus482 pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus {
483 BtStatus::from(self.internal.pin_mut().disconnect(addr))
484 }
485
486 #[profile_enabled_or(BtStatus::NotReady.into())]
disconnect_audio(&mut self, addr: RawAddress) -> i32487 pub fn disconnect_audio(&mut self, addr: RawAddress) -> i32 {
488 self.internal.pin_mut().disconnect_audio(addr)
489 }
490
491 #[profile_enabled_or(BtStatus::NotReady)]
device_status_notification( &mut self, status: TelephonyDeviceStatus, addr: RawAddress, ) -> BtStatus492 pub fn device_status_notification(
493 &mut self,
494 status: TelephonyDeviceStatus,
495 addr: RawAddress,
496 ) -> BtStatus {
497 BtStatus::from(self.internal.pin_mut().device_status_notification(status, addr))
498 }
499
500 #[profile_enabled_or(BtStatus::NotReady)]
indicator_query_response( &mut self, device_status: TelephonyDeviceStatus, phone_state: PhoneState, addr: RawAddress, ) -> BtStatus501 pub fn indicator_query_response(
502 &mut self,
503 device_status: TelephonyDeviceStatus,
504 phone_state: PhoneState,
505 addr: RawAddress,
506 ) -> BtStatus {
507 BtStatus::from(self.internal.pin_mut().indicator_query_response(
508 device_status,
509 phone_state,
510 addr,
511 ))
512 }
513
514 #[profile_enabled_or(BtStatus::NotReady)]
current_calls_query_response( &mut self, call_list: &Vec<CallInfo>, addr: RawAddress, ) -> BtStatus515 pub fn current_calls_query_response(
516 &mut self,
517 call_list: &Vec<CallInfo>,
518 addr: RawAddress,
519 ) -> BtStatus {
520 BtStatus::from(self.internal.pin_mut().current_calls_query_response(call_list, addr))
521 }
522
523 #[profile_enabled_or(BtStatus::NotReady)]
phone_state_change( &mut self, phone_state: PhoneState, number: &String, addr: RawAddress, ) -> BtStatus524 pub fn phone_state_change(
525 &mut self,
526 phone_state: PhoneState,
527 number: &String,
528 addr: RawAddress,
529 ) -> BtStatus {
530 BtStatus::from(self.internal.pin_mut().phone_state_change(phone_state, number, addr))
531 }
532
533 #[profile_enabled_or(BtStatus::NotReady)]
simple_at_response(&mut self, ok: bool, addr: RawAddress) -> BtStatus534 pub fn simple_at_response(&mut self, ok: bool, addr: RawAddress) -> BtStatus {
535 BtStatus::from(self.internal.pin_mut().simple_at_response(ok, addr))
536 }
537
538 #[profile_enabled_or]
debug_dump(&mut self)539 pub fn debug_dump(&mut self) {
540 self.internal.pin_mut().debug_dump();
541 }
542
543 #[profile_enabled_or(false)]
cleanup(&mut self) -> bool544 pub fn cleanup(&mut self) -> bool {
545 self.internal.pin_mut().cleanup();
546 true
547 }
548 }
549