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