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