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