• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::btif::{BluetoothInterface, BtStatus, RawAddress, SupportedProfiles, ToggleableProfile};
2 use crate::topstack::get_dispatchers;
3 
4 use std::fmt::{Debug, Formatter, Result};
5 use std::sync::{Arc, Mutex};
6 use topshim_macros::{cb_variant, log_args, profile_enabled_or};
7 
8 use crate::bindings::root as bindings;
9 use crate::ccall;
10 use crate::utils::LTCheckedPtrMut;
11 
12 use log::warn;
13 
14 #[derive(Debug, Default)]
15 pub struct PlayerMetadata {
16     pub title: String,
17     pub artist: String,
18     pub album: String,
19     pub length_us: i64,
20 }
21 
22 #[cxx::bridge(namespace = bluetooth::topshim::rust)]
23 pub mod ffi {
24     unsafe extern "C++" {
25         include!("types/raw_address.h");
26         #[namespace = ""]
27         type RawAddress = crate::btif::RawAddress;
28     }
29 
30     unsafe extern "C++" {
31         include!("btav/btav_shim.h");
32         include!("btav_sink/btav_sink_shim.h");
33 
34         type AvrcpIntf;
35 
GetAvrcpProfile(btif: *const u8) -> UniquePtr<AvrcpIntf>36         unsafe fn GetAvrcpProfile(btif: *const u8) -> UniquePtr<AvrcpIntf>;
37 
init(self: Pin<&mut AvrcpIntf>)38         fn init(self: Pin<&mut AvrcpIntf>);
cleanup(self: Pin<&mut AvrcpIntf>)39         fn cleanup(self: Pin<&mut AvrcpIntf>);
connect(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress) -> u3240         fn connect(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress) -> u32;
disconnect(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress) -> u3241         fn disconnect(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress) -> u32;
set_volume(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress, volume: i8)42         fn set_volume(self: Pin<&mut AvrcpIntf>, bt_addr: RawAddress, volume: i8);
set_playback_status(self: Pin<&mut AvrcpIntf>, status: &String)43         fn set_playback_status(self: Pin<&mut AvrcpIntf>, status: &String);
set_position(self: Pin<&mut AvrcpIntf>, position_us: i64)44         fn set_position(self: Pin<&mut AvrcpIntf>, position_us: i64);
set_metadata( self: Pin<&mut AvrcpIntf>, title: &String, artist: &String, album: &String, length_us: i64, )45         fn set_metadata(
46             self: Pin<&mut AvrcpIntf>,
47             title: &String,
48             artist: &String,
49             album: &String,
50             length_us: i64,
51         );
add_player(self: Pin<&mut AvrcpIntf>, name: &String, browsing_supported: bool) -> u1652         fn add_player(self: Pin<&mut AvrcpIntf>, name: &String, browsing_supported: bool) -> u16;
53 
54     }
55     extern "Rust" {
avrcp_device_connected(addr: RawAddress, absolute_volume_enabled: bool)56         fn avrcp_device_connected(addr: RawAddress, absolute_volume_enabled: bool);
avrcp_device_disconnected(addr: RawAddress)57         fn avrcp_device_disconnected(addr: RawAddress);
avrcp_absolute_volume_update(volume: u8)58         fn avrcp_absolute_volume_update(volume: u8);
avrcp_send_key_event(key: u8, state: u8)59         fn avrcp_send_key_event(key: u8, state: u8);
avrcp_set_active_device(addr: RawAddress)60         fn avrcp_set_active_device(addr: RawAddress);
61     }
62 }
63 
64 #[derive(Debug)]
65 pub enum AvrcpCallbacks {
66     /// Emitted when avrcp completes connection.
67     /// Params: Device address, Absolute Volume Enabled
68     AvrcpDeviceConnected(RawAddress, bool),
69     /// Emitted when avrcp device disconnected.
70     /// Params: Device address
71     AvrcpDeviceDisconnected(RawAddress),
72     /// Emitted when the absolute volume of a connected AVRCP device changed
73     /// Params: Volume
74     AvrcpAbsoluteVolumeUpdate(u8),
75     /// Emitted when received a key event from a connected AVRCP device
76     /// Params: Key, Value
77     AvrcpSendKeyEvent(u8, u8),
78     /// Emitted when received request from AVRCP interface to set a device to active
79     /// Params: Device address
80     AvrcpSetActiveDevice(RawAddress),
81 }
82 
83 pub struct AvrcpCallbacksDispatcher {
84     pub dispatch: Box<dyn Fn(AvrcpCallbacks) + Send>,
85 }
86 
87 impl Debug for AvrcpCallbacksDispatcher {
fmt(&self, f: &mut Formatter<'_>) -> Result88     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
89         write!(f, "AvrcpCallbacksDispatcher {{}}")
90     }
91 }
92 
93 type AvrcpCb = Arc<Mutex<AvrcpCallbacksDispatcher>>;
94 
95 cb_variant!(
96     AvrcpCb,
97     avrcp_device_connected -> AvrcpCallbacks::AvrcpDeviceConnected,
98     RawAddress, bool);
99 
100 cb_variant!(
101     AvrcpCb,
102     avrcp_device_disconnected -> AvrcpCallbacks::AvrcpDeviceDisconnected,
103     RawAddress);
104 
105 cb_variant!(
106     AvrcpCb,
107     avrcp_absolute_volume_update -> AvrcpCallbacks::AvrcpAbsoluteVolumeUpdate,
108     u8, {}
109 );
110 
111 cb_variant!(
112     AvrcpCb,
113     avrcp_send_key_event -> AvrcpCallbacks::AvrcpSendKeyEvent,
114     u8, u8, {}
115 );
116 
117 cb_variant!(
118     AvrcpCb,
119     avrcp_set_active_device -> AvrcpCallbacks::AvrcpSetActiveDevice,
120     RawAddress);
121 
122 pub struct Avrcp {
123     internal: cxx::UniquePtr<ffi::AvrcpIntf>,
124     _is_init: bool,
125     _is_enabled: bool,
126 }
127 
128 // For *const u8 opaque btif
129 unsafe impl Send for Avrcp {}
130 
131 impl ToggleableProfile for Avrcp {
is_enabled(&self) -> bool132     fn is_enabled(&self) -> bool {
133         self._is_enabled
134     }
135 
enable(&mut self) -> bool136     fn enable(&mut self) -> bool {
137         self.internal.pin_mut().init();
138         self._is_enabled = true;
139         true
140     }
141 
142     #[profile_enabled_or(false)]
disable(&mut self) -> bool143     fn disable(&mut self) -> bool {
144         self.internal.pin_mut().cleanup();
145         self._is_enabled = false;
146         true
147     }
148 }
149 
150 impl Avrcp {
new(intf: &BluetoothInterface) -> Avrcp151     pub fn new(intf: &BluetoothInterface) -> Avrcp {
152         let avrcpif: cxx::UniquePtr<ffi::AvrcpIntf>;
153         unsafe {
154             avrcpif = ffi::GetAvrcpProfile(intf.as_raw_ptr());
155         }
156 
157         Avrcp { internal: avrcpif, _is_init: false, _is_enabled: false }
158     }
159 
160     #[log_args]
is_initialized(&self) -> bool161     pub fn is_initialized(&self) -> bool {
162         self._is_init
163     }
164 
165     #[log_args]
initialize(&mut self, callbacks: AvrcpCallbacksDispatcher) -> bool166     pub fn initialize(&mut self, callbacks: AvrcpCallbacksDispatcher) -> bool {
167         if get_dispatchers().lock().unwrap().set::<AvrcpCb>(Arc::new(Mutex::new(callbacks))) {
168             panic!("Tried to set dispatcher for Avrcp callbacks while it already exists");
169         }
170         self._is_init = true;
171         true
172     }
173 
174     #[log_args]
175     #[profile_enabled_or(BtStatus::NotReady)]
connect(&mut self, addr: RawAddress) -> BtStatus176     pub fn connect(&mut self, addr: RawAddress) -> BtStatus {
177         BtStatus::from(self.internal.pin_mut().connect(addr.into()))
178     }
179 
180     #[profile_enabled_or(BtStatus::NotReady)]
disconnect(&mut self, addr: RawAddress) -> BtStatus181     pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus {
182         BtStatus::from(self.internal.pin_mut().disconnect(addr.into()))
183     }
184 
185     #[profile_enabled_or]
set_volume(&mut self, addr: RawAddress, volume: i8)186     pub fn set_volume(&mut self, addr: RawAddress, volume: i8) {
187         self.internal.pin_mut().set_volume(addr, volume);
188     }
189 
190     #[profile_enabled_or(false)]
cleanup(&mut self) -> bool191     pub fn cleanup(&mut self) -> bool {
192         self.internal.pin_mut().cleanup();
193         true
194     }
195 
196     #[profile_enabled_or]
set_playback_status(&mut self, status: &String)197     pub fn set_playback_status(&mut self, status: &String) {
198         self.internal.pin_mut().set_playback_status(status);
199     }
200 
201     #[profile_enabled_or]
set_position(&mut self, position_us: i64)202     pub fn set_position(&mut self, position_us: i64) {
203         self.internal.pin_mut().set_position(position_us);
204     }
205 
206     #[profile_enabled_or]
set_metadata(&mut self, metadata: &PlayerMetadata)207     pub fn set_metadata(&mut self, metadata: &PlayerMetadata) {
208         self.internal.pin_mut().set_metadata(
209             &metadata.title,
210             &metadata.artist,
211             &metadata.album,
212             metadata.length_us,
213         );
214     }
215 
216     #[profile_enabled_or]
add_player(&mut self, name: &String, browsing_supported: bool)217     pub fn add_player(&mut self, name: &String, browsing_supported: bool) {
218         self.internal.pin_mut().add_player(name, browsing_supported);
219     }
220 }
221 
222 struct RawAvrcpCtrlWrapper {
223     raw: *const bindings::btrc_ctrl_interface_t,
224 }
225 
226 // Pointers unsafe due to ownership but this is a static pointer so Send is ok.
227 unsafe impl Send for RawAvrcpCtrlWrapper {}
228 
229 pub struct AvrcpCtrl {
230     internal: RawAvrcpCtrlWrapper,
231     callbacks: Option<Box<bindings::btrc_ctrl_callbacks_t>>,
232 }
233 
234 cb_variant!(AvrcpCtCb, avrcp_connection_state_cb -> AvrcpCtrlCallbacks::ConnectionState,
235 bool, bool, *const RawAddress, {
236     let _2 = unsafe { *_2 };
237 });
238 
239 cb_variant!(AvrcpCtCb, avrcp_getrcfeatures_cb -> AvrcpCtrlCallbacks::GetRCFeatures,
240 *const RawAddress, i32, {
241     let _0 = unsafe { *_0 };
242 });
243 
244 cb_variant!(AvrcpCtCb, avrcp_get_cover_art_psm_cb -> AvrcpCtrlCallbacks::GetCoverArtPsm,
245 *const RawAddress, u16, {
246     let _0 = unsafe { *_0 };
247 });
248 
249 cb_variant!(AvrcpCtCb, avrcp_passthrough_rsp_cb -> AvrcpCtrlCallbacks::PassthroughRsp,
250 *const RawAddress, i32, i32, {
251     let _0 = unsafe { *_0 };
252 });
253 
254 #[derive(Debug)]
255 pub enum AvrcpCtrlCallbacks {
256     PassthroughRsp(RawAddress, i32, i32),
257     ConnectionState(bool, bool, RawAddress),
258     GetRCFeatures(RawAddress, i32),
259     GetCoverArtPsm(RawAddress, u16),
260 }
261 
262 pub struct AvrcpCtrlCallbacksDispatcher {
263     pub dispatch: Box<dyn Fn(AvrcpCtrlCallbacks) + Send>,
264 }
265 
266 impl Debug for AvrcpCtrlCallbacksDispatcher {
fmt(&self, f: &mut Formatter<'_>) -> Result267     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
268         write!(f, "AvrcpCtrlCallbacksDispatcher {{}}")
269     }
270 }
271 
272 type AvrcpCtCb = Arc<Mutex<AvrcpCtrlCallbacksDispatcher>>;
273 
274 impl AvrcpCtrl {
275     #[log_args]
new(intf: &BluetoothInterface) -> AvrcpCtrl276     pub fn new(intf: &BluetoothInterface) -> AvrcpCtrl {
277         let r = intf.get_profile_interface(SupportedProfiles::AvrcpCtrl);
278         AvrcpCtrl {
279             internal: RawAvrcpCtrlWrapper { raw: r as *const bindings::btrc_ctrl_interface_t },
280             callbacks: None,
281         }
282     }
283 
284     #[log_args]
initialize(&mut self, callbacks: AvrcpCtrlCallbacksDispatcher) -> bool285     pub fn initialize(&mut self, callbacks: AvrcpCtrlCallbacksDispatcher) -> bool {
286         // Register dispatcher
287         if get_dispatchers().lock().unwrap().set::<AvrcpCtCb>(Arc::new(Mutex::new(callbacks))) {
288             panic!("Tried to set dispatcher for AvrcpCt Callbacks but it already existed");
289         }
290 
291         let callbacks = Box::new(bindings::btrc_ctrl_callbacks_t {
292             size: 21 * 8,
293             passthrough_rsp_cb: Some(avrcp_passthrough_rsp_cb),
294             groupnavigation_rsp_cb: None,
295             connection_state_cb: Some(avrcp_connection_state_cb),
296             getrcfeatures_cb: Some(avrcp_getrcfeatures_cb),
297             setplayerappsetting_rsp_cb: None,
298             playerapplicationsetting_cb: None,
299             playerapplicationsetting_changed_cb: None,
300             setabsvol_cmd_cb: None,
301             registernotification_absvol_cb: None,
302             track_changed_cb: None,
303             play_position_changed_cb: None,
304             play_status_changed_cb: None,
305             get_folder_items_cb: None,
306             change_folder_path_cb: None,
307             set_browsed_player_cb: None,
308             set_addressed_player_cb: None,
309             addressed_player_changed_cb: None,
310             now_playing_contents_changed_cb: None,
311             available_player_changed_cb: None,
312             get_cover_art_psm_cb: Some(avrcp_get_cover_art_psm_cb),
313         });
314 
315         self.callbacks = Some(callbacks);
316 
317         let cb_ptr = LTCheckedPtrMut::from(self.callbacks.as_mut().unwrap());
318 
319         ccall!(self, init, cb_ptr.into());
320 
321         true
322     }
323 
324     #[log_args]
send_pass_through_cmd( &mut self, addr: RawAddress, key_code: u8, key_state: u8, ) -> BtStatus325     pub fn send_pass_through_cmd(
326         &mut self,
327         addr: RawAddress,
328         key_code: u8,
329         key_state: u8,
330     ) -> BtStatus {
331         ccall!(self, send_pass_through_cmd, &addr, key_code.into(), key_state.into()).into()
332     }
333 }
334