• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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