• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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