• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::bindings::root as bindings;
2 use crate::btif::{BluetoothInterface, BtStatus, RawAddress, SupportedProfiles, ToggleableProfile};
3 use crate::ccall;
4 use crate::profiles::hf_client::bindings::bthf_client_interface_t;
5 use crate::topstack::get_dispatchers;
6 use crate::utils::{LTCheckedPtr, LTCheckedPtrMut};
7 
8 use num_derive::{FromPrimitive, ToPrimitive};
9 use num_traits::cast::FromPrimitive;
10 use std::fmt::{Debug, Formatter, Result};
11 use std::sync::{Arc, Mutex};
12 use topshim_macros::{cb_variant, log_args, profile_enabled_or};
13 
14 use log::warn;
15 
16 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
17 #[repr(u32)]
18 /// Represents the various connection states a Hands-Free client would go through.
19 pub enum BthfClientConnectionState {
20     Disconnected = 0,
21     Connecting,
22     Connected,
23     SlcConnected,
24     Disconnecting,
25 }
26 
27 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
28 #[repr(u32)]
29 /// Represents the various connection states the audio channel for a
30 /// Hands-Free client would go through.
31 pub enum BthfClientAudioState {
32     Disconnected = 0,
33     Connecting,
34     Connected,
35     Disconnecting,
36 }
37 
38 impl From<bindings::bthf_client_connection_state_t> for BthfClientConnectionState {
from(item: bindings::bthf_client_connection_state_t) -> Self39     fn from(item: bindings::bthf_client_connection_state_t) -> Self {
40         BthfClientConnectionState::from_u32(item).unwrap_or(BthfClientConnectionState::Disconnected)
41     }
42 }
43 
44 impl From<bindings::bthf_client_audio_state_t> for BthfClientAudioState {
from(item: bindings::bthf_client_audio_state_t) -> Self45     fn from(item: bindings::bthf_client_audio_state_t) -> Self {
46         BthfClientAudioState::from_u32(item).unwrap_or(BthfClientAudioState::Disconnected)
47     }
48 }
49 
50 #[derive(Debug)]
51 pub enum BthfClientCallbacks {
52     /// Callback invoked when the connection state of the client changes.
53     /// Params (Address, Connection state, peer features, child features)
54     ConnectionState(RawAddress, BthfClientConnectionState, u32, u32),
55 
56     /// Callback invoked when the audio connection state of the client changes.
57     AudioState(RawAddress, BthfClientAudioState),
58     // TODO(b/262264556): Incomplete implementation. Other callbacks will be implemented if necessary.
59 }
60 
61 pub struct BthfClientCallbacksDispatcher {
62     pub dispatch: Box<dyn Fn(BthfClientCallbacks) + Send>,
63 }
64 
65 impl Debug for BthfClientCallbacksDispatcher {
fmt(&self, f: &mut Formatter<'_>) -> Result66     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
67         write!(f, "BthfClientCallbacksDispatcher {{}}")
68     }
69 }
70 
71 type BthfClientCb = Arc<Mutex<BthfClientCallbacksDispatcher>>;
72 
73 cb_variant!(
74     BthfClientCb,
75     hf_client_connection_state_cb -> BthfClientCallbacks::ConnectionState,
76     *const RawAddress,
77     bindings::bthf_client_connection_state_t -> BthfClientConnectionState,
78     u32, u32, {
79         let _0 = unsafe { *_0 };
80     }
81 );
82 
83 cb_variant!(
84     BthfClientCb,
85     hf_client_audio_state_cb -> BthfClientCallbacks::AudioState,
86     *const RawAddress,
87     bindings::bthf_client_audio_state_t -> BthfClientAudioState,{
88         let _0 = unsafe { *_0 };
89     }
90 );
91 
92 struct RawHfClientWrapper {
93     raw: *const bindings::bthf_client_interface_t,
94 }
95 
96 unsafe impl Send for RawHfClientWrapper {}
97 
98 pub struct HfClient {
99     internal: RawHfClientWrapper,
100     is_init: bool,
101     is_enabled: bool,
102     callbacks: Option<Box<bindings::bthf_client_callbacks_t>>,
103 }
104 
105 impl ToggleableProfile for HfClient {
is_enabled(&self) -> bool106     fn is_enabled(&self) -> bool {
107         self.is_enabled
108     }
109 
enable(&mut self) -> bool110     fn enable(&mut self) -> bool {
111         let cb_ptr = LTCheckedPtrMut::from(self.callbacks.as_mut().unwrap());
112 
113         let init = ccall!(self, init, cb_ptr.into());
114         self.is_init = BtStatus::from(init) == BtStatus::Success;
115         self.is_enabled = self.is_init;
116         true
117     }
118 
119     #[profile_enabled_or(false)]
disable(&mut self) -> bool120     fn disable(&mut self) -> bool {
121         ccall!(self, cleanup);
122         self.is_enabled = false;
123         true
124     }
125 }
126 
127 impl HfClient {
128     #[log_args]
new(intf: &BluetoothInterface) -> HfClient129     pub fn new(intf: &BluetoothInterface) -> HfClient {
130         let r = intf.get_profile_interface(SupportedProfiles::HfClient);
131         HfClient {
132             internal: RawHfClientWrapper { raw: r as *const bthf_client_interface_t },
133             is_init: false,
134             is_enabled: false,
135             callbacks: None,
136         }
137     }
138 
139     #[log_args]
is_initialized(&self) -> bool140     pub fn is_initialized(&self) -> bool {
141         self.is_init
142     }
143 
144     #[log_args]
initialize(&mut self, callbacks: BthfClientCallbacksDispatcher) -> bool145     pub fn initialize(&mut self, callbacks: BthfClientCallbacksDispatcher) -> bool {
146         // Register dispatcher
147         if get_dispatchers().lock().unwrap().set::<BthfClientCb>(Arc::new(Mutex::new(callbacks))) {
148             panic!("Tried to set dispatcher for BthfClienCallbacks but it already existed");
149         }
150 
151         let callbacks = Box::new(bindings::bthf_client_callbacks_t {
152             // TODO(b/262264556): Incomplete implementation. Only necessary callbacks are implemented currently.
153             size: 22 * 8,
154             connection_state_cb: Some(hf_client_connection_state_cb),
155             audio_state_cb: Some(hf_client_audio_state_cb),
156             vr_cmd_cb: None,
157             network_state_cb: None,
158             network_roaming_cb: None,
159             network_signal_cb: None,
160             battery_level_cb: None,
161             current_operator_cb: None,
162             call_cb: None,
163             callsetup_cb: None,
164             callheld_cb: None,
165             resp_and_hold_cb: None,
166             clip_cb: None,
167             call_waiting_cb: None,
168             current_calls_cb: None,
169             volume_change_cb: None,
170             cmd_complete_cb: None,
171             subscriber_info_cb: None,
172             in_band_ring_tone_cb: None,
173             last_voice_tag_number_callback: None,
174             ring_indication_cb: None,
175             unknown_event_cb: None,
176         });
177         self.callbacks = Some(callbacks);
178 
179         true
180     }
181 
182     #[log_args]
183     #[profile_enabled_or(BtStatus::NotReady)]
connect(&self, addr: RawAddress) -> BtStatus184     pub fn connect(&self, addr: RawAddress) -> BtStatus {
185         let addr_ptr = LTCheckedPtr::from_ref(&addr);
186         BtStatus::from(ccall!(self, connect, addr_ptr.into()))
187     }
188 
189     #[log_args]
190     #[profile_enabled_or(BtStatus::NotReady)]
disconnect(&self, addr: RawAddress) -> BtStatus191     pub fn disconnect(&self, addr: RawAddress) -> BtStatus {
192         let addr_ptr = LTCheckedPtr::from_ref(&addr);
193         BtStatus::from(ccall!(self, disconnect, addr_ptr.into()))
194     }
195 
196     #[log_args]
197     #[profile_enabled_or(BtStatus::NotReady)]
connect_audio(&mut self, addr: RawAddress) -> BtStatus198     pub fn connect_audio(&mut self, addr: RawAddress) -> BtStatus {
199         let addr_ptr = LTCheckedPtr::from_ref(&addr);
200         BtStatus::from(ccall!(self, connect_audio, addr_ptr.into()))
201     }
202 
203     #[log_args]
204     #[profile_enabled_or(BtStatus::NotReady)]
disconnect_audio(&mut self, addr: RawAddress) -> BtStatus205     pub fn disconnect_audio(&mut self, addr: RawAddress) -> BtStatus {
206         let addr_ptr = LTCheckedPtr::from_ref(&addr);
207         BtStatus::from(ccall!(self, disconnect_audio, addr_ptr.into()))
208     }
209 
210     #[log_args]
211     #[profile_enabled_or]
cleanup(&mut self)212     pub fn cleanup(&mut self) {
213         ccall!(self, cleanup)
214     }
215     // TODO(b/262264556): Incomplete API implementation. Only necessary APIs are implemented currently.
216 }
217