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