• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::btif::{BluetoothInterface, RawAddress};
2 use crate::topstack::get_dispatchers;
3 
4 use num_traits::cast::FromPrimitive;
5 use std::sync::{Arc, Mutex};
6 use topshim_macros::cb_variant;
7 
8 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
9 #[repr(u32)]
10 pub enum BtavConnectionState {
11     Disconnected = 0,
12     Connecting,
13     Connected,
14     Disconnecting,
15 }
16 
17 impl From<u32> for BtavConnectionState {
from(item: u32) -> Self18     fn from(item: u32) -> Self {
19         BtavConnectionState::from_u32(item).unwrap()
20     }
21 }
22 
23 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
24 #[repr(u32)]
25 pub enum BtavAudioState {
26     RemoteSuspend = 0,
27     Stopped,
28     Started,
29 }
30 
31 impl From<u32> for BtavAudioState {
from(item: u32) -> Self32     fn from(item: u32) -> Self {
33         BtavAudioState::from_u32(item).unwrap()
34     }
35 }
36 
37 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
38 #[repr(u32)]
39 pub enum A2dpCodecIndex {
40     SrcSbc = 0,
41     SrcAac,
42     SrcAptx,
43     SrcAptxHD,
44     SrcLdac,
45     SinkSbc,
46     SinkAac,
47     SinkLdac,
48     Max,
49 }
50 
51 impl A2dpCodecIndex {
52     pub const SRC_MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc;
53     pub const SRC_MAX: A2dpCodecIndex = A2dpCodecIndex::SinkSbc;
54     pub const SINK_MIN: A2dpCodecIndex = A2dpCodecIndex::SinkSbc;
55     pub const SINK_MAX: A2dpCodecIndex = A2dpCodecIndex::Max;
56     pub const MAX: A2dpCodecIndex = A2dpCodecIndex::Max;
57     pub const MIN: A2dpCodecIndex = A2dpCodecIndex::SrcSbc;
58 }
59 
60 impl From<i32> for A2dpCodecIndex {
from(item: i32) -> Self61     fn from(item: i32) -> Self {
62         A2dpCodecIndex::from_i32(item).unwrap_or_else(|| A2dpCodecIndex::MIN)
63     }
64 }
65 
66 #[derive(Debug, FromPrimitive, PartialEq, PartialOrd)]
67 #[repr(i32)]
68 pub enum A2dpCodecPriority {
69     Disabled = -1,
70     Default = 0,
71     Highest = 1_000_000,
72 }
73 
74 impl From<i32> for A2dpCodecPriority {
from(item: i32) -> Self75     fn from(item: i32) -> Self {
76         A2dpCodecPriority::from_i32(item).unwrap_or_else(|| A2dpCodecPriority::Default)
77     }
78 }
79 
80 bitflags! {
81     pub struct A2dpCodecSampleRate: i32 {
82         const RATE_NONE = 0x0;
83         const RATE_44100 = 0x01;
84         const RATE_48000 = 0x02;
85         const RATE_88200 = 0x04;
86         const RATE_96000 = 0x08;
87         const RATE_176400 = 0x10;
88         const RATE_192000 = 0x20;
89         const RATE_16000 = 0x40;
90         const RATE_24000 = 0x80;
91     }
92 }
93 
94 impl A2dpCodecSampleRate {
validate_bits(val: i32) -> bool95     pub fn validate_bits(val: i32) -> bool {
96         val <= A2dpCodecSampleRate::all().bits()
97     }
98 }
99 
100 bitflags! {
101     pub struct A2dpCodecBitsPerSample: i32 {
102         const SAMPLE_NONE = 0x0;
103         const SAMPLE_16 = 0x01;
104         const SAMPLE_24 = 0x02;
105         const SAMPLE_32 = 0x04;
106     }
107 }
108 
109 impl A2dpCodecBitsPerSample {
validate_bits(val: i32) -> bool110     pub fn validate_bits(val: i32) -> bool {
111         val <= A2dpCodecBitsPerSample::all().bits()
112     }
113 }
114 
115 bitflags! {
116     pub struct A2dpCodecChannelMode: i32 {
117         const MODE_NONE = 0x0;
118         const MODE_MONO = 0x01;
119         const MODE_STEREO = 0x02;
120     }
121 }
122 
123 impl A2dpCodecChannelMode {
validate_bits(val: i32) -> bool124     pub fn validate_bits(val: i32) -> bool {
125         val <= A2dpCodecChannelMode::all().bits()
126     }
127 }
128 
129 #[cxx::bridge(namespace = bluetooth::topshim::rust)]
130 pub mod ffi {
131     #[derive(Debug, Copy, Clone)]
132     pub struct RustRawAddress {
133         address: [u8; 6],
134     }
135 
136     #[derive(Debug, Copy, Clone)]
137     pub struct A2dpCodecConfig {
138         pub codec_type: i32,
139         pub codec_priority: i32,
140         pub sample_rate: i32,
141         pub bits_per_sample: i32,
142         pub channel_mode: i32,
143         pub codec_specific_1: i64,
144         pub codec_specific_2: i64,
145         pub codec_specific_3: i64,
146         pub codec_specific_4: i64,
147     }
148 
149     #[derive(Debug, Default)]
150     pub struct RustPresentationPosition {
151         remote_delay_report_ns: u64,
152         total_bytes_read: u64,
153         data_position_sec: i64,
154         data_position_nsec: i32,
155     }
156 
157     unsafe extern "C++" {
158         include!("btav/btav_shim.h");
159         include!("btav_sink/btav_sink_shim.h");
160 
161         type A2dpIntf;
162         type A2dpSinkIntf;
163 
GetA2dpProfile(btif: *const u8) -> UniquePtr<A2dpIntf>164         unsafe fn GetA2dpProfile(btif: *const u8) -> UniquePtr<A2dpIntf>;
165 
init(self: &A2dpIntf) -> i32166         fn init(self: &A2dpIntf) -> i32;
connect(self: &A2dpIntf, bt_addr: RustRawAddress) -> i32167         fn connect(self: &A2dpIntf, bt_addr: RustRawAddress) -> i32;
disconnect(self: &A2dpIntf, bt_addr: RustRawAddress) -> i32168         fn disconnect(self: &A2dpIntf, bt_addr: RustRawAddress) -> i32;
set_silence_device(self: &A2dpIntf, bt_addr: RustRawAddress, silent: bool) -> i32169         fn set_silence_device(self: &A2dpIntf, bt_addr: RustRawAddress, silent: bool) -> i32;
set_active_device(self: &A2dpIntf, bt_addr: RustRawAddress) -> i32170         fn set_active_device(self: &A2dpIntf, bt_addr: RustRawAddress) -> i32;
config_codec( self: &A2dpIntf, bt_addr: RustRawAddress, codec_preferences: Vec<A2dpCodecConfig>, ) -> i32171         fn config_codec(
172             self: &A2dpIntf,
173             bt_addr: RustRawAddress,
174             codec_preferences: Vec<A2dpCodecConfig>,
175         ) -> i32;
set_audio_config(self: &A2dpIntf, config: A2dpCodecConfig) -> bool176         fn set_audio_config(self: &A2dpIntf, config: A2dpCodecConfig) -> bool;
start_audio_request(self: &A2dpIntf) -> bool177         fn start_audio_request(self: &A2dpIntf) -> bool;
stop_audio_request(self: &A2dpIntf) -> bool178         fn stop_audio_request(self: &A2dpIntf) -> bool;
cleanup(self: &A2dpIntf)179         fn cleanup(self: &A2dpIntf);
get_presentation_position(self: &A2dpIntf) -> RustPresentationPosition180         fn get_presentation_position(self: &A2dpIntf) -> RustPresentationPosition;
181         // A2dp sink functions
182 
GetA2dpSinkProfile(btif: *const u8) -> UniquePtr<A2dpSinkIntf>183         unsafe fn GetA2dpSinkProfile(btif: *const u8) -> UniquePtr<A2dpSinkIntf>;
184 
init(self: &A2dpSinkIntf) -> i32185         fn init(self: &A2dpSinkIntf) -> i32;
connect(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32186         fn connect(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32;
disconnect(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32187         fn disconnect(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32;
set_active_device(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32188         fn set_active_device(self: &A2dpSinkIntf, bt_addr: RustRawAddress) -> i32;
cleanup(self: &A2dpSinkIntf)189         fn cleanup(self: &A2dpSinkIntf);
190     }
191     extern "Rust" {
connection_state_callback(addr: RustRawAddress, state: u32)192         fn connection_state_callback(addr: RustRawAddress, state: u32);
audio_state_callback(addr: RustRawAddress, state: u32)193         fn audio_state_callback(addr: RustRawAddress, state: u32);
audio_config_callback( addr: RustRawAddress, codec_config: A2dpCodecConfig, codecs_local_capabilities: Vec<A2dpCodecConfig>, codecs_selectable_capabilities: Vec<A2dpCodecConfig>, )194         fn audio_config_callback(
195             addr: RustRawAddress,
196             codec_config: A2dpCodecConfig,
197             codecs_local_capabilities: Vec<A2dpCodecConfig>,
198             codecs_selectable_capabilities: Vec<A2dpCodecConfig>,
199         );
mandatory_codec_preferred_callback(addr: RustRawAddress)200         fn mandatory_codec_preferred_callback(addr: RustRawAddress);
201     }
202 }
203 
204 pub type FfiAddress = ffi::RustRawAddress;
205 pub type A2dpCodecConfig = ffi::A2dpCodecConfig;
206 pub type PresentationPosition = ffi::RustPresentationPosition;
207 
208 impl From<RawAddress> for FfiAddress {
from(addr: RawAddress) -> Self209     fn from(addr: RawAddress) -> Self {
210         FfiAddress { address: addr.val }
211     }
212 }
213 
214 impl Into<RawAddress> for FfiAddress {
into(self) -> RawAddress215     fn into(self) -> RawAddress {
216         RawAddress { val: self.address }
217     }
218 }
219 
220 impl Default for A2dpCodecConfig {
default() -> A2dpCodecConfig221     fn default() -> A2dpCodecConfig {
222         A2dpCodecConfig {
223             codec_type: 0,
224             codec_priority: 0,
225             sample_rate: 0,
226             bits_per_sample: 0,
227             channel_mode: 0,
228             codec_specific_1: 0,
229             codec_specific_2: 0,
230             codec_specific_3: 0,
231             codec_specific_4: 0,
232         }
233     }
234 }
235 
236 #[derive(Debug)]
237 pub enum A2dpCallbacks {
238     ConnectionState(RawAddress, BtavConnectionState),
239     AudioState(RawAddress, BtavAudioState),
240     AudioConfig(RawAddress, A2dpCodecConfig, Vec<A2dpCodecConfig>, Vec<A2dpCodecConfig>),
241     MandatoryCodecPreferred(RawAddress),
242 }
243 
244 pub struct A2dpCallbacksDispatcher {
245     pub dispatch: Box<dyn Fn(A2dpCallbacks) + Send>,
246 }
247 
248 type A2dpCb = Arc<Mutex<A2dpCallbacksDispatcher>>;
249 
250 cb_variant!(A2dpCb, connection_state_callback -> A2dpCallbacks::ConnectionState,
251 FfiAddress -> RawAddress, u32 -> BtavConnectionState, {
252     let _0 = _0.into();
253 });
254 
255 cb_variant!(A2dpCb, audio_state_callback -> A2dpCallbacks::AudioState,
256 FfiAddress -> RawAddress, u32 -> BtavAudioState, {
257     let _0 = _0.into();
258 });
259 
260 cb_variant!(A2dpCb, mandatory_codec_preferred_callback -> A2dpCallbacks::MandatoryCodecPreferred,
261 FfiAddress -> RawAddress, {
262     let _0 = _0.into();
263 });
264 
265 cb_variant!(A2dpCb, audio_config_callback -> A2dpCallbacks::AudioConfig,
266 FfiAddress -> RawAddress, A2dpCodecConfig, Vec<A2dpCodecConfig>, Vec<A2dpCodecConfig>, {
267     let _0 = _0.into();
268 });
269 
270 pub struct A2dp {
271     internal: cxx::UniquePtr<ffi::A2dpIntf>,
272     _is_init: bool,
273 }
274 
275 // For *const u8 opaque btif
276 unsafe impl Send for A2dp {}
277 
278 impl A2dp {
new(intf: &BluetoothInterface) -> A2dp279     pub fn new(intf: &BluetoothInterface) -> A2dp {
280         let a2dpif: cxx::UniquePtr<ffi::A2dpIntf>;
281         unsafe {
282             a2dpif = ffi::GetA2dpProfile(intf.as_raw_ptr());
283         }
284 
285         A2dp { internal: a2dpif, _is_init: false }
286     }
287 
initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool288     pub fn initialize(&mut self, callbacks: A2dpCallbacksDispatcher) -> bool {
289         if get_dispatchers().lock().unwrap().set::<A2dpCb>(Arc::new(Mutex::new(callbacks))) {
290             panic!("Tried to set dispatcher for A2dp callbacks while it already exists");
291         }
292         self.internal.init();
293         true
294     }
295 
connect(&mut self, addr: RawAddress)296     pub fn connect(&mut self, addr: RawAddress) {
297         self.internal.connect(addr.into());
298     }
299 
set_active_device(&mut self, addr: RawAddress)300     pub fn set_active_device(&mut self, addr: RawAddress) {
301         self.internal.set_active_device(addr.into());
302     }
303 
disconnect(&mut self, addr: RawAddress)304     pub fn disconnect(&mut self, addr: RawAddress) {
305         self.internal.disconnect(addr.into());
306     }
307 
set_audio_config(&self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32)308     pub fn set_audio_config(&self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32) {
309         let config =
310             A2dpCodecConfig { sample_rate, bits_per_sample, channel_mode, ..Default::default() };
311         self.internal.set_audio_config(config);
312     }
start_audio_request(&self)313     pub fn start_audio_request(&self) {
314         self.internal.start_audio_request();
315     }
316 
stop_audio_request(&self)317     pub fn stop_audio_request(&self) {
318         self.internal.stop_audio_request();
319     }
320 
get_presentation_position(&self) -> PresentationPosition321     pub fn get_presentation_position(&self) -> PresentationPosition {
322         self.internal.get_presentation_position()
323     }
324 }
325 
326 #[derive(Debug)]
327 pub enum A2dpSinkCallbacks {
328     ConnectionState(RawAddress, BtavConnectionState),
329 }
330 
331 pub struct A2dpSinkCallbacksDispatcher {
332     pub dispatch: Box<dyn Fn(A2dpSinkCallbacks) + Send>,
333 }
334 
335 type A2dpSinkCb = Arc<Mutex<A2dpSinkCallbacksDispatcher>>;
336 
337 pub struct A2dpSink {
338     internal: cxx::UniquePtr<ffi::A2dpSinkIntf>,
339     _is_init: bool,
340 }
341 
342 // For *const u8 opaque btif
343 unsafe impl Send for A2dpSink {}
344 
345 impl A2dpSink {
new(intf: &BluetoothInterface) -> A2dpSink346     pub fn new(intf: &BluetoothInterface) -> A2dpSink {
347         let a2dp_sink: cxx::UniquePtr<ffi::A2dpSinkIntf>;
348         unsafe {
349             a2dp_sink = ffi::GetA2dpSinkProfile(intf.as_raw_ptr());
350         }
351 
352         A2dpSink { internal: a2dp_sink, _is_init: false }
353     }
354 
initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool355     pub fn initialize(&mut self, callbacks: A2dpSinkCallbacksDispatcher) -> bool {
356         if get_dispatchers().lock().unwrap().set::<A2dpSinkCb>(Arc::new(Mutex::new(callbacks))) {
357             panic!("Tried to set dispatcher for A2dp Sink Callbacks while it already exists");
358         }
359         self.internal.init();
360         true
361     }
362 
connect(&mut self, bt_addr: RawAddress)363     pub fn connect(&mut self, bt_addr: RawAddress) {
364         self.internal.connect(bt_addr.into());
365     }
366 
disconnect(&mut self, bt_addr: RawAddress)367     pub fn disconnect(&mut self, bt_addr: RawAddress) {
368         self.internal.disconnect(bt_addr.into());
369     }
370 
set_active_device(&mut self, bt_addr: RawAddress)371     pub fn set_active_device(&mut self, bt_addr: RawAddress) {
372         self.internal.set_active_device(bt_addr.into());
373     }
374 
cleanup(&mut self)375     pub fn cleanup(&mut self) {}
376 }
377 
378 #[cfg(test)]
379 mod tests {
380     use super::*;
381 
382     #[test]
validate_sample_rate()383     fn validate_sample_rate() {
384         assert!(!A2dpCodecSampleRate::validate_bits(256));
385         assert!(A2dpCodecSampleRate::validate_bits(2 + 32 + 128));
386     }
387 
388     #[test]
validate_bits_per_sample()389     fn validate_bits_per_sample() {
390         assert!(!A2dpCodecBitsPerSample::validate_bits(8));
391         assert!(A2dpCodecBitsPerSample::validate_bits(1 + 4));
392     }
393 
394     #[test]
validate_channel_mode()395     fn validate_channel_mode() {
396         assert!(!A2dpCodecChannelMode::validate_bits(4));
397         assert!(A2dpCodecChannelMode::validate_bits(1 + 2));
398     }
399 }
400