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