• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Anything related to audio and media API.
2 
3 use bt_topshim::btif::{BluetoothInterface, RawAddress};
4 use bt_topshim::profiles::a2dp::{
5     A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, A2dpCodecBitsPerSample, A2dpCodecChannelMode,
6     A2dpCodecConfig, A2dpCodecSampleRate, BtavConnectionState, PresentationPosition,
7 };
8 use bt_topshim::profiles::avrcp::{Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher};
9 use bt_topshim::profiles::hfp::{
10     BthfAudioState, BthfConnectionState, Hfp, HfpCallbacks, HfpCallbacksDispatcher,
11     HfpCodecCapability,
12 };
13 
14 use bt_topshim::topstack;
15 
16 use log::{info, warn};
17 use num_traits::cast::ToPrimitive;
18 use std::collections::HashMap;
19 use std::convert::TryFrom;
20 use std::sync::Arc;
21 use std::sync::Mutex;
22 
23 use tokio::sync::mpsc::Sender;
24 use tokio::task::JoinHandle;
25 use tokio::time::{sleep, Duration};
26 
27 use crate::bluetooth::{Bluetooth, BluetoothDevice, IBluetooth};
28 use crate::Message;
29 
30 const DEFAULT_PROFILE_DISCOVERY_TIMEOUT_SEC: u64 = 5;
31 
32 pub trait IBluetoothMedia {
33     ///
register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool34     fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool;
35 
36     /// initializes media (both A2dp and AVRCP) stack
initialize(&mut self) -> bool37     fn initialize(&mut self) -> bool;
38 
39     /// clean up media stack
cleanup(&mut self) -> bool40     fn cleanup(&mut self) -> bool;
41 
connect(&mut self, device: String)42     fn connect(&mut self, device: String);
set_active_device(&mut self, device: String)43     fn set_active_device(&mut self, device: String);
disconnect(&mut self, device: String)44     fn disconnect(&mut self, device: String);
set_audio_config( &mut self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32, ) -> bool45     fn set_audio_config(
46         &mut self,
47         sample_rate: i32,
48         bits_per_sample: i32,
49         channel_mode: i32,
50     ) -> bool;
set_volume(&mut self, volume: i32)51     fn set_volume(&mut self, volume: i32);
start_audio_request(&mut self)52     fn start_audio_request(&mut self);
stop_audio_request(&mut self)53     fn stop_audio_request(&mut self);
get_presentation_position(&mut self) -> PresentationPosition54     fn get_presentation_position(&mut self) -> PresentationPosition;
55 
start_sco_call(&mut self, device: String)56     fn start_sco_call(&mut self, device: String);
stop_sco_call(&mut self, device: String)57     fn stop_sco_call(&mut self, device: String);
58 }
59 
60 pub trait IBluetoothMediaCallback {
61     /// Triggered when a Bluetooth audio device is ready to be used. This should
62     /// only be triggered once for a device and send an event to clients. If the
63     /// device supports both HFP and A2DP, both should be ready when this is
64     /// triggered.
on_bluetooth_audio_device_added(&self, device: BluetoothAudioDevice)65     fn on_bluetooth_audio_device_added(&self, device: BluetoothAudioDevice);
66 
67     ///
on_bluetooth_audio_device_removed(&self, addr: String)68     fn on_bluetooth_audio_device_removed(&self, addr: String);
69 
70     ///
on_absolute_volume_supported_changed(&self, supported: bool)71     fn on_absolute_volume_supported_changed(&self, supported: bool);
72 
73     ///
on_absolute_volume_changed(&self, volume: i32)74     fn on_absolute_volume_changed(&self, volume: i32);
75 }
76 
77 /// Serializable device used in.
78 #[derive(Debug, Default, Clone)]
79 pub struct BluetoothAudioDevice {
80     pub address: String,
81     pub name: String,
82     pub a2dp_caps: Vec<A2dpCodecConfig>,
83     pub hfp_cap: HfpCodecCapability,
84     pub absolute_volume: bool,
85 }
86 
87 impl BluetoothAudioDevice {
new( address: String, name: String, a2dp_caps: Vec<A2dpCodecConfig>, hfp_cap: HfpCodecCapability, absolute_volume: bool, ) -> BluetoothAudioDevice88     pub(crate) fn new(
89         address: String,
90         name: String,
91         a2dp_caps: Vec<A2dpCodecConfig>,
92         hfp_cap: HfpCodecCapability,
93         absolute_volume: bool,
94     ) -> BluetoothAudioDevice {
95         BluetoothAudioDevice { address, name, a2dp_caps, hfp_cap, absolute_volume }
96     }
97 }
98 /// Actions that `BluetoothMedia` can take on behalf of the stack.
99 pub enum MediaActions {
100     Connect(String),
101     Disconnect(String),
102 }
103 
104 pub struct BluetoothMedia {
105     intf: Arc<Mutex<BluetoothInterface>>,
106     initialized: bool,
107     callbacks: Arc<Mutex<Vec<(u32, Box<dyn IBluetoothMediaCallback + Send>)>>>,
108     callback_last_id: u32,
109     tx: Sender<Message>,
110     adapter: Option<Arc<Mutex<Box<Bluetooth>>>>,
111     a2dp: Option<A2dp>,
112     avrcp: Option<Avrcp>,
113     a2dp_states: HashMap<RawAddress, BtavConnectionState>,
114     hfp: Option<Hfp>,
115     hfp_states: HashMap<RawAddress, BthfConnectionState>,
116     selectable_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>,
117     hfp_caps: HashMap<RawAddress, HfpCodecCapability>,
118     device_added_tasks: Arc<Mutex<HashMap<RawAddress, Option<JoinHandle<()>>>>>,
119     absolute_volume: bool,
120 }
121 
122 impl BluetoothMedia {
new(tx: Sender<Message>, intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothMedia123     pub fn new(tx: Sender<Message>, intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothMedia {
124         BluetoothMedia {
125             intf,
126             initialized: false,
127             callbacks: Arc::new(Mutex::new(vec![])),
128             callback_last_id: 0,
129             tx,
130             adapter: None,
131             a2dp: None,
132             avrcp: None,
133             a2dp_states: HashMap::new(),
134             hfp: None,
135             hfp_states: HashMap::new(),
136             selectable_caps: HashMap::new(),
137             hfp_caps: HashMap::new(),
138             device_added_tasks: Arc::new(Mutex::new(HashMap::new())),
139             absolute_volume: false,
140         }
141     }
142 
set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>)143     pub fn set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>) {
144         self.adapter = Some(adapter);
145     }
146 
dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks)147     pub fn dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks) {
148         match cb {
149             A2dpCallbacks::ConnectionState(addr, state) => {
150                 if !self.a2dp_states.get(&addr).is_none()
151                     && state == *self.a2dp_states.get(&addr).unwrap()
152                 {
153                     return;
154                 }
155                 match state {
156                     BtavConnectionState::Connected => {
157                         info!("[{}]: a2dp connected.", addr.to_string());
158                         self.notify_media_capability_added(addr);
159                         self.a2dp_states.insert(addr, state);
160                     }
161                     BtavConnectionState::Disconnected => match self.a2dp_states.remove(&addr) {
162                         Some(_) => self.notify_media_capability_removed(addr),
163                         None => {
164                             warn!("[{}]: Unknown address a2dp disconnected.", addr.to_string());
165                         }
166                     },
167                     _ => {
168                         self.a2dp_states.insert(addr, state);
169                     }
170                 }
171             }
172             A2dpCallbacks::AudioState(_addr, _state) => {}
173             A2dpCallbacks::AudioConfig(addr, _config, _local_caps, selectable_caps) => {
174                 self.selectable_caps.insert(addr, selectable_caps);
175             }
176             A2dpCallbacks::MandatoryCodecPreferred(_addr) => {}
177         }
178     }
179 
dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks)180     pub fn dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks) {
181         match cb {
182             AvrcpCallbacks::AvrcpAbsoluteVolumeEnabled(supported) => {
183                 self.absolute_volume = supported;
184                 self.for_all_callbacks(|callback| {
185                     callback.on_absolute_volume_supported_changed(supported);
186                 });
187             }
188             AvrcpCallbacks::AvrcpAbsoluteVolumeUpdate(volume) => {
189                 self.for_all_callbacks(|callback| {
190                     callback.on_absolute_volume_changed(i32::from(volume));
191                 });
192             }
193         }
194     }
195 
dispatch_media_actions(&mut self, action: MediaActions)196     pub fn dispatch_media_actions(&mut self, action: MediaActions) {
197         match action {
198             MediaActions::Connect(address) => self.connect(address),
199             MediaActions::Disconnect(address) => self.disconnect(address),
200         }
201     }
202 
dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks)203     pub fn dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks) {
204         match cb {
205             HfpCallbacks::ConnectionState(state, addr) => {
206                 if !self.hfp_states.get(&addr).is_none()
207                     && state == *self.hfp_states.get(&addr).unwrap()
208                 {
209                     return;
210                 }
211                 match state {
212                     BthfConnectionState::Connected => {
213                         info!("[{}]: hfp connected.", addr.to_string());
214                     }
215                     BthfConnectionState::SlcConnected => {
216                         info!("[{}]: hfp slc connected.", addr.to_string());
217                         // TODO(b/214148074): Support WBS
218                         self.hfp_caps.insert(addr, HfpCodecCapability::CVSD);
219                         self.notify_media_capability_added(addr);
220                     }
221                     BthfConnectionState::Disconnected => {
222                         info!("[{}]: hfp disconnected.", addr.to_string());
223                         match self.hfp_states.remove(&addr) {
224                             Some(_) => self.notify_media_capability_removed(addr),
225                             None => {
226                                 warn!("[{}] Unknown address hfp disconnected.", addr.to_string())
227                             }
228                         }
229                         return;
230                     }
231                     BthfConnectionState::Connecting => {
232                         info!("[{}]: hfp connecting.", addr.to_string());
233                     }
234                     BthfConnectionState::Disconnecting => {
235                         info!("[{}]: hfp disconnecting.", addr.to_string());
236                     }
237                 }
238 
239                 self.hfp_states.insert(addr, state);
240             }
241             HfpCallbacks::AudioState(state, addr) => {
242                 if self.hfp_states.get(&addr).is_none()
243                     || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap()
244                 {
245                     warn!("[{}]: Unknown address hfp or slc not ready", addr.to_string());
246                     return;
247                 }
248                 match state {
249                     BthfAudioState::Connected => {
250                         info!("[{}]: hfp audio connected.", addr.to_string());
251                     }
252                     BthfAudioState::Disconnected => {
253                         info!("[{}]: hfp audio disconnected.", addr.to_string());
254                     }
255                     BthfAudioState::Connecting => {
256                         info!("[{}]: hfp audio connecting.", addr.to_string());
257                     }
258                     BthfAudioState::Disconnecting => {
259                         info!("[{}]: hfp audio disconnecting.", addr.to_string());
260                     }
261                 }
262             }
263         }
264     }
265 
notify_media_capability_added(&self, addr: RawAddress)266     fn notify_media_capability_added(&self, addr: RawAddress) {
267         // Return true if the device added message is sent by the call.
268         fn dedup_added_cb(
269             device_added_tasks: Arc<Mutex<HashMap<RawAddress, Option<JoinHandle<()>>>>>,
270             addr: RawAddress,
271             callbacks: Arc<Mutex<Vec<(u32, Box<dyn IBluetoothMediaCallback + Send>)>>>,
272             device: BluetoothAudioDevice,
273             is_delayed: bool,
274         ) -> bool {
275             // Closure used to lock and trigger the device added callbacks.
276             let trigger_device_added = || {
277                 for callback in &*callbacks.lock().unwrap() {
278                     callback.1.on_bluetooth_audio_device_added(device.clone());
279                 }
280             };
281             let mut guard = device_added_tasks.lock().unwrap();
282             let task = guard.insert(addr, None);
283             match task {
284                 // None handler means the device has just been added
285                 Some(handler) if handler.is_none() => {
286                     warn!("[{}]: A device with the same address has been added.", addr.to_string());
287                     false
288                 }
289                 // Not None handler means there is a pending task.
290                 Some(handler) => {
291                     trigger_device_added();
292 
293                     // Abort the delayed callback if the caller is not delayed.
294                     // Otherwise, it is the delayed callback task itself.
295                     // The abort call can be out of the critical section as we
296                     // have updated the device_added_tasks and send the message.
297                     drop(guard);
298                     if !is_delayed {
299                         handler.unwrap().abort();
300                     }
301                     true
302                 }
303                 // The delayed callback task has been removed and couldn't be found.
304                 None if is_delayed => false,
305                 // No delayed callback and the device hasn't been added.
306                 None => {
307                     trigger_device_added();
308                     true
309                 }
310             }
311         }
312 
313         let cur_a2dp_caps = self.selectable_caps.get(&addr);
314         let cur_hfp_cap = self.hfp_caps.get(&addr);
315         let name = self.adapter_get_remote_name(addr);
316         let absolute_volume = self.absolute_volume;
317         match (cur_a2dp_caps, cur_hfp_cap) {
318             (None, None) => warn!(
319                 "[{}]: Try to add a device without a2dp and hfp capability.",
320                 addr.to_string()
321             ),
322             (Some(caps), Some(hfp_cap)) => {
323                 dedup_added_cb(
324                     self.device_added_tasks.clone(),
325                     addr,
326                     self.callbacks.clone(),
327                     BluetoothAudioDevice::new(
328                         addr.to_string(),
329                         name.clone(),
330                         caps.to_vec(),
331                         *hfp_cap,
332                         absolute_volume,
333                     ),
334                     false,
335                 );
336             }
337             (_, _) => {
338                 let mut guard = self.device_added_tasks.lock().unwrap();
339                 if guard.get(&addr).is_none() {
340                     let callbacks = self.callbacks.clone();
341                     let device_added_tasks = self.device_added_tasks.clone();
342                     let device = BluetoothAudioDevice::new(
343                         addr.to_string(),
344                         name.clone(),
345                         cur_a2dp_caps.unwrap_or(&Vec::new()).to_vec(),
346                         *cur_hfp_cap.unwrap_or(&HfpCodecCapability::UNSUPPORTED),
347                         absolute_volume,
348                     );
349                     let task = topstack::get_runtime().spawn(async move {
350                         sleep(Duration::from_secs(DEFAULT_PROFILE_DISCOVERY_TIMEOUT_SEC)).await;
351                         if dedup_added_cb(device_added_tasks, addr, callbacks, device, true) {
352                             warn!(
353                                 "[{}]: Add a device with only hfp or a2dp capability after timeout.",
354                                 addr.to_string()
355                             );
356                         }
357                     });
358                     guard.insert(addr, Some(task));
359                 }
360             }
361         }
362     }
363 
notify_media_capability_removed(&self, addr: RawAddress)364     fn notify_media_capability_removed(&self, addr: RawAddress) {
365         if let Some(task) = self.device_added_tasks.lock().unwrap().remove(&addr) {
366             match task {
367                 // Abort what is pending
368                 Some(handler) => handler.abort(),
369                 // This addr has been added so tell audio server to remove it
370                 None => self.for_all_callbacks(|callback| {
371                     callback.on_bluetooth_audio_device_removed(addr.to_string());
372                 }),
373             }
374         } else {
375             warn!("[{}]: Device hasn't been added yet.", addr.to_string());
376         }
377     }
378 
for_all_callbacks<F: Fn(&Box<dyn IBluetoothMediaCallback + Send>)>(&self, f: F)379     fn for_all_callbacks<F: Fn(&Box<dyn IBluetoothMediaCallback + Send>)>(&self, f: F) {
380         for callback in &*self.callbacks.lock().unwrap() {
381             f(&callback.1);
382         }
383     }
384 
adapter_get_remote_name(&self, addr: RawAddress) -> String385     fn adapter_get_remote_name(&self, addr: RawAddress) -> String {
386         let device = BluetoothDevice::new(
387             addr.to_string(),
388             // get_remote_name needs a BluetoothDevice just for its address, the
389             // name field is unused so construct one with a fake name.
390             "Classic Device".to_string(),
391         );
392         if let Some(adapter) = &self.adapter {
393             match adapter.lock().unwrap().get_remote_name(device).as_str() {
394                 "" => addr.to_string(),
395                 name => name.into(),
396             }
397         } else {
398             addr.to_string()
399         }
400     }
401 
get_hfp_connection_state(&self) -> u32402     pub fn get_hfp_connection_state(&self) -> u32 {
403         for state in self.hfp_states.values() {
404             return BthfConnectionState::to_u32(state).unwrap_or(0);
405         }
406         0
407     }
408 
get_a2dp_connection_state(&self) -> u32409     pub fn get_a2dp_connection_state(&self) -> u32 {
410         for state in self.a2dp_states.values() {
411             return BtavConnectionState::to_u32(state).unwrap_or(0);
412         }
413         0
414     }
415 }
416 
get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher417 fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher {
418     A2dpCallbacksDispatcher {
419         dispatch: Box::new(move |cb| {
420             let txl = tx.clone();
421             topstack::get_runtime().spawn(async move {
422                 let _ = txl.send(Message::A2dp(cb)).await;
423             });
424         }),
425     }
426 }
427 
get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher428 fn get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher {
429     AvrcpCallbacksDispatcher {
430         dispatch: Box::new(move |cb| {
431             let txl = tx.clone();
432             topstack::get_runtime().spawn(async move {
433                 let _ = txl.send(Message::Avrcp(cb)).await;
434             });
435         }),
436     }
437 }
438 
get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher439 fn get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher {
440     HfpCallbacksDispatcher {
441         dispatch: Box::new(move |cb| {
442             let txl = tx.clone();
443             topstack::get_runtime().spawn(async move {
444                 let _ = txl.send(Message::Hfp(cb)).await;
445             });
446         }),
447     }
448 }
449 
450 impl IBluetoothMedia for BluetoothMedia {
register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool451     fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool {
452         self.callback_last_id += 1;
453         self.callbacks.lock().unwrap().push((self.callback_last_id, callback));
454         true
455     }
456 
initialize(&mut self) -> bool457     fn initialize(&mut self) -> bool {
458         if self.initialized {
459             return false;
460         }
461         self.initialized = true;
462 
463         // TEST A2dp
464         let a2dp_dispatcher = get_a2dp_dispatcher(self.tx.clone());
465         self.a2dp = Some(A2dp::new(&self.intf.lock().unwrap()));
466         self.a2dp.as_mut().unwrap().initialize(a2dp_dispatcher);
467 
468         // AVRCP
469         let avrcp_dispatcher = get_avrcp_dispatcher(self.tx.clone());
470         self.avrcp = Some(Avrcp::new(&self.intf.lock().unwrap()));
471         self.avrcp.as_mut().unwrap().initialize(avrcp_dispatcher);
472 
473         // HFP
474         let hfp_dispatcher = get_hfp_dispatcher(self.tx.clone());
475         self.hfp = Some(Hfp::new(&self.intf.lock().unwrap()));
476         self.hfp.as_mut().unwrap().initialize(hfp_dispatcher);
477 
478         true
479     }
480 
connect(&mut self, device: String)481     fn connect(&mut self, device: String) {
482         if let Some(addr) = RawAddress::from_string(device.clone()) {
483             self.a2dp.as_mut().unwrap().connect(addr);
484             self.hfp.as_mut().unwrap().connect(addr);
485         } else {
486             warn!("Invalid device string {}", device);
487         }
488     }
489 
cleanup(&mut self) -> bool490     fn cleanup(&mut self) -> bool {
491         true
492     }
493 
set_active_device(&mut self, device: String)494     fn set_active_device(&mut self, device: String) {
495         if let Some(addr) = RawAddress::from_string(device.clone()) {
496             self.a2dp.as_mut().unwrap().set_active_device(addr);
497         } else {
498             warn!("Invalid device string {}", device);
499         }
500     }
501 
disconnect(&mut self, device: String)502     fn disconnect(&mut self, device: String) {
503         if let Some(addr) = RawAddress::from_string(device.clone()) {
504             self.a2dp.as_mut().unwrap().disconnect(addr);
505             self.hfp.as_mut().unwrap().disconnect(addr);
506         } else {
507             warn!("Invalid device string {}", device);
508         }
509     }
510 
set_audio_config( &mut self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32, ) -> bool511     fn set_audio_config(
512         &mut self,
513         sample_rate: i32,
514         bits_per_sample: i32,
515         channel_mode: i32,
516     ) -> bool {
517         if !A2dpCodecSampleRate::validate_bits(sample_rate)
518             || !A2dpCodecBitsPerSample::validate_bits(bits_per_sample)
519             || !A2dpCodecChannelMode::validate_bits(channel_mode)
520         {
521             return false;
522         }
523         self.a2dp.as_mut().unwrap().set_audio_config(sample_rate, bits_per_sample, channel_mode);
524         true
525     }
526 
set_volume(&mut self, volume: i32)527     fn set_volume(&mut self, volume: i32) {
528         match i8::try_from(volume) {
529             Ok(val) => self.avrcp.as_mut().unwrap().set_volume(val),
530             _ => (),
531         };
532     }
533 
start_audio_request(&mut self)534     fn start_audio_request(&mut self) {
535         self.a2dp.as_mut().unwrap().start_audio_request();
536     }
537 
stop_audio_request(&mut self)538     fn stop_audio_request(&mut self) {
539         self.a2dp.as_mut().unwrap().stop_audio_request();
540     }
541 
start_sco_call(&mut self, device: String)542     fn start_sco_call(&mut self, device: String) {
543         if let Some(addr) = RawAddress::from_string(device.clone()) {
544             info!("Start sco call for {}", device);
545             match self.hfp.as_mut().unwrap().connect_audio(addr) {
546                 0 => {
547                     info!("SCO connect_audio status success.");
548                 }
549                 x => {
550                     warn!("SCO connect_audio status failed: {}", x);
551                 }
552             };
553         } else {
554             warn!("Can't start sco call with: {}", device);
555         }
556     }
557 
stop_sco_call(&mut self, device: String)558     fn stop_sco_call(&mut self, device: String) {
559         if let Some(addr) = RawAddress::from_string(device.clone()) {
560             info!("Stop sco call for {}", device);
561             self.hfp.as_mut().unwrap().disconnect_audio(addr);
562         } else {
563             warn!("Can't stop sco call with: {}", device);
564         }
565     }
566 
get_presentation_position(&mut self) -> PresentationPosition567     fn get_presentation_position(&mut self) -> PresentationPosition {
568         let position = self.a2dp.as_mut().unwrap().get_presentation_position();
569         PresentationPosition {
570             remote_delay_report_ns: position.remote_delay_report_ns,
571             total_bytes_read: position.total_bytes_read,
572             data_position_sec: position.data_position_sec,
573             data_position_nsec: position.data_position_nsec,
574         }
575     }
576 }
577