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::convert::{TryFrom, TryInto}; 8 use std::sync::{Arc, Mutex}; 9 use topshim_macros::{cb_variant, profile_enabled_or, profile_enabled_or_default}; 10 11 use log::warn; 12 13 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd, Clone)] 14 #[repr(u32)] 15 pub enum BtavConnectionState { 16 Disconnected = 0, 17 Connecting, 18 Connected, 19 Disconnecting, 20 } 21 22 impl From<u32> for BtavConnectionState { from(item: u32) -> Self23 fn from(item: u32) -> Self { 24 BtavConnectionState::from_u32(item).unwrap() 25 } 26 } 27 28 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)] 29 #[repr(u32)] 30 pub enum BtavAudioState { 31 RemoteSuspend = 0, 32 Stopped, 33 Started, 34 } 35 36 impl From<u32> for BtavAudioState { from(item: u32) -> Self37 fn from(item: u32) -> Self { 38 BtavAudioState::from_u32(item).unwrap() 39 } 40 } 41 42 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] 43 #[repr(i32)] 44 pub enum A2dpCodecIndex { 45 SrcSbc = 0, 46 SrcAac, 47 SrcAptx, 48 SrcAptxHD, 49 SrcLdac, 50 SinkSbc, 51 SinkAac, 52 SinkLdac, 53 Max, 54 } 55 56 impl A2dpCodecIndex { 57 pub const SRC_MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc; 58 pub const SRC_MAX: A2dpCodecIndex = A2dpCodecIndex::SinkSbc; 59 pub const SINK_MIN: A2dpCodecIndex = A2dpCodecIndex::SinkSbc; 60 pub const SINK_MAX: A2dpCodecIndex = A2dpCodecIndex::Max; 61 pub const MAX: A2dpCodecIndex = A2dpCodecIndex::Max; 62 pub const MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc; 63 } 64 65 impl From<i32> for A2dpCodecIndex { from(item: i32) -> Self66 fn from(item: i32) -> Self { 67 A2dpCodecIndex::from_i32(item).unwrap_or_else(|| A2dpCodecIndex::MIN) 68 } 69 } 70 71 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] 72 #[repr(i32)] 73 pub enum A2dpCodecPriority { 74 Disabled = -1, 75 Default = 0, 76 Highest = 1_000_000, 77 } 78 79 impl From<i32> for A2dpCodecPriority { from(item: i32) -> Self80 fn from(item: i32) -> Self { 81 A2dpCodecPriority::from_i32(item).unwrap_or_else(|| A2dpCodecPriority::Default) 82 } 83 } 84 85 #[derive(Debug)] 86 pub struct A2dpError { 87 /// Standard BT status come from a function return or the cloest approximation to the real 88 /// error. 89 pub status: BtStatus, 90 /// An additional value to help explain the error. In the A2DP context, this is often referring 91 /// to the BTA_AV_XXX status. 92 pub error: i32, 93 /// An optional error message that the lower layer wants to deliver. 94 pub error_message: Option<String>, 95 } 96 97 bitflags! { 98 #[derive(Clone, Copy, Debug, PartialEq)] 99 pub struct A2dpCodecSampleRate: i32 { 100 const RATE_NONE = 0x0; 101 const RATE_44100 = 0x01; 102 const RATE_48000 = 0x02; 103 const RATE_88200 = 0x04; 104 const RATE_96000 = 0x08; 105 const RATE_176400 = 0x10; 106 const RATE_192000 = 0x20; 107 const RATE_16000 = 0x40; 108 const RATE_24000 = 0x80; 109 } 110 } 111 112 impl A2dpCodecSampleRate { validate_bits(val: i32) -> bool113 pub fn validate_bits(val: i32) -> bool { 114 val <= A2dpCodecSampleRate::all().bits() 115 } 116 } 117 118 impl TryInto<i32> for A2dpCodecSampleRate { 119 type Error = (); try_into(self) -> Result<i32, Self::Error>120 fn try_into(self) -> Result<i32, Self::Error> { 121 Ok(self.bits()) 122 } 123 } 124 125 impl TryFrom<i32> for A2dpCodecSampleRate { 126 type Error = (); try_from(val: i32) -> Result<Self, Self::Error>127 fn try_from(val: i32) -> Result<Self, Self::Error> { 128 Self::from_bits(val).ok_or(()) 129 } 130 } 131 132 bitflags! { 133 #[derive(Clone, Copy, Debug, PartialEq)] 134 pub struct A2dpCodecBitsPerSample: i32 { 135 const SAMPLE_NONE = 0x0; 136 const SAMPLE_16 = 0x01; 137 const SAMPLE_24 = 0x02; 138 const SAMPLE_32 = 0x04; 139 } 140 } 141 142 impl A2dpCodecBitsPerSample { validate_bits(val: i32) -> bool143 pub fn validate_bits(val: i32) -> bool { 144 val <= A2dpCodecBitsPerSample::all().bits() 145 } 146 } 147 148 impl TryInto<i32> for A2dpCodecBitsPerSample { 149 type Error = (); try_into(self) -> Result<i32, Self::Error>150 fn try_into(self) -> Result<i32, Self::Error> { 151 Ok(self.bits()) 152 } 153 } 154 155 impl TryFrom<i32> for A2dpCodecBitsPerSample { 156 type Error = (); try_from(val: i32) -> Result<Self, Self::Error>157 fn try_from(val: i32) -> Result<Self, Self::Error> { 158 Self::from_bits(val).ok_or(()) 159 } 160 } 161 162 bitflags! { 163 #[derive(Clone, Copy, Debug, PartialEq)] 164 pub struct A2dpCodecChannelMode: i32 { 165 const MODE_NONE = 0x0; 166 const MODE_MONO = 0x01; 167 const MODE_STEREO = 0x02; 168 } 169 } 170 171 impl A2dpCodecChannelMode { validate_bits(val: i32) -> bool172 pub fn validate_bits(val: i32) -> bool { 173 val <= A2dpCodecChannelMode::all().bits() 174 } 175 } 176 177 impl TryInto<i32> for A2dpCodecChannelMode { 178 type Error = (); try_into(self) -> Result<i32, Self::Error>179 fn try_into(self) -> Result<i32, Self::Error> { 180 Ok(self.bits()) 181 } 182 } 183 184 impl TryFrom<i32> for A2dpCodecChannelMode { 185 type Error = (); try_from(val: i32) -> Result<Self, Self::Error>186 fn try_from(val: i32) -> Result<Self, Self::Error> { 187 Self::from_bits(val).ok_or(()) 188 } 189 } 190 191 #[cxx::bridge(namespace = bluetooth::topshim::rust)] 192 pub mod ffi { 193 unsafe extern "C++" { 194 include!("types/raw_address.h"); 195 #[namespace = ""] 196 type RawAddress = crate::btif::RawAddress; 197 } 198 199 #[derive(Debug, Copy, Clone)] 200 pub struct A2dpCodecConfig { 201 pub codec_type: i32, 202 pub codec_priority: i32, 203 pub sample_rate: i32, 204 pub bits_per_sample: i32, 205 pub channel_mode: i32, 206 pub codec_specific_1: i64, 207 pub codec_specific_2: i64, 208 pub codec_specific_3: i64, 209 pub codec_specific_4: i64, 210 } 211 212 #[derive(Debug, Default)] 213 pub struct RustPresentationPosition { 214 remote_delay_report_ns: u64, 215 total_bytes_read: u64, 216 data_position_sec: i64, 217 data_position_nsec: i32, 218 } 219 220 #[derive(Debug)] 221 pub struct A2dpError<'a> { 222 status: u32, 223 error_code: u8, 224 error_msg: &'a CxxString, 225 } 226 227 unsafe extern "C++" { 228 include!("btav/btav_shim.h"); 229 include!("btav_sink/btav_sink_shim.h"); 230 231 type A2dpIntf; 232 type A2dpSinkIntf; 233 GetA2dpProfile(btif: *const u8) -> UniquePtr<A2dpIntf>234 unsafe fn GetA2dpProfile(btif: *const u8) -> UniquePtr<A2dpIntf>; 235 init(self: &A2dpIntf) -> i32236 fn init(self: &A2dpIntf) -> i32; connect(self: &A2dpIntf, bt_addr: RawAddress) -> u32237 fn connect(self: &A2dpIntf, bt_addr: RawAddress) -> u32; disconnect(self: &A2dpIntf, bt_addr: RawAddress) -> u32238 fn disconnect(self: &A2dpIntf, bt_addr: RawAddress) -> u32; set_silence_device(self: &A2dpIntf, bt_addr: RawAddress, silent: bool) -> i32239 fn set_silence_device(self: &A2dpIntf, bt_addr: RawAddress, silent: bool) -> i32; set_active_device(self: &A2dpIntf, bt_addr: RawAddress) -> i32240 fn set_active_device(self: &A2dpIntf, bt_addr: RawAddress) -> i32; config_codec( self: &A2dpIntf, bt_addr: RawAddress, codec_preferences: Vec<A2dpCodecConfig>, ) -> i32241 fn config_codec( 242 self: &A2dpIntf, 243 bt_addr: RawAddress, 244 codec_preferences: Vec<A2dpCodecConfig>, 245 ) -> i32; set_audio_config(self: &A2dpIntf, config: A2dpCodecConfig) -> bool246 fn set_audio_config(self: &A2dpIntf, config: A2dpCodecConfig) -> bool; start_audio_request(self: &A2dpIntf) -> bool247 fn start_audio_request(self: &A2dpIntf) -> bool; stop_audio_request(self: &A2dpIntf) -> bool248 fn stop_audio_request(self: &A2dpIntf) -> bool; suspend_audio_request(self: &A2dpIntf) -> bool249 fn suspend_audio_request(self: &A2dpIntf) -> bool; cleanup(self: &A2dpIntf)250 fn cleanup(self: &A2dpIntf); get_presentation_position(self: &A2dpIntf) -> RustPresentationPosition251 fn get_presentation_position(self: &A2dpIntf) -> RustPresentationPosition; 252 // A2dp sink functions 253 GetA2dpSinkProfile(btif: *const u8) -> UniquePtr<A2dpSinkIntf>254 unsafe fn GetA2dpSinkProfile(btif: *const u8) -> UniquePtr<A2dpSinkIntf>; 255 init(self: &A2dpSinkIntf) -> i32256 fn init(self: &A2dpSinkIntf) -> i32; connect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32257 fn connect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32; disconnect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32258 fn disconnect(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32; set_active_device(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32259 fn set_active_device(self: &A2dpSinkIntf, bt_addr: RawAddress) -> i32; cleanup(self: &A2dpSinkIntf)260 fn cleanup(self: &A2dpSinkIntf); 261 } 262 extern "Rust" { connection_state_callback(addr: RawAddress, state: u32, error: A2dpError)263 fn connection_state_callback(addr: RawAddress, state: u32, error: A2dpError); audio_state_callback(addr: RawAddress, state: u32)264 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>, )265 fn audio_config_callback( 266 addr: RawAddress, 267 codec_config: A2dpCodecConfig, 268 codecs_local_capabilities: &Vec<A2dpCodecConfig>, 269 codecs_selectable_capabilities: &Vec<A2dpCodecConfig>, 270 ); mandatory_codec_preferred_callback(addr: RawAddress)271 fn mandatory_codec_preferred_callback(addr: RawAddress); 272 273 // Currently only by qualification tests. sink_audio_config_callback(addr: RawAddress, sample_rate: u32, channel_count: u8)274 fn sink_audio_config_callback(addr: RawAddress, sample_rate: u32, channel_count: u8); sink_connection_state_callback(addr: RawAddress, state: u32, error: A2dpError)275 fn sink_connection_state_callback(addr: RawAddress, state: u32, error: A2dpError); sink_audio_state_callback(addr: RawAddress, state: u32)276 fn sink_audio_state_callback(addr: RawAddress, state: u32); 277 } 278 } 279 280 pub type A2dpCodecConfig = ffi::A2dpCodecConfig; 281 pub type PresentationPosition = ffi::RustPresentationPosition; 282 pub type FfiA2dpError<'a> = ffi::A2dpError<'a>; 283 284 impl Default for A2dpCodecConfig { default() -> A2dpCodecConfig285 fn default() -> A2dpCodecConfig { 286 A2dpCodecConfig { 287 codec_type: 0, 288 codec_priority: 0, 289 sample_rate: 0, 290 bits_per_sample: 0, 291 channel_mode: 0, 292 codec_specific_1: 0, 293 codec_specific_2: 0, 294 codec_specific_3: 0, 295 codec_specific_4: 0, 296 } 297 } 298 } 299 300 impl<'a> Into<A2dpError> for FfiA2dpError<'a> { into(self) -> A2dpError301 fn into(self) -> A2dpError { 302 A2dpError { 303 status: self.status.into(), 304 error: self.error_code as i32, 305 error_message: if self.error_msg == "" { 306 None 307 } else { 308 Some(self.error_msg.to_string()) 309 }, 310 } 311 } 312 } 313 314 #[derive(Debug)] 315 pub enum A2dpCallbacks { 316 ConnectionState(RawAddress, BtavConnectionState, A2dpError), 317 AudioState(RawAddress, BtavAudioState), 318 AudioConfig(RawAddress, A2dpCodecConfig, Vec<A2dpCodecConfig>, Vec<A2dpCodecConfig>), 319 MandatoryCodecPreferred(RawAddress), 320 } 321 322 pub struct A2dpCallbacksDispatcher { 323 pub dispatch: Box<dyn Fn(A2dpCallbacks) + Send>, 324 } 325 326 type A2dpCb = Arc<Mutex<A2dpCallbacksDispatcher>>; 327 328 cb_variant!(A2dpCb, connection_state_callback -> A2dpCallbacks::ConnectionState, 329 RawAddress, u32 -> BtavConnectionState, FfiA2dpError -> A2dpError,{ 330 let _2 = _2.into(); 331 }); 332 333 cb_variant!(A2dpCb, audio_state_callback -> A2dpCallbacks::AudioState, RawAddress, u32 -> BtavAudioState); 334 335 cb_variant!(A2dpCb, mandatory_codec_preferred_callback -> A2dpCallbacks::MandatoryCodecPreferred, RawAddress); 336 337 cb_variant!(A2dpCb, audio_config_callback -> A2dpCallbacks::AudioConfig, 338 RawAddress, A2dpCodecConfig, &Vec<A2dpCodecConfig>, &Vec<A2dpCodecConfig>, { 339 let _2: Vec<A2dpCodecConfig> = _2.to_vec(); 340 let _3: Vec<A2dpCodecConfig> = _3.to_vec(); 341 }); 342 343 pub struct A2dp { 344 internal: cxx::UniquePtr<ffi::A2dpIntf>, 345 _is_init: bool, 346 _is_enabled: bool, 347 } 348 349 // For *const u8 opaque btif 350 unsafe impl Send for A2dp {} 351 352 impl ToggleableProfile for A2dp { is_enabled(&self) -> bool353 fn is_enabled(&self) -> bool { 354 self._is_enabled 355 } 356 enable(&mut self) -> bool357 fn enable(&mut self) -> bool { 358 self.internal.init(); 359 self._is_enabled = true; 360 true 361 } 362 363 #[profile_enabled_or(false)] disable(&mut self) -> bool364 fn disable(&mut self) -> bool { 365 self.internal.cleanup(); 366 self._is_enabled = false; 367 true 368 } 369 } 370 371 impl A2dp { new(intf: &BluetoothInterface) -> A2dp372 pub fn new(intf: &BluetoothInterface) -> A2dp { 373 let a2dpif: cxx::UniquePtr<ffi::A2dpIntf>; 374 unsafe { 375 a2dpif = ffi::GetA2dpProfile(intf.as_raw_ptr()); 376 } 377 378 A2dp { internal: a2dpif, _is_init: false, _is_enabled: false } 379 } 380 is_initialized(&self) -> bool381 pub fn is_initialized(&self) -> bool { 382 self._is_init 383 } 384 initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool385 pub fn initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool { 386 if get_dispatchers().lock().unwrap().set::<A2dpCb>(Arc::new(Mutex::new(callbacks))) { 387 panic!("Tried to set dispatcher for A2dp callbacks while it already exists"); 388 } 389 390 if self._is_init { 391 warn!("A2dp has already been initialized"); 392 return false; 393 } 394 395 true 396 } 397 398 #[profile_enabled_or(BtStatus::NotReady)] connect(&mut self, addr: RawAddress) -> BtStatus399 pub fn connect(&mut self, addr: RawAddress) -> BtStatus { 400 BtStatus::from(self.internal.connect(addr)) 401 } 402 403 #[profile_enabled_or] set_active_device(&mut self, addr: RawAddress)404 pub fn set_active_device(&mut self, addr: RawAddress) { 405 self.internal.set_active_device(addr); 406 } 407 408 #[profile_enabled_or(BtStatus::NotReady)] disconnect(&mut self, addr: RawAddress) -> BtStatus409 pub fn disconnect(&mut self, addr: RawAddress) -> BtStatus { 410 BtStatus::from(self.internal.disconnect(addr)) 411 } 412 413 #[profile_enabled_or] config_codec(&self, addr: RawAddress, config: Vec<A2dpCodecConfig>)414 pub fn config_codec(&self, addr: RawAddress, config: Vec<A2dpCodecConfig>) { 415 self.internal.config_codec(addr, config); 416 } 417 418 #[profile_enabled_or(false)] start_audio_request(&self) -> bool419 pub fn start_audio_request(&self) -> bool { 420 self.internal.start_audio_request() 421 } 422 423 #[profile_enabled_or] stop_audio_request(&self)424 pub fn stop_audio_request(&self) { 425 self.internal.stop_audio_request(); 426 } 427 428 #[profile_enabled_or] suspend_audio_request(&self)429 pub fn suspend_audio_request(&self) { 430 self.internal.suspend_audio_request(); 431 } 432 433 #[profile_enabled_or_default] get_presentation_position(&self) -> PresentationPosition434 pub fn get_presentation_position(&self) -> PresentationPosition { 435 self.internal.get_presentation_position() 436 } 437 } 438 439 #[derive(Debug)] 440 pub enum A2dpSinkCallbacks { 441 ConnectionState(RawAddress, BtavConnectionState, A2dpError), 442 AudioState(RawAddress, BtavAudioState), 443 AudioConfig(RawAddress, u32, u8), 444 } 445 446 pub struct A2dpSinkCallbacksDispatcher { 447 pub dispatch: Box<dyn Fn(A2dpSinkCallbacks) + Send>, 448 } 449 450 type A2dpSinkCb = Arc<Mutex<A2dpSinkCallbacksDispatcher>>; 451 452 cb_variant!(A2dpSinkCb, sink_connection_state_callback -> A2dpSinkCallbacks::ConnectionState, 453 RawAddress, u32 -> BtavConnectionState, FfiA2dpError -> A2dpError,{ 454 let _2 = _2.into(); 455 }); 456 457 cb_variant!(A2dpSinkCb, sink_audio_state_callback -> A2dpSinkCallbacks::AudioState, RawAddress, u32 -> BtavAudioState); 458 459 cb_variant!(A2dpSinkCb, sink_audio_config_callback -> A2dpSinkCallbacks::AudioConfig, RawAddress, u32, u8); 460 461 pub struct A2dpSink { 462 internal: cxx::UniquePtr<ffi::A2dpSinkIntf>, 463 _is_init: bool, 464 _is_enabled: bool, 465 } 466 467 // For *const u8 opaque btif 468 unsafe impl Send for A2dpSink {} 469 470 impl ToggleableProfile for A2dpSink { is_enabled(&self) -> bool471 fn is_enabled(&self) -> bool { 472 self._is_enabled 473 } 474 enable(&mut self) -> bool475 fn enable(&mut self) -> bool { 476 self.internal.init(); 477 self._is_enabled = true; 478 true 479 } 480 481 #[profile_enabled_or(false)] disable(&mut self) -> bool482 fn disable(&mut self) -> bool { 483 self.internal.cleanup(); 484 self._is_enabled = false; 485 true 486 } 487 } 488 489 impl A2dpSink { new(intf: &BluetoothInterface) -> A2dpSink490 pub fn new(intf: &BluetoothInterface) -> A2dpSink { 491 let a2dp_sink: cxx::UniquePtr<ffi::A2dpSinkIntf>; 492 unsafe { 493 a2dp_sink = ffi::GetA2dpSinkProfile(intf.as_raw_ptr()); 494 } 495 496 A2dpSink { internal: a2dp_sink, _is_init: false, _is_enabled: false } 497 } 498 is_initialized(&self) -> bool499 pub fn is_initialized(&self) -> bool { 500 self._is_init 501 } 502 initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool503 pub fn initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool { 504 if get_dispatchers().lock().unwrap().set::<A2dpSinkCb>(Arc::new(Mutex::new(callbacks))) { 505 panic!("Tried to set dispatcher for A2dp Sink Callbacks while it already exists"); 506 } 507 self._is_init = true; 508 true 509 } 510 511 #[profile_enabled_or] connect(&mut self, bt_addr: RawAddress)512 pub fn connect(&mut self, bt_addr: RawAddress) { 513 self.internal.connect(bt_addr); 514 } 515 516 #[profile_enabled_or] disconnect(&mut self, bt_addr: RawAddress)517 pub fn disconnect(&mut self, bt_addr: RawAddress) { 518 self.internal.disconnect(bt_addr); 519 } 520 521 #[profile_enabled_or] set_active_device(&mut self, bt_addr: RawAddress)522 pub fn set_active_device(&mut self, bt_addr: RawAddress) { 523 self.internal.set_active_device(bt_addr); 524 } 525 526 #[profile_enabled_or] cleanup(&mut self)527 pub fn cleanup(&mut self) {} 528 } 529 530 #[cfg(test)] 531 mod tests { 532 use super::*; 533 534 #[test] validate_sample_rate()535 fn validate_sample_rate() { 536 assert!(!A2dpCodecSampleRate::validate_bits(256)); 537 assert!(A2dpCodecSampleRate::validate_bits(2 + 32 + 128)); 538 } 539 540 #[test] validate_bits_per_sample()541 fn validate_bits_per_sample() { 542 assert!(!A2dpCodecBitsPerSample::validate_bits(8)); 543 assert!(A2dpCodecBitsPerSample::validate_bits(1 + 4)); 544 } 545 546 #[test] validate_channel_mode()547 fn validate_channel_mode() { 548 assert!(!A2dpCodecChannelMode::validate_bits(4)); 549 assert!(A2dpCodecChannelMode::validate_bits(1 + 2)); 550 } 551 } 552