1 use crate::btif::{BluetoothInterface, BtStatus, RawAddress, ToggleableProfile}; 2 use crate::topstack::get_dispatchers; 3 4 use bitflags::bitflags; 5 use num_derive::{FromPrimitive, ToPrimitive}; 6 use num_traits::cast::FromPrimitive; 7 use std::sync::{Arc, Mutex}; 8 use topshim_macros::{cb_variant, profile_enabled_or, profile_enabled_or_default}; 9 10 use log::warn; 11 12 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] 13 #[repr(u32)] 14 pub enum BtavConnectionState { 15 Disconnected = 0, 16 Connecting, 17 Connected, 18 Disconnecting, 19 } 20 21 impl From<u32> for BtavConnectionState { from(item: u32) -> Self22 fn from(item: u32) -> Self { 23 BtavConnectionState::from_u32(item).unwrap() 24 } 25 } 26 27 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)] 28 #[repr(u32)] 29 pub enum BtavAudioState { 30 RemoteSuspend = 0, 31 Stopped, 32 Started, 33 } 34 35 impl From<u32> for BtavAudioState { from(item: u32) -> Self36 fn from(item: u32) -> Self { 37 BtavAudioState::from_u32(item).unwrap() 38 } 39 } 40 41 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)] 42 #[repr(u32)] 43 pub enum A2dpCodecIndex { 44 SrcSbc = 0, 45 SrcAac, 46 SrcAptx, 47 SrcAptxHD, 48 SrcLdac, 49 SinkSbc, 50 SinkAac, 51 SinkLdac, 52 Max, 53 } 54 55 impl A2dpCodecIndex { 56 pub const SRC_MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc; 57 pub const SRC_MAX: A2dpCodecIndex = A2dpCodecIndex::SinkSbc; 58 pub const SINK_MIN: A2dpCodecIndex = A2dpCodecIndex::SinkSbc; 59 pub const SINK_MAX: A2dpCodecIndex = A2dpCodecIndex::Max; 60 pub const MAX: A2dpCodecIndex = A2dpCodecIndex::Max; 61 pub const MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc; 62 } 63 64 impl From<i32> for A2dpCodecIndex { from(item: i32) -> Self65 fn from(item: i32) -> Self { 66 A2dpCodecIndex::from_i32(item).unwrap_or_else(|| A2dpCodecIndex::MIN) 67 } 68 } 69 70 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)] 71 #[repr(i32)] 72 pub enum A2dpCodecPriority { 73 Disabled = -1, 74 Default = 0, 75 Highest = 1_000_000, 76 } 77 78 impl From<i32> for A2dpCodecPriority { from(item: i32) -> Self79 fn from(item: i32) -> Self { 80 A2dpCodecPriority::from_i32(item).unwrap_or_else(|| A2dpCodecPriority::Default) 81 } 82 } 83 84 #[derive(Debug)] 85 pub struct A2dpError { 86 /// Standard BT status come from a function return or the cloest approximation to the real 87 /// error. 88 pub status: BtStatus, 89 /// An additional value to help explain the error. In the A2DP context, this is often referring 90 /// to the BTA_AV_XXX status. 91 pub error: i32, 92 /// An optional error message that the lower layer wants to deliver. 93 pub error_message: Option<String>, 94 } 95 96 bitflags! { 97 pub struct A2dpCodecSampleRate: i32 { 98 const RATE_NONE = 0x0; 99 const RATE_44100 = 0x01; 100 const RATE_48000 = 0x02; 101 const RATE_88200 = 0x04; 102 const RATE_96000 = 0x08; 103 const RATE_176400 = 0x10; 104 const RATE_192000 = 0x20; 105 const RATE_16000 = 0x40; 106 const RATE_24000 = 0x80; 107 } 108 } 109 110 impl A2dpCodecSampleRate { validate_bits(val: i32) -> bool111 pub fn validate_bits(val: i32) -> bool { 112 val <= A2dpCodecSampleRate::all().bits() 113 } 114 } 115 116 bitflags! { 117 pub struct A2dpCodecBitsPerSample: i32 { 118 const SAMPLE_NONE = 0x0; 119 const SAMPLE_16 = 0x01; 120 const SAMPLE_24 = 0x02; 121 const SAMPLE_32 = 0x04; 122 } 123 } 124 125 impl A2dpCodecBitsPerSample { validate_bits(val: i32) -> bool126 pub fn validate_bits(val: i32) -> bool { 127 val <= A2dpCodecBitsPerSample::all().bits() 128 } 129 } 130 131 bitflags! { 132 pub struct A2dpCodecChannelMode: i32 { 133 const MODE_NONE = 0x0; 134 const MODE_MONO = 0x01; 135 const MODE_STEREO = 0x02; 136 } 137 } 138 139 impl A2dpCodecChannelMode { validate_bits(val: i32) -> bool140 pub fn validate_bits(val: i32) -> bool { 141 val <= A2dpCodecChannelMode::all().bits() 142 } 143 } 144 145 #[cxx::bridge(namespace = bluetooth::topshim::rust)] 146 pub mod ffi { 147 unsafe extern "C++" { 148 include!("gd/rust/topshim/common/type_alias.h"); 149 type RawAddress = crate::btif::RawAddress; 150 } 151 152 #[derive(Debug, Copy, Clone)] 153 pub struct A2dpCodecConfig { 154 pub codec_type: i32, 155 pub codec_priority: i32, 156 pub sample_rate: i32, 157 pub bits_per_sample: i32, 158 pub channel_mode: i32, 159 pub codec_specific_1: i64, 160 pub codec_specific_2: i64, 161 pub codec_specific_3: i64, 162 pub codec_specific_4: i64, 163 } 164 165 #[derive(Debug, Default)] 166 pub struct RustPresentationPosition { 167 remote_delay_report_ns: u64, 168 total_bytes_read: u64, 169 data_position_sec: i64, 170 data_position_nsec: i32, 171 } 172 173 #[derive(Debug)] 174 pub struct A2dpError<'a> { 175 status: u32, 176 error_code: u8, 177 error_msg: &'a CxxString, 178 } 179 180 unsafe extern "C++" { 181 include!("btav/btav_shim.h"); 182 include!("btav_sink/btav_sink_shim.h"); 183 184 type A2dpIntf; 185 type A2dpSinkIntf; 186 GetA2dpProfile(btif: *const u8) -> UniquePtr<A2dpIntf>187 unsafe fn GetA2dpProfile(btif: *const u8) -> UniquePtr<A2dpIntf>; 188 init(self: &A2dpIntf) -> i32189 fn init(self: &A2dpIntf) -> i32; connect(self: &A2dpIntf, bt_addr: RawAddress) -> u32190 fn connect(self: &A2dpIntf, bt_addr: RawAddress) -> u32; disconnect(self: &A2dpIntf, bt_addr: RawAddress) -> u32191 fn disconnect(self: &A2dpIntf, bt_addr: RawAddress) -> u32; set_silence_device(self: &A2dpIntf, bt_addr: RawAddress, silent: bool) -> i32192 fn set_silence_device(self: &A2dpIntf, bt_addr: RawAddress, silent: bool) -> i32; set_active_device(self: &A2dpIntf, bt_addr: RawAddress) -> i32193 fn set_active_device(self: &A2dpIntf, bt_addr: RawAddress) -> i32; config_codec( self: &A2dpIntf, bt_addr: RawAddress, codec_preferences: Vec<A2dpCodecConfig>, ) -> i32194 fn config_codec( 195 self: &A2dpIntf, 196 bt_addr: RawAddress, 197 codec_preferences: Vec<A2dpCodecConfig>, 198 ) -> i32; set_audio_config(self: &A2dpIntf, config: A2dpCodecConfig) -> bool199 fn set_audio_config(self: &A2dpIntf, config: A2dpCodecConfig) -> bool; start_audio_request(self: &A2dpIntf) -> bool200 fn start_audio_request(self: &A2dpIntf) -> bool; stop_audio_request(self: &A2dpIntf) -> bool201 fn stop_audio_request(self: &A2dpIntf) -> bool; suspend_audio_request(self: &A2dpIntf) -> bool202 fn suspend_audio_request(self: &A2dpIntf) -> bool; cleanup(self: &A2dpIntf)203 fn cleanup(self: &A2dpIntf); get_presentation_position(self: &A2dpIntf) -> RustPresentationPosition204 fn get_presentation_position(self: &A2dpIntf) -> RustPresentationPosition; 205 // A2dp sink functions 206 GetA2dpSinkProfile(btif: *const u8) -> UniquePtr<A2dpSinkIntf>207 unsafe fn GetA2dpSinkProfile(btif: *const u8) -> UniquePtr<A2dpSinkIntf>; 208 init(self: &A2dpSinkIntf) -> i32209 fn init(self: &A2dpSinkIntf) -> i32; connect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32210 fn connect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32; disconnect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32211 fn disconnect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32; set_active_device(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32212 fn set_active_device(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32; cleanup(self: &A2dpSinkIntf)213 fn cleanup(self: &A2dpSinkIntf); 214 } 215 extern "Rust" { connection_state_callback(addr: RawAddress, state: u32, error: A2dpError)216 fn connection_state_callback(addr: RawAddress, state: u32, error: A2dpError); audio_state_callback(addr: RawAddress, state: u32)217 fn audio_state_callback(addr: RawAddress, state: u32); audio_config_callback( addr: RawAddress, codec_config: A2dpCodecConfig, codecs_local_capabilities: &Vec<A2dpCodecConfig>, codecs_selectable_capabilities: &Vec<A2dpCodecConfig>, )218 fn audio_config_callback( 219 addr: RawAddress, 220 codec_config: A2dpCodecConfig, 221 codecs_local_capabilities: &Vec<A2dpCodecConfig>, 222 codecs_selectable_capabilities: &Vec<A2dpCodecConfig>, 223 ); mandatory_codec_preferred_callback(addr: RawAddress)224 fn mandatory_codec_preferred_callback(addr: RawAddress); 225 226 // Currently only by qualification tests. sink_audio_config_callback(addr: RawAddress, sample_rate: u32, channel_count: u8)227 fn sink_audio_config_callback(addr: RawAddress, sample_rate: u32, channel_count: u8); sink_connection_state_callback(addr: RawAddress, state: u32, error: A2dpError)228 fn sink_connection_state_callback(addr: RawAddress, state: u32, error: A2dpError); sink_audio_state_callback(addr: RawAddress, state: u32)229 fn sink_audio_state_callback(addr: RawAddress, state: u32); 230 } 231 } 232 233 pub type A2dpCodecConfig = ffi::A2dpCodecConfig; 234 pub type PresentationPosition = ffi::RustPresentationPosition; 235 pub type FfiA2dpError<'a> = ffi::A2dpError<'a>; 236 237 impl Default for A2dpCodecConfig { default() -> A2dpCodecConfig238 fn default() -> A2dpCodecConfig { 239 A2dpCodecConfig { 240 codec_type: 0, 241 codec_priority: 0, 242 sample_rate: 0, 243 bits_per_sample: 0, 244 channel_mode: 0, 245 codec_specific_1: 0, 246 codec_specific_2: 0, 247 codec_specific_3: 0, 248 codec_specific_4: 0, 249 } 250 } 251 } 252 253 impl<'a> Into<A2dpError> for FfiA2dpError<'a> { into(self) -> A2dpError254 fn into(self) -> A2dpError { 255 A2dpError { 256 status: self.status.into(), 257 error: self.error_code as i32, 258 error_message: if self.error_msg == "" { 259 None 260 } else { 261 Some(self.error_msg.to_string()) 262 }, 263 } 264 } 265 } 266 267 #[derive(Debug)] 268 pub enum A2dpCallbacks { 269 ConnectionState(RawAddress, BtavConnectionState, A2dpError), 270 AudioState(RawAddress, BtavAudioState), 271 AudioConfig(RawAddress, A2dpCodecConfig, Vec<A2dpCodecConfig>, Vec<A2dpCodecConfig>), 272 MandatoryCodecPreferred(RawAddress), 273 } 274 275 pub struct A2dpCallbacksDispatcher { 276 pub dispatch: Box<dyn Fn(A2dpCallbacks) + Send>, 277 } 278 279 type A2dpCb = Arc<Mutex<A2dpCallbacksDispatcher>>; 280 281 cb_variant!(A2dpCb, connection_state_callback -> A2dpCallbacks::ConnectionState, 282 RawAddress, u32 -> BtavConnectionState, FfiA2dpError -> A2dpError,{ 283 let _2 = _2.into(); 284 }); 285 286 cb_variant!(A2dpCb, audio_state_callback -> A2dpCallbacks::AudioState, RawAddress, u32 -> BtavAudioState); 287 288 cb_variant!(A2dpCb, mandatory_codec_preferred_callback -> A2dpCallbacks::MandatoryCodecPreferred, RawAddress); 289 290 cb_variant!(A2dpCb, audio_config_callback -> A2dpCallbacks::AudioConfig, 291 RawAddress, A2dpCodecConfig, &Vec<A2dpCodecConfig>, &Vec<A2dpCodecConfig>, { 292 let _2: Vec<A2dpCodecConfig> = _2.to_vec(); 293 let _3: Vec<A2dpCodecConfig> = _3.to_vec(); 294 }); 295 296 pub struct A2dp { 297 internal: cxx::UniquePtr<ffi::A2dpIntf>, 298 _is_init: bool, 299 _is_enabled: bool, 300 } 301 302 // For *const u8 opaque btif 303 unsafe impl Send for A2dp {} 304 305 impl ToggleableProfile for A2dp { is_enabled(&self) -> bool306 fn is_enabled(&self) -> bool { 307 self._is_enabled 308 } 309 enable(&mut self) -> bool310 fn enable(&mut self) -> bool { 311 self.internal.init(); 312 self._is_enabled = true; 313 true 314 } 315 316 #[profile_enabled_or(false)] disable(&mut self) -> bool317 fn disable(&mut self) -> bool { 318 self.internal.cleanup(); 319 self._is_enabled = false; 320 true 321 } 322 } 323 324 impl A2dp { new(intf: &BluetoothInterface) -> A2dp325 pub fn new(intf: &BluetoothInterface) -> A2dp { 326 let a2dpif: cxx::UniquePtr<ffi::A2dpIntf>; 327 unsafe { 328 a2dpif = ffi::GetA2dpProfile(intf.as_raw_ptr()); 329 } 330 331 A2dp { internal: a2dpif, _is_init: false, _is_enabled: false } 332 } 333 is_initialized(&self) -> bool334 pub fn is_initialized(&self) -> bool { 335 self._is_init 336 } 337 initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool338 pub fn initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool { 339 if get_dispatchers().lock().unwrap().set::<A2dpCb>(Arc::new(Mutex::new(callbacks))) { 340 panic!("Tried to set dispatcher for A2dp callbacks while it already exists"); 341 } 342 343 if self._is_init { 344 warn!("A2dp has already been initialized"); 345 return false; 346 } 347 348 true 349 } 350 351 #[profile_enabled_or(BtStatus::NotReady)] connect(&mut self, addr: RawAddress) -> BtStatus352 pub fn connect(&mut self, addr: RawAddress) -> BtStatus { 353 BtStatus::from(self.internal.connect(addr)) 354 } 355 356 #[profile_enabled_or] set_active_device(&mut self, addr: RawAddress)357 pub fn set_active_device(&mut self, addr: RawAddress) { 358 self.internal.set_active_device(addr); 359 } 360 361 #[profile_enabled_or(BtStatus::NotReady)] disconnect(&mut self, addr: RawAddress) -> BtStatus362 pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus { 363 BtStatus::from(self.internal.disconnect(addr)) 364 } 365 366 #[profile_enabled_or] set_audio_config(&self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32)367 pub fn set_audio_config(&self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32) { 368 let config = 369 A2dpCodecConfig { sample_rate, bits_per_sample, channel_mode, ..Default::default() }; 370 self.internal.set_audio_config(config); 371 } 372 373 #[profile_enabled_or(false)] start_audio_request(&self) -> bool374 pub fn start_audio_request(&self) -> bool { 375 self.internal.start_audio_request() 376 } 377 378 #[profile_enabled_or] stop_audio_request(&self)379 pub fn stop_audio_request(&self) { 380 self.internal.stop_audio_request(); 381 } 382 383 #[profile_enabled_or] suspend_audio_request(&self)384 pub fn suspend_audio_request(&self) { 385 self.internal.suspend_audio_request(); 386 } 387 388 #[profile_enabled_or_default] get_presentation_position(&self) -> PresentationPosition389 pub fn get_presentation_position(&self) -> PresentationPosition { 390 self.internal.get_presentation_position() 391 } 392 } 393 394 #[derive(Debug)] 395 pub enum A2dpSinkCallbacks { 396 ConnectionState(RawAddress, BtavConnectionState, A2dpError), 397 AudioState(RawAddress, BtavAudioState), 398 AudioConfig(RawAddress, u32, u8), 399 } 400 401 pub struct A2dpSinkCallbacksDispatcher { 402 pub dispatch: Box<dyn Fn(A2dpSinkCallbacks) + Send>, 403 } 404 405 type A2dpSinkCb = Arc<Mutex<A2dpSinkCallbacksDispatcher>>; 406 407 cb_variant!(A2dpSinkCb, sink_connection_state_callback -> A2dpSinkCallbacks::ConnectionState, 408 RawAddress, u32 -> BtavConnectionState, FfiA2dpError -> A2dpError,{ 409 let _2 = _2.into(); 410 }); 411 412 cb_variant!(A2dpSinkCb, sink_audio_state_callback -> A2dpSinkCallbacks::AudioState, RawAddress, u32 -> BtavAudioState); 413 414 cb_variant!(A2dpSinkCb, sink_audio_config_callback -> A2dpSinkCallbacks::AudioConfig, RawAddress, u32, u8); 415 416 pub struct A2dpSink { 417 internal: cxx::UniquePtr<ffi::A2dpSinkIntf>, 418 _is_init: bool, 419 _is_enabled: bool, 420 } 421 422 // For *const u8 opaque btif 423 unsafe impl Send for A2dpSink {} 424 425 impl ToggleableProfile for A2dpSink { is_enabled(&self) -> bool426 fn is_enabled(&self) -> bool { 427 self._is_enabled 428 } 429 enable(&mut self) -> bool430 fn enable(&mut self) -> bool { 431 self.internal.init(); 432 self._is_enabled = true; 433 true 434 } 435 436 #[profile_enabled_or(false)] disable(&mut self) -> bool437 fn disable(&mut self) -> bool { 438 self.internal.cleanup(); 439 self._is_enabled = false; 440 true 441 } 442 } 443 444 impl A2dpSink { new(intf: &BluetoothInterface) -> A2dpSink445 pub fn new(intf: &BluetoothInterface) -> A2dpSink { 446 let a2dp_sink: cxx::UniquePtr<ffi::A2dpSinkIntf>; 447 unsafe { 448 a2dp_sink = ffi::GetA2dpSinkProfile(intf.as_raw_ptr()); 449 } 450 451 A2dpSink { internal: a2dp_sink, _is_init: false, _is_enabled: false } 452 } 453 is_initialized(&self) -> bool454 pub fn is_initialized(&self) -> bool { 455 self._is_init 456 } 457 initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool458 pub fn initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool { 459 if get_dispatchers().lock().unwrap().set::<A2dpSinkCb>(Arc::new(Mutex::new(callbacks))) { 460 panic!("Tried to set dispatcher for A2dp Sink Callbacks while it already exists"); 461 } 462 self._is_init = true; 463 true 464 } 465 466 #[profile_enabled_or] connect(&mut self, bt_addr: RawAddress)467 pub fn connect(&mut self, bt_addr: RawAddress) { 468 self.internal.connect(bt_addr); 469 } 470 471 #[profile_enabled_or] disconnect(&mut self, bt_addr: RawAddress)472 pub fn disconnect(&mut self, bt_addr: RawAddress) { 473 self.internal.disconnect(bt_addr); 474 } 475 476 #[profile_enabled_or] set_active_device(&mut self, bt_addr: RawAddress)477 pub fn set_active_device(&mut self, bt_addr: RawAddress) { 478 self.internal.set_active_device(bt_addr); 479 } 480 481 #[profile_enabled_or] cleanup(&mut self)482 pub fn cleanup(&mut self) {} 483 } 484 485 #[cfg(test)] 486 mod tests { 487 use super::*; 488 489 #[test] validate_sample_rate()490 fn validate_sample_rate() { 491 assert!(!A2dpCodecSampleRate::validate_bits(256)); 492 assert!(A2dpCodecSampleRate::validate_bits(2 + 32 + 128)); 493 } 494 495 #[test] validate_bits_per_sample()496 fn validate_bits_per_sample() { 497 assert!(!A2dpCodecBitsPerSample::validate_bits(8)); 498 assert!(A2dpCodecBitsPerSample::validate_bits(1 + 4)); 499 } 500 501 #[test] validate_channel_mode()502 fn validate_channel_mode() { 503 assert!(!A2dpCodecChannelMode::validate_bits(4)); 504 assert!(A2dpCodecChannelMode::validate_bits(1 + 2)); 505 } 506 } 507