1 //! Anything related to audio and media API.
2
3 use bt_topshim::btif::{
4 BluetoothInterface, BtBondState, BtConnectionDirection, BtStatus, DisplayAddress, RawAddress,
5 ToggleableProfile,
6 };
7 use bt_topshim::profiles::a2dp::{
8 A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, A2dpCodecBitsPerSample, A2dpCodecChannelMode,
9 A2dpCodecConfig, A2dpCodecSampleRate, BtavAudioState, BtavConnectionState,
10 PresentationPosition,
11 };
12 use bt_topshim::profiles::avrcp::{
13 Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher, PlayerMetadata,
14 };
15 use bt_topshim::profiles::hfp::{
16 BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallState, Hfp, HfpCallbacks,
17 HfpCallbacksDispatcher, HfpCodecCapability, PhoneState, TelephonyDeviceStatus,
18 };
19 use bt_topshim::profiles::ProfileConnectionState;
20 use bt_topshim::{metrics, topstack};
21 use bt_utils::uinput::UInput;
22
23 use itertools::Itertools;
24 use log::{debug, info, warn};
25 use std::collections::{HashMap, HashSet};
26 use std::convert::TryFrom;
27 use std::sync::Arc;
28 use std::sync::Mutex;
29
30 use tokio::sync::mpsc::Sender;
31 use tokio::task::JoinHandle;
32 use tokio::time::{sleep, Duration, Instant};
33
34 use crate::battery_manager::{Battery, BatterySet};
35 use crate::battery_provider_manager::{
36 BatteryProviderManager, IBatteryProviderCallback, IBatteryProviderManager,
37 };
38 use crate::bluetooth::{Bluetooth, BluetoothDevice, IBluetooth};
39 use crate::callbacks::Callbacks;
40 use crate::uuid;
41 use crate::uuid::Profile;
42 use crate::{Message, RPCProxy};
43
44 // The timeout we have to wait for all supported profiles to connect after we
45 // receive the first profile connected event. The host shall disconnect the
46 // device after this many seconds of timeout.
47 const PROFILE_DISCOVERY_TIMEOUT_SEC: u64 = 10;
48 // The timeout we have to wait for the initiator peer device to complete the
49 // initial profile connection. After this many seconds, we will begin to
50 // connect the missing profiles.
51 // 6s is set to align with Android's default. See "btservice/PhonePolicy".
52 const CONNECT_MISSING_PROFILES_TIMEOUT_SEC: u64 = 6;
53 // The duration we assume the role of the initiator, i.e. the side that starts
54 // the profile connection. If the profile is connected before this many seconds,
55 // we assume we are the initiator and can keep connecting the remaining
56 // profiles, otherwise we wait for the peer initiator.
57 // Set to 5s to align with default page timeout (BT spec vol 4 part E sec 6.6)
58 const CONNECT_AS_INITIATOR_TIMEOUT_SEC: u64 = 5;
59
60 /// The list of profiles we consider as audio profiles for media.
61 const MEDIA_AUDIO_PROFILES: &[uuid::Profile] =
62 &[uuid::Profile::A2dpSink, uuid::Profile::Hfp, uuid::Profile::AvrcpController];
63
64 pub trait IBluetoothMedia {
65 ///
register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool66 fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool;
67
68 /// initializes media (both A2dp and AVRCP) stack
initialize(&mut self) -> bool69 fn initialize(&mut self) -> bool;
70
71 /// clean up media stack
cleanup(&mut self) -> bool72 fn cleanup(&mut self) -> bool;
73
74 /// connect to available but missing media profiles
connect(&mut self, address: String)75 fn connect(&mut self, address: String);
disconnect(&mut self, address: String)76 fn disconnect(&mut self, address: String);
77
78 // Set the device as the active A2DP device
set_active_device(&mut self, address: String)79 fn set_active_device(&mut self, address: String);
80
81 // Reset the active A2DP device
reset_active_device(&mut self)82 fn reset_active_device(&mut self);
83
84 // Set the device as the active HFP device
set_hfp_active_device(&mut self, address: String)85 fn set_hfp_active_device(&mut self, address: String);
86
set_audio_config( &mut self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32, ) -> bool87 fn set_audio_config(
88 &mut self,
89 sample_rate: i32,
90 bits_per_sample: i32,
91 channel_mode: i32,
92 ) -> bool;
93
94 // Set the A2DP/AVRCP volume. Valid volume specified by the spec should be
95 // in the range of 0-127.
set_volume(&mut self, volume: u8)96 fn set_volume(&mut self, volume: u8);
97
98 // Set the HFP speaker volume. Valid volume specified by the HFP spec should
99 // be in the range of 0-15.
set_hfp_volume(&mut self, volume: u8, address: String)100 fn set_hfp_volume(&mut self, volume: u8, address: String);
start_audio_request(&mut self) -> bool101 fn start_audio_request(&mut self) -> bool;
stop_audio_request(&mut self)102 fn stop_audio_request(&mut self);
103
104 /// Returns true iff A2DP audio has started.
get_a2dp_audio_started(&mut self, address: String) -> bool105 fn get_a2dp_audio_started(&mut self, address: String) -> bool;
106
107 /// Returns the negotiated codec (CVSD=1, mSBC=2, LC3=4) to use if HFP audio has started.
108 /// Returns 0 if HFP audio hasn't started.
get_hfp_audio_final_codecs(&mut self, address: String) -> u8109 fn get_hfp_audio_final_codecs(&mut self, address: String) -> u8;
110
get_presentation_position(&mut self) -> PresentationPosition111 fn get_presentation_position(&mut self) -> PresentationPosition;
112
113 /// Start the SCO setup to connect audio
start_sco_call(&mut self, address: String, sco_offload: bool, force_cvsd: bool) -> bool114 fn start_sco_call(&mut self, address: String, sco_offload: bool, force_cvsd: bool) -> bool;
stop_sco_call(&mut self, address: String)115 fn stop_sco_call(&mut self, address: String);
116
117 /// Set the current playback status: e.g., playing, paused, stopped, etc. The method is a copy
118 /// of the existing CRAS API, hence not following Floss API conventions.
set_player_playback_status(&mut self, status: String)119 fn set_player_playback_status(&mut self, status: String);
120 /// Set the position of the current media in microseconds. The method is a copy of the existing
121 /// CRAS API, hence not following Floss API conventions.
set_player_position(&mut self, position: i64)122 fn set_player_position(&mut self, position: i64);
123 /// Set the media metadata, including title, artist, album, and length. The method is a
124 /// copy of the existing CRAS API, hence not following Floss API conventions. PlayerMetadata is
125 /// a custom data type that requires special handlng.
set_player_metadata(&mut self, metadata: PlayerMetadata)126 fn set_player_metadata(&mut self, metadata: PlayerMetadata);
127 }
128
129 pub trait IBluetoothMediaCallback: RPCProxy {
130 /// Triggered when a Bluetooth audio device is ready to be used. This should
131 /// only be triggered once for a device and send an event to clients. If the
132 /// device supports both HFP and A2DP, both should be ready when this is
133 /// triggered.
on_bluetooth_audio_device_added(&mut self, device: BluetoothAudioDevice)134 fn on_bluetooth_audio_device_added(&mut self, device: BluetoothAudioDevice);
135
136 ///
on_bluetooth_audio_device_removed(&mut self, addr: String)137 fn on_bluetooth_audio_device_removed(&mut self, addr: String);
138
139 ///
on_absolute_volume_supported_changed(&mut self, supported: bool)140 fn on_absolute_volume_supported_changed(&mut self, supported: bool);
141
142 /// Triggered when a Bluetooth device triggers an AVRCP/A2DP volume change
143 /// event. We need to notify audio client to reflect the change on the audio
144 /// stack. The volume should be in the range of 0 to 127.
on_absolute_volume_changed(&mut self, volume: u8)145 fn on_absolute_volume_changed(&mut self, volume: u8);
146
147 /// Triggered when a Bluetooth device triggers a HFP AT command (AT+VGS) to
148 /// notify AG about its speaker volume change. We need to notify audio
149 /// client to reflect the change on the audio stack. The volume should be
150 /// in the range of 0 to 15.
on_hfp_volume_changed(&mut self, volume: u8, addr: String)151 fn on_hfp_volume_changed(&mut self, volume: u8, addr: String);
152
153 /// Triggered when HFP audio is disconnected, in which case it could be
154 /// waiting for the audio client to issue a reconnection request. We need
155 /// to notify audio client of this event for it to do appropriate handling.
on_hfp_audio_disconnected(&mut self, addr: String)156 fn on_hfp_audio_disconnected(&mut self, addr: String);
157 }
158
159 pub trait IBluetoothTelephony {
160 /// Sets whether the device is connected to the cellular network.
set_network_available(&mut self, network_available: bool)161 fn set_network_available(&mut self, network_available: bool);
162 /// Sets whether the device is roaming.
set_roaming(&mut self, roaming: bool)163 fn set_roaming(&mut self, roaming: bool);
164 /// Sets the device signal strength, 0 to 5.
set_signal_strength(&mut self, signal_strength: i32) -> bool165 fn set_signal_strength(&mut self, signal_strength: i32) -> bool;
166 /// Sets the device battery level, 0 to 5.
set_battery_level(&mut self, battery_level: i32) -> bool167 fn set_battery_level(&mut self, battery_level: i32) -> bool;
168 /// Enables/disables phone operations.
169 /// The call state is fully reset whenever this is called.
set_phone_ops_enabled(&mut self, enable: bool)170 fn set_phone_ops_enabled(&mut self, enable: bool);
171 /// Acts like the AG received an incoming call.
incoming_call(&mut self, number: String) -> bool172 fn incoming_call(&mut self, number: String) -> bool;
173 /// Acts like dialing a call from the AG.
dialing_call(&mut self, number: String) -> bool174 fn dialing_call(&mut self, number: String) -> bool;
175 /// Acts like answering an incoming/dialing call from the AG.
answer_call(&mut self) -> bool176 fn answer_call(&mut self) -> bool;
177 /// Acts like hanging up an active/incoming/dialing call from the AG.
hangup_call(&mut self) -> bool178 fn hangup_call(&mut self) -> bool;
179 /// Sets/unsets the memory slot. Note that we store at most one memory
180 /// number and return it regardless of which slot is specified by HF.
set_memory_call(&mut self, number: Option<String>) -> bool181 fn set_memory_call(&mut self, number: Option<String>) -> bool;
182 /// Sets/unsets the last call.
set_last_call(&mut self, number: Option<String>) -> bool183 fn set_last_call(&mut self, number: Option<String>) -> bool;
184 /// Releases all of the held calls.
release_held(&mut self) -> bool185 fn release_held(&mut self) -> bool;
186 /// Releases the active call and accepts a held call.
release_active_accept_held(&mut self) -> bool187 fn release_active_accept_held(&mut self) -> bool;
188 /// Holds the active call and accepts a held call.
hold_active_accept_held(&mut self) -> bool189 fn hold_active_accept_held(&mut self) -> bool;
190 /// Establishes an audio connection to <address>.
audio_connect(&mut self, address: String) -> bool191 fn audio_connect(&mut self, address: String) -> bool;
192 /// Stops the audio connection to <address>.
audio_disconnect(&mut self, address: String)193 fn audio_disconnect(&mut self, address: String);
194 }
195
196 /// Serializable device used in.
197 #[derive(Debug, Default, Clone)]
198 pub struct BluetoothAudioDevice {
199 pub address: String,
200 pub name: String,
201 pub a2dp_caps: Vec<A2dpCodecConfig>,
202 pub hfp_cap: HfpCodecCapability,
203 pub absolute_volume: bool,
204 }
205
206 impl BluetoothAudioDevice {
new( address: String, name: String, a2dp_caps: Vec<A2dpCodecConfig>, hfp_cap: HfpCodecCapability, absolute_volume: bool, ) -> BluetoothAudioDevice207 pub(crate) fn new(
208 address: String,
209 name: String,
210 a2dp_caps: Vec<A2dpCodecConfig>,
211 hfp_cap: HfpCodecCapability,
212 absolute_volume: bool,
213 ) -> BluetoothAudioDevice {
214 BluetoothAudioDevice { address, name, a2dp_caps, hfp_cap, absolute_volume }
215 }
216 }
217 /// Actions that `BluetoothMedia` can take on behalf of the stack.
218 pub enum MediaActions {
219 Connect(String),
220 Disconnect(String),
221 ForceEnterConnected(String), // Only used for qualification.
222 }
223
224 #[derive(Debug, Clone, PartialEq)]
225 enum DeviceConnectionStates {
226 Initiating, // Some profile is connected, initiated from host side
227 ConnectingBeforeRetry, // Some profile is connected, probably initiated from peer side
228 ConnectingAfterRetry, // Host initiated requests to missing profiles after timeout
229 FullyConnected, // All profiles (excluding AVRCP) are connected
230 Disconnecting, // Working towards disconnection of each connected profile
231 }
232
233 pub struct BluetoothMedia {
234 intf: Arc<Mutex<BluetoothInterface>>,
235 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
236 battery_provider_id: u32,
237 initialized: bool,
238 callbacks: Arc<Mutex<Callbacks<dyn IBluetoothMediaCallback + Send>>>,
239 tx: Sender<Message>,
240 adapter: Option<Arc<Mutex<Box<Bluetooth>>>>,
241 a2dp: Option<A2dp>,
242 avrcp: Option<Avrcp>,
243 avrcp_direction: BtConnectionDirection,
244 a2dp_states: HashMap<RawAddress, BtavConnectionState>,
245 a2dp_audio_state: HashMap<RawAddress, BtavAudioState>,
246 a2dp_has_interrupted_stream: bool, // Only used for qualification.
247 hfp: Option<Hfp>,
248 hfp_states: HashMap<RawAddress, BthfConnectionState>,
249 hfp_audio_state: HashMap<RawAddress, BthfAudioState>,
250 a2dp_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>,
251 hfp_cap: HashMap<RawAddress, HfpCodecCapability>,
252 fallback_tasks: Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>,
253 absolute_volume: bool,
254 uinput: UInput,
255 delay_enable_profiles: HashSet<uuid::Profile>,
256 connected_profiles: HashMap<RawAddress, HashSet<uuid::Profile>>,
257 device_states: Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>,
258 delay_volume_update: HashMap<uuid::Profile, u8>,
259 telephony_device_status: TelephonyDeviceStatus,
260 phone_state: PhoneState,
261 call_list: Vec<CallInfo>,
262 phone_ops_enabled: bool,
263 memory_dialing_number: Option<String>,
264 last_dialing_number: Option<String>,
265 }
266
267 impl BluetoothMedia {
new( tx: Sender<Message>, intf: Arc<Mutex<BluetoothInterface>>, battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, ) -> BluetoothMedia268 pub fn new(
269 tx: Sender<Message>,
270 intf: Arc<Mutex<BluetoothInterface>>,
271 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
272 ) -> BluetoothMedia {
273 let battery_provider_id = battery_provider_manager
274 .lock()
275 .unwrap()
276 .register_battery_provider(Box::new(BatteryProviderCallback::new()));
277 BluetoothMedia {
278 intf,
279 battery_provider_manager,
280 battery_provider_id,
281 initialized: false,
282 callbacks: Arc::new(Mutex::new(Callbacks::new(
283 tx.clone(),
284 Message::MediaCallbackDisconnected,
285 ))),
286 tx,
287 adapter: None,
288 a2dp: None,
289 avrcp: None,
290 avrcp_direction: BtConnectionDirection::Unknown,
291 a2dp_states: HashMap::new(),
292 a2dp_audio_state: HashMap::new(),
293 a2dp_has_interrupted_stream: false,
294 hfp: None,
295 hfp_states: HashMap::new(),
296 hfp_audio_state: HashMap::new(),
297 a2dp_caps: HashMap::new(),
298 hfp_cap: HashMap::new(),
299 fallback_tasks: Arc::new(Mutex::new(HashMap::new())),
300 absolute_volume: false,
301 uinput: UInput::new(),
302 delay_enable_profiles: HashSet::new(),
303 connected_profiles: HashMap::new(),
304 device_states: Arc::new(Mutex::new(HashMap::new())),
305 delay_volume_update: HashMap::new(),
306 telephony_device_status: TelephonyDeviceStatus::new(),
307 phone_state: PhoneState { num_active: 0, num_held: 0, state: CallState::Idle },
308 call_list: vec![],
309 phone_ops_enabled: false,
310 memory_dialing_number: None,
311 last_dialing_number: None,
312 }
313 }
314
is_profile_connected(&self, addr: &RawAddress, profile: &uuid::Profile) -> bool315 fn is_profile_connected(&self, addr: &RawAddress, profile: &uuid::Profile) -> bool {
316 self.is_any_profile_connected(addr, &[profile.clone()])
317 }
318
is_any_profile_connected(&self, addr: &RawAddress, profiles: &[uuid::Profile]) -> bool319 fn is_any_profile_connected(&self, addr: &RawAddress, profiles: &[uuid::Profile]) -> bool {
320 if let Some(connected_profiles) = self.connected_profiles.get(addr) {
321 return profiles.iter().any(|p| connected_profiles.contains(&p));
322 }
323
324 return false;
325 }
326
add_connected_profile(&mut self, addr: RawAddress, profile: uuid::Profile)327 fn add_connected_profile(&mut self, addr: RawAddress, profile: uuid::Profile) {
328 if self.is_profile_connected(&addr, &profile) {
329 warn!("[{}]: profile is already connected", DisplayAddress(&addr));
330 return;
331 }
332
333 self.connected_profiles.entry(addr).or_insert_with(HashSet::new).insert(profile);
334
335 self.notify_media_capability_updated(addr);
336 }
337
rm_connected_profile( &mut self, addr: RawAddress, profile: uuid::Profile, is_profile_critical: bool, )338 fn rm_connected_profile(
339 &mut self,
340 addr: RawAddress,
341 profile: uuid::Profile,
342 is_profile_critical: bool,
343 ) {
344 if !self.is_profile_connected(&addr, &profile) {
345 warn!("[{}]: profile is already disconnected", DisplayAddress(&addr));
346 return;
347 }
348
349 self.connected_profiles.entry(addr).or_insert_with(HashSet::new).remove(&profile);
350 self.delay_volume_update.remove(&profile);
351
352 if is_profile_critical && self.is_complete_profiles_required() {
353 self.notify_critical_profile_disconnected(addr);
354 }
355
356 self.notify_media_capability_updated(addr);
357 }
358
set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>)359 pub fn set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>) {
360 self.adapter = Some(adapter);
361 }
362
enable_profile(&mut self, profile: &Profile)363 pub fn enable_profile(&mut self, profile: &Profile) {
364 match profile {
365 &Profile::A2dpSource => {
366 if let Some(a2dp) = &mut self.a2dp {
367 a2dp.enable();
368 }
369 }
370 &Profile::AvrcpTarget => {
371 if let Some(avrcp) = &mut self.avrcp {
372 avrcp.enable();
373 }
374 }
375 &Profile::Hfp => {
376 if let Some(hfp) = &mut self.hfp {
377 hfp.enable();
378 }
379 }
380 _ => {
381 warn!("Tried to enable {} in bluetooth_media", profile);
382 return;
383 }
384 }
385
386 if self.is_profile_enabled(profile).unwrap() {
387 self.delay_enable_profiles.remove(profile);
388 } else {
389 self.delay_enable_profiles.insert(profile.clone());
390 }
391 }
392
disable_profile(&mut self, profile: &Profile)393 pub fn disable_profile(&mut self, profile: &Profile) {
394 match profile {
395 &Profile::A2dpSource => {
396 if let Some(a2dp) = &mut self.a2dp {
397 a2dp.disable();
398 }
399 }
400 &Profile::AvrcpTarget => {
401 if let Some(avrcp) = &mut self.avrcp {
402 avrcp.disable();
403 }
404 }
405 &Profile::Hfp => {
406 if let Some(hfp) = &mut self.hfp {
407 hfp.disable();
408 }
409 }
410 _ => {
411 warn!("Tried to disable {} in bluetooth_media", profile);
412 return;
413 }
414 }
415
416 self.delay_enable_profiles.remove(profile);
417 }
418
is_profile_enabled(&self, profile: &Profile) -> Option<bool>419 pub fn is_profile_enabled(&self, profile: &Profile) -> Option<bool> {
420 match profile {
421 &Profile::A2dpSource => {
422 Some(self.a2dp.as_ref().map_or(false, |a2dp| a2dp.is_enabled()))
423 }
424 &Profile::AvrcpTarget => {
425 Some(self.avrcp.as_ref().map_or(false, |avrcp| avrcp.is_enabled()))
426 }
427 &Profile::Hfp => Some(self.hfp.as_ref().map_or(false, |hfp| hfp.is_enabled())),
428 _ => {
429 warn!("Tried to query enablement status of {} in bluetooth_media", profile);
430 None
431 }
432 }
433 }
434
dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks)435 pub fn dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks) {
436 match cb {
437 A2dpCallbacks::ConnectionState(addr, state, error) => {
438 if !self.a2dp_states.get(&addr).is_none()
439 && state == *self.a2dp_states.get(&addr).unwrap()
440 {
441 return;
442 }
443 metrics::profile_connection_state_changed(
444 addr,
445 Profile::A2dpSink as u32,
446 error.status,
447 state.clone() as u32,
448 );
449 match state {
450 BtavConnectionState::Connected => {
451 info!("[{}]: a2dp connected.", DisplayAddress(&addr));
452 self.a2dp_states.insert(addr, state);
453 self.add_connected_profile(addr, uuid::Profile::A2dpSink);
454 }
455 BtavConnectionState::Disconnected => {
456 info!("[{}]: a2dp disconnected.", DisplayAddress(&addr));
457 self.a2dp_states.remove(&addr);
458 self.a2dp_caps.remove(&addr);
459 self.a2dp_audio_state.remove(&addr);
460 self.rm_connected_profile(addr, uuid::Profile::A2dpSink, true);
461 if self.is_complete_profiles_required() {
462 self.disconnect(addr.to_string());
463 }
464 }
465 _ => {
466 self.a2dp_states.insert(addr, state);
467 }
468 }
469 }
470 A2dpCallbacks::AudioState(addr, state) => {
471 self.a2dp_audio_state.insert(addr, state);
472 }
473 A2dpCallbacks::AudioConfig(addr, _config, _local_caps, a2dp_caps) => {
474 debug!("[{}]: a2dp updated audio config: {:?}", DisplayAddress(&addr), a2dp_caps);
475 self.a2dp_caps.insert(addr, a2dp_caps);
476 }
477 A2dpCallbacks::MandatoryCodecPreferred(_addr) => {}
478 }
479 }
480
dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks)481 pub fn dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks) {
482 match cb {
483 AvrcpCallbacks::AvrcpDeviceConnected(addr, supported) => {
484 info!(
485 "[{}]: avrcp connected. Absolute volume support: {}.",
486 DisplayAddress(&addr),
487 supported
488 );
489
490 match self.uinput.create(self.adapter_get_remote_name(addr), addr.to_string()) {
491 Ok(()) => info!("uinput device created for: {}", DisplayAddress(&addr)),
492 Err(e) => warn!("{}", e),
493 }
494
495 // Notify change via callback if device is added.
496 if self.absolute_volume != supported {
497 let guard = self.fallback_tasks.lock().unwrap();
498 if let Some(task) = guard.get(&addr) {
499 if task.is_none() {
500 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
501 callback.on_absolute_volume_supported_changed(supported);
502 });
503 }
504 }
505 }
506
507 self.absolute_volume = supported;
508
509 // If is device initiated the AVRCP connection, emit a fake connecting state as
510 // stack don't receive one.
511 if self.avrcp_direction != BtConnectionDirection::Outgoing {
512 metrics::profile_connection_state_changed(
513 addr,
514 Profile::AvrcpController as u32,
515 BtStatus::Success,
516 BtavConnectionState::Connecting as u32,
517 );
518 }
519 metrics::profile_connection_state_changed(
520 addr,
521 Profile::AvrcpController as u32,
522 BtStatus::Success,
523 BtavConnectionState::Connected as u32,
524 );
525 // Reset direction to unknown.
526 self.avrcp_direction = BtConnectionDirection::Unknown;
527
528 self.add_connected_profile(addr, uuid::Profile::AvrcpController);
529 }
530 AvrcpCallbacks::AvrcpDeviceDisconnected(addr) => {
531 info!("[{}]: avrcp disconnected.", DisplayAddress(&addr));
532
533 self.uinput.close(addr.to_string());
534
535 // TODO: better support for multi-device
536 self.absolute_volume = false;
537
538 // This may be considered a critical profile in the extreme case
539 // where only AVRCP was connected.
540 let is_profile_critical = match self.connected_profiles.get(&addr) {
541 Some(profiles) => *profiles == HashSet::from([uuid::Profile::AvrcpController]),
542 None => false,
543 };
544
545 // If the peer device initiated the AVRCP disconnection, emit a fake connecting
546 // state as stack don't receive one.
547 if self.avrcp_direction != BtConnectionDirection::Outgoing {
548 metrics::profile_connection_state_changed(
549 addr,
550 Profile::AvrcpController as u32,
551 BtStatus::Success,
552 BtavConnectionState::Disconnecting as u32,
553 );
554 }
555 metrics::profile_connection_state_changed(
556 addr,
557 Profile::AvrcpController as u32,
558 BtStatus::Success,
559 BtavConnectionState::Disconnected as u32,
560 );
561 // Reset direction to unknown.
562 self.avrcp_direction = BtConnectionDirection::Unknown;
563
564 self.rm_connected_profile(
565 addr,
566 uuid::Profile::AvrcpController,
567 is_profile_critical,
568 );
569 }
570 AvrcpCallbacks::AvrcpAbsoluteVolumeUpdate(volume) => {
571 for (addr, state) in self.device_states.lock().unwrap().iter() {
572 info!("[{}]: state {:?}", DisplayAddress(&addr), state);
573 match state {
574 DeviceConnectionStates::ConnectingBeforeRetry
575 | DeviceConnectionStates::ConnectingAfterRetry => {
576 self.delay_volume_update.insert(Profile::AvrcpController, volume);
577 }
578 DeviceConnectionStates::FullyConnected => {
579 self.delay_volume_update.remove(&Profile::AvrcpController);
580 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
581 callback.on_absolute_volume_changed(volume);
582 });
583 return;
584 }
585 _ => {}
586 }
587 }
588 }
589 AvrcpCallbacks::AvrcpSendKeyEvent(key, value) => {
590 match self.uinput.send_key(key, value) {
591 Ok(()) => (),
592 Err(e) => warn!("{}", e),
593 }
594
595 const AVRCP_ID_PAUSE: u8 = 0x46;
596 const AVRCP_STATE_PRESS: u8 = 0;
597
598 // Per MPS v1.0, on receiving a pause key through AVRCP,
599 // central should pause the A2DP stream with an AVDTP suspend command.
600 if self.phone_ops_enabled && key == AVRCP_ID_PAUSE && value == AVRCP_STATE_PRESS {
601 self.suspend_audio_request_impl();
602 }
603 }
604 AvrcpCallbacks::AvrcpSetActiveDevice(addr) => {
605 self.uinput.set_active_device(addr.to_string());
606 }
607 }
608 }
609
dispatch_media_actions(&mut self, action: MediaActions)610 pub fn dispatch_media_actions(&mut self, action: MediaActions) {
611 match action {
612 MediaActions::Connect(address) => self.connect(address),
613 MediaActions::Disconnect(address) => self.disconnect(address),
614 MediaActions::ForceEnterConnected(address) => self.force_enter_connected(address),
615 }
616 }
617
dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks)618 pub fn dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks) {
619 match cb {
620 HfpCallbacks::ConnectionState(state, addr) => {
621 if !self.hfp_states.get(&addr).is_none()
622 && state == *self.hfp_states.get(&addr).unwrap()
623 {
624 return;
625 }
626 metrics::profile_connection_state_changed(
627 addr,
628 Profile::Hfp as u32,
629 BtStatus::Success,
630 state.clone() as u32,
631 );
632 match state {
633 BthfConnectionState::Connected => {
634 info!("[{}]: hfp connected.", DisplayAddress(&addr));
635 }
636 BthfConnectionState::SlcConnected => {
637 info!("[{}]: hfp slc connected.", DisplayAddress(&addr));
638 // The device may not support codec-negotiation,
639 // in which case we shall assume it supports CVSD at this point.
640 if !self.hfp_cap.contains_key(&addr) {
641 self.hfp_cap.insert(addr, HfpCodecCapability::CVSD);
642 }
643 self.add_connected_profile(addr, uuid::Profile::Hfp);
644
645 // Connect SCO if phone operations are enabled and an active call exists.
646 // This is only used for Bluetooth HFP qualification.
647 if self.phone_ops_enabled && self.phone_state.num_active > 0 {
648 debug!("[{}]: Connect SCO due to active call.", DisplayAddress(&addr));
649 self.start_sco_call_impl(addr.to_string(), false, false);
650 }
651 }
652 BthfConnectionState::Disconnected => {
653 info!("[{}]: hfp disconnected.", DisplayAddress(&addr));
654 self.hfp_states.remove(&addr);
655 self.hfp_cap.remove(&addr);
656 self.hfp_audio_state.remove(&addr);
657 self.rm_connected_profile(addr, uuid::Profile::Hfp, true);
658 if self.is_complete_profiles_required() {
659 self.disconnect(addr.to_string());
660 }
661 }
662 BthfConnectionState::Connecting => {
663 info!("[{}]: hfp connecting.", DisplayAddress(&addr));
664 }
665 BthfConnectionState::Disconnecting => {
666 info!("[{}]: hfp disconnecting.", DisplayAddress(&addr));
667 }
668 }
669
670 self.hfp_states.insert(addr, state);
671 }
672 HfpCallbacks::AudioState(state, addr) => {
673 if self.hfp_states.get(&addr).is_none()
674 || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap()
675 {
676 warn!("[{}]: Unknown address hfp or slc not ready", DisplayAddress(&addr));
677 return;
678 }
679
680 match state {
681 BthfAudioState::Connected => {
682 info!("[{}]: hfp audio connected.", DisplayAddress(&addr));
683
684 self.hfp_audio_state.insert(addr, state);
685
686 // Change the phone state only when it's currently managed by media stack
687 // (I.e., phone operations are not enabled).
688 if !self.phone_ops_enabled && self.phone_state.num_active != 1 {
689 // This triggers a +CIEV command to set the call status for HFP devices.
690 // It is required for some devices to provide sound.
691 self.phone_state.num_active = 1;
692 self.call_list = vec![CallInfo {
693 index: 1,
694 dir_incoming: false,
695 state: CallState::Active,
696 number: "".into(),
697 }];
698 self.phone_state_change("".into());
699 }
700 }
701 BthfAudioState::Disconnected => {
702 info!("[{}]: hfp audio disconnected.", DisplayAddress(&addr));
703
704 // Ignore disconnected -> disconnected
705 if let Some(BthfAudioState::Connected) =
706 self.hfp_audio_state.insert(addr, state)
707 {
708 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
709 callback.on_hfp_audio_disconnected(addr.to_string());
710 });
711 }
712
713 // Change the phone state only when it's currently managed by media stack
714 // (I.e., phone operations are not enabled).
715 if !self.phone_ops_enabled && self.phone_state.num_active != 0 {
716 self.phone_state.num_active = 0;
717 self.call_list = vec![];
718 self.phone_state_change("".into());
719 }
720
721 // Resume the A2DP stream when a phone call ended (per MPS v1.0).
722 self.try_a2dp_resume();
723 }
724 BthfAudioState::Connecting => {
725 info!("[{}]: hfp audio connecting.", DisplayAddress(&addr));
726 }
727 BthfAudioState::Disconnecting => {
728 info!("[{}]: hfp audio disconnecting.", DisplayAddress(&addr));
729 }
730 }
731 }
732 HfpCallbacks::VolumeUpdate(volume, addr) => {
733 if self.hfp_states.get(&addr).is_none()
734 || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap()
735 {
736 warn!("[{}]: Unknown address hfp or slc not ready", addr.to_string());
737 return;
738 }
739
740 let states = self.device_states.lock().unwrap();
741 info!(
742 "[{}]: VolumeUpdate state: {:?}",
743 DisplayAddress(&addr),
744 states.get(&addr).unwrap()
745 );
746 match states.get(&addr).unwrap() {
747 DeviceConnectionStates::ConnectingBeforeRetry
748 | DeviceConnectionStates::ConnectingAfterRetry => {
749 self.delay_volume_update.insert(Profile::Hfp, volume);
750 }
751 DeviceConnectionStates::FullyConnected => {
752 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
753 callback.on_hfp_volume_changed(volume, addr.to_string());
754 });
755 }
756 _ => {}
757 }
758 }
759 HfpCallbacks::BatteryLevelUpdate(battery_level, addr) => {
760 let battery_set = BatterySet::new(
761 addr.to_string(),
762 uuid::HFP.to_string(),
763 "HFP".to_string(),
764 vec![Battery { percentage: battery_level as u32, variant: "".to_string() }],
765 );
766 self.battery_provider_manager
767 .lock()
768 .unwrap()
769 .set_battery_info(self.battery_provider_id, battery_set);
770 }
771 HfpCallbacks::WbsCapsUpdate(wbs_supported, addr) => {
772 if let Some(cur_hfp_cap) = self.hfp_cap.get_mut(&addr) {
773 if wbs_supported {
774 *cur_hfp_cap |= HfpCodecCapability::MSBC;
775 } else if (*cur_hfp_cap & HfpCodecCapability::MSBC) == HfpCodecCapability::MSBC
776 {
777 *cur_hfp_cap ^= HfpCodecCapability::MSBC;
778 }
779 } else {
780 let new_hfp_cap = match wbs_supported {
781 true => HfpCodecCapability::CVSD | HfpCodecCapability::MSBC,
782 false => HfpCodecCapability::CVSD,
783 };
784 self.hfp_cap.insert(addr, new_hfp_cap);
785 }
786 }
787 HfpCallbacks::SwbCapsUpdate(swb_supported, addr) => {
788 if let Some(cur_hfp_cap) = self.hfp_cap.get_mut(&addr) {
789 if swb_supported {
790 *cur_hfp_cap |= HfpCodecCapability::LC3;
791 } else if (*cur_hfp_cap & HfpCodecCapability::LC3) == HfpCodecCapability::LC3 {
792 *cur_hfp_cap ^= HfpCodecCapability::LC3;
793 }
794 } else {
795 let new_hfp_cap = match swb_supported {
796 true => HfpCodecCapability::CVSD | HfpCodecCapability::LC3,
797 false => HfpCodecCapability::CVSD,
798 };
799 self.hfp_cap.insert(addr, new_hfp_cap);
800 }
801 }
802 HfpCallbacks::IndicatorQuery(addr) => {
803 match self.hfp.as_mut() {
804 Some(hfp) => {
805 debug!(
806 "[{}]: Responding CIND query with device={:?} phone={:?}",
807 DisplayAddress(&addr),
808 self.telephony_device_status,
809 self.phone_state,
810 );
811 let status = hfp.indicator_query_response(
812 self.telephony_device_status,
813 self.phone_state,
814 addr,
815 );
816 if status != BtStatus::Success {
817 warn!(
818 "[{}]: CIND response failed, status={:?}",
819 DisplayAddress(&addr),
820 status
821 );
822 }
823 }
824 None => warn!("Uninitialized HFP to notify telephony status"),
825 };
826 }
827 HfpCallbacks::CurrentCallsQuery(addr) => {
828 match self.hfp.as_mut() {
829 Some(hfp) => {
830 debug!(
831 "[{}]: Responding CLCC query with call_list={:?}",
832 DisplayAddress(&addr),
833 self.call_list,
834 );
835 let status = hfp.current_calls_query_response(&self.call_list, addr);
836 if status != BtStatus::Success {
837 warn!(
838 "[{}]: CLCC response failed, status={:?}",
839 DisplayAddress(&addr),
840 status
841 );
842 }
843 }
844 None => warn!("Uninitialized HFP to notify telephony status"),
845 };
846 }
847 HfpCallbacks::AnswerCall(addr) => {
848 if !self.answer_call_impl() {
849 warn!("[{}]: answer_call triggered by ATA failed", DisplayAddress(&addr));
850 return;
851 }
852 self.phone_state_change("".into());
853
854 debug!("[{}]: Start SCO call due to ATA", DisplayAddress(&addr));
855 self.start_sco_call_impl(addr.to_string(), false, false);
856 }
857 HfpCallbacks::HangupCall(addr) => {
858 if !self.hangup_call_impl() {
859 warn!("[{}]: hangup_call triggered by AT+CHUP failed", DisplayAddress(&addr));
860 return;
861 }
862 self.phone_state_change("".into());
863
864 // Try resume the A2DP stream (per MPS v1.0) on rejecting an incoming call or an
865 // outgoing call is rejected.
866 // It may fail if a SCO connection is still active (terminate call case), in that
867 // case we will retry on SCO disconnected.
868 self.try_a2dp_resume();
869 }
870 HfpCallbacks::DialCall(number, addr) => {
871 let number = if number == "" {
872 self.last_dialing_number.clone()
873 } else if number.starts_with(">") {
874 self.memory_dialing_number.clone()
875 } else {
876 Some(number)
877 };
878
879 let success = number.map_or(false, |num| self.dialing_call_impl(num));
880
881 // Respond OK/ERROR to the HF which sent the command.
882 // This should be called before calling phone_state_change.
883 self.simple_at_response(success, addr.clone());
884 if !success {
885 warn!("[{}]: Unexpected dialing command from HF", DisplayAddress(&addr));
886 return;
887 }
888 // Inform libbluetooth that the state has changed to dialing.
889 self.phone_state_change("".into());
890 self.try_a2dp_suspend();
891 // Change to alerting state and inform libbluetooth.
892 self.dialing_to_alerting();
893 self.phone_state_change("".into());
894 }
895 HfpCallbacks::CallHold(command, addr) => {
896 let success = match command {
897 CallHoldCommand::ReleaseHeld => self.release_held_impl(),
898 CallHoldCommand::ReleaseActiveAcceptHeld => {
899 self.release_active_accept_held_impl()
900 }
901 CallHoldCommand::HoldActiveAcceptHeld => self.hold_active_accept_held_impl(),
902 _ => false, // We only support the 3 operations above.
903 };
904 // Respond OK/ERROR to the HF which sent the command.
905 // This should be called before calling phone_state_change.
906 self.simple_at_response(success, addr.clone());
907 if success {
908 // Success means the call state has changed. Inform libbluetooth.
909 self.phone_state_change("".into());
910 } else {
911 warn!(
912 "[{}]: Unexpected or unsupported CHLD command {:?} from HF",
913 DisplayAddress(&addr),
914 command
915 );
916 }
917 }
918 }
919 }
920
remove_callback(&mut self, id: u32) -> bool921 pub fn remove_callback(&mut self, id: u32) -> bool {
922 self.callbacks.lock().unwrap().remove_callback(id)
923 }
924
notify_critical_profile_disconnected(&mut self, addr: RawAddress)925 fn notify_critical_profile_disconnected(&mut self, addr: RawAddress) {
926 info!(
927 "[{}]: Device connection state: {:?}.",
928 DisplayAddress(&addr),
929 DeviceConnectionStates::Disconnecting
930 );
931
932 let mut states = self.device_states.lock().unwrap();
933 let prev_state = states.insert(addr, DeviceConnectionStates::Disconnecting).unwrap();
934 if prev_state != DeviceConnectionStates::Disconnecting {
935 let mut guard = self.fallback_tasks.lock().unwrap();
936 if let Some(task) = guard.get(&addr) {
937 match task {
938 // Abort pending task if there is any.
939 Some((handler, _ts)) => {
940 warn!(
941 "[{}]: Device disconnected a critical profile before it was added.",
942 DisplayAddress(&addr)
943 );
944 handler.abort();
945 guard.insert(addr, None);
946 }
947 // Notify device removal if it has been added.
948 None => {
949 info!(
950 "[{}]: Device disconnected a critical profile, removing the device.",
951 DisplayAddress(&addr)
952 );
953 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
954 callback.on_bluetooth_audio_device_removed(addr.to_string());
955 });
956 }
957 };
958 }
959 self.delay_volume_update.clear();
960 }
961 }
962
wait_retry( _fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>, device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>, txl: &Sender<Message>, addr: &RawAddress, first_conn_ts: Instant, )963 async fn wait_retry(
964 _fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>,
965 device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>,
966 txl: &Sender<Message>,
967 addr: &RawAddress,
968 first_conn_ts: Instant,
969 ) {
970 let now_ts = Instant::now();
971 let total_duration = Duration::from_secs(CONNECT_MISSING_PROFILES_TIMEOUT_SEC);
972 let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts);
973 sleep(sleep_duration).await;
974
975 device_states.lock().unwrap().insert(*addr, DeviceConnectionStates::ConnectingAfterRetry);
976
977 info!(
978 "[{}]: Device connection state: {:?}.",
979 DisplayAddress(addr),
980 DeviceConnectionStates::ConnectingAfterRetry
981 );
982
983 let _ = txl.send(Message::Media(MediaActions::Connect(addr.to_string()))).await;
984 }
985
wait_disconnect( fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>, device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>, txl: &Sender<Message>, addr: &RawAddress, first_conn_ts: Instant, )986 async fn wait_disconnect(
987 fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>,
988 device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>,
989 txl: &Sender<Message>,
990 addr: &RawAddress,
991 first_conn_ts: Instant,
992 ) {
993 let now_ts = Instant::now();
994 let total_duration = Duration::from_secs(PROFILE_DISCOVERY_TIMEOUT_SEC);
995 let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts);
996 sleep(sleep_duration).await;
997
998 device_states.lock().unwrap().insert(*addr, DeviceConnectionStates::Disconnecting);
999 fallback_tasks.lock().unwrap().insert(*addr, None);
1000
1001 info!(
1002 "[{}]: Device connection state: {:?}.",
1003 DisplayAddress(addr),
1004 DeviceConnectionStates::Disconnecting
1005 );
1006
1007 let _ = txl.send(Message::Media(MediaActions::Disconnect(addr.to_string()))).await;
1008 }
1009
wait_force_enter_connected( txl: &Sender<Message>, addr: &RawAddress, first_conn_ts: Instant, )1010 async fn wait_force_enter_connected(
1011 txl: &Sender<Message>,
1012 addr: &RawAddress,
1013 first_conn_ts: Instant,
1014 ) {
1015 let now_ts = Instant::now();
1016 let total_duration = Duration::from_secs(CONNECT_MISSING_PROFILES_TIMEOUT_SEC);
1017 let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts);
1018 sleep(sleep_duration).await;
1019 let _ = txl.send(Message::Media(MediaActions::ForceEnterConnected(addr.to_string()))).await;
1020 }
1021
notify_media_capability_updated(&mut self, addr: RawAddress)1022 fn notify_media_capability_updated(&mut self, addr: RawAddress) {
1023 let mut guard = self.fallback_tasks.lock().unwrap();
1024 let mut states = self.device_states.lock().unwrap();
1025 let mut first_conn_ts = Instant::now();
1026
1027 let is_profile_cleared = self.connected_profiles.get(&addr).unwrap().is_empty();
1028
1029 if let Some(task) = guard.get(&addr) {
1030 if let Some((handler, ts)) = task {
1031 // Abort the pending task. It may be updated or
1032 // removed depending on whether all profiles are cleared.
1033 handler.abort();
1034 first_conn_ts = *ts;
1035 guard.insert(addr, None);
1036 } else {
1037 // The device is already added or is disconnecting.
1038 // Ignore unless all profiles are cleared.
1039 if !is_profile_cleared {
1040 return;
1041 }
1042 }
1043 }
1044
1045 // Cleanup if transitioning to empty set.
1046 if is_profile_cleared {
1047 info!("[{}]: Device connection state: Disconnected.", DisplayAddress(&addr));
1048 self.connected_profiles.remove(&addr);
1049 states.remove(&addr);
1050 guard.remove(&addr);
1051 return;
1052 }
1053
1054 let available_profiles = self.adapter_get_audio_profiles(addr);
1055 let connected_profiles = self.connected_profiles.get(&addr).unwrap();
1056 let missing_profiles =
1057 available_profiles.difference(&connected_profiles).cloned().collect::<HashSet<_>>();
1058
1059 // Update device states
1060 if states.get(&addr).is_none() {
1061 states.insert(addr, DeviceConnectionStates::ConnectingBeforeRetry);
1062 }
1063 if missing_profiles.is_empty()
1064 || missing_profiles == HashSet::from([Profile::AvrcpController])
1065 {
1066 info!(
1067 "[{}]: Fully connected, available profiles: {:?}, connected profiles: {:?}.",
1068 DisplayAddress(&addr),
1069 available_profiles,
1070 connected_profiles
1071 );
1072
1073 states.insert(addr, DeviceConnectionStates::FullyConnected);
1074 }
1075
1076 info!(
1077 "[{}]: Device connection state: {:?}.",
1078 DisplayAddress(&addr),
1079 states.get(&addr).unwrap()
1080 );
1081
1082 // React on updated device states
1083 let tasks = self.fallback_tasks.clone();
1084 let device_states = self.device_states.clone();
1085 let txl = self.tx.clone();
1086 let ts = first_conn_ts;
1087 let is_complete_profiles_required = self.is_complete_profiles_required();
1088 match states.get(&addr).unwrap() {
1089 DeviceConnectionStates::Initiating => {
1090 let task = topstack::get_runtime().spawn(async move {
1091 // As initiator we can just immediately start connecting
1092 let _ = txl.send(Message::Media(MediaActions::Connect(addr.to_string()))).await;
1093 if !is_complete_profiles_required {
1094 BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
1095 return;
1096 }
1097 BluetoothMedia::wait_retry(&tasks, &device_states, &txl, &addr, ts).await;
1098 BluetoothMedia::wait_disconnect(&tasks, &device_states, &txl, &addr, ts).await;
1099 });
1100 guard.insert(addr, Some((task, ts)));
1101 }
1102 DeviceConnectionStates::ConnectingBeforeRetry => {
1103 let task = topstack::get_runtime().spawn(async move {
1104 if !is_complete_profiles_required {
1105 BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
1106 return;
1107 }
1108 BluetoothMedia::wait_retry(&tasks, &device_states, &txl, &addr, ts).await;
1109 BluetoothMedia::wait_disconnect(&tasks, &device_states, &txl, &addr, ts).await;
1110 });
1111 guard.insert(addr, Some((task, ts)));
1112 }
1113 DeviceConnectionStates::ConnectingAfterRetry => {
1114 let task = topstack::get_runtime().spawn(async move {
1115 if !is_complete_profiles_required {
1116 BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
1117 return;
1118 }
1119 BluetoothMedia::wait_disconnect(&tasks, &device_states, &txl, &addr, ts).await;
1120 });
1121 guard.insert(addr, Some((task, ts)));
1122 }
1123 DeviceConnectionStates::FullyConnected => {
1124 // Rejecting the unbonded connection after we finished our profile
1125 // reconnectinglogic to avoid a collision.
1126 if let Some(adapter) = &self.adapter {
1127 if BtBondState::Bonded
1128 != adapter.lock().unwrap().get_bond_state_by_addr(&addr.to_string())
1129 {
1130 warn!(
1131 "[{}]: Rejecting a unbonded device's attempt to connect to media profiles",
1132 DisplayAddress(&addr));
1133 let fallback_tasks = self.fallback_tasks.clone();
1134 let device_states = self.device_states.clone();
1135 let txl = self.tx.clone();
1136 let task = topstack::get_runtime().spawn(async move {
1137 {
1138 device_states
1139 .lock()
1140 .unwrap()
1141 .insert(addr, DeviceConnectionStates::Disconnecting);
1142 fallback_tasks.lock().unwrap().insert(addr, None);
1143 }
1144
1145 debug!(
1146 "[{}]: Device connection state: {:?}.",
1147 DisplayAddress(&addr),
1148 DeviceConnectionStates::Disconnecting
1149 );
1150
1151 let _ = txl
1152 .send(Message::Media(MediaActions::Disconnect(addr.to_string())))
1153 .await;
1154 });
1155 guard.insert(addr, Some((task, first_conn_ts)));
1156 return;
1157 }
1158 }
1159
1160 let cur_a2dp_caps = self.a2dp_caps.get(&addr);
1161 let cur_hfp_cap = self.hfp_cap.get(&addr);
1162 let name = self.adapter_get_remote_name(addr);
1163 let absolute_volume = self.absolute_volume;
1164 let device = BluetoothAudioDevice::new(
1165 addr.to_string(),
1166 name.clone(),
1167 cur_a2dp_caps.unwrap_or(&Vec::new()).to_vec(),
1168 *cur_hfp_cap.unwrap_or(&HfpCodecCapability::UNSUPPORTED),
1169 absolute_volume,
1170 );
1171
1172 let hfp_volume = self.delay_volume_update.remove(&Profile::Hfp);
1173 let avrcp_volume = self.delay_volume_update.remove(&Profile::AvrcpController);
1174
1175 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1176 callback.on_bluetooth_audio_device_added(device.clone());
1177 if let Some(volume) = hfp_volume {
1178 info!("Trigger HFP volume update to {}", DisplayAddress(&addr));
1179 callback.on_hfp_volume_changed(volume, addr.to_string());
1180 }
1181
1182 if let Some(volume) = avrcp_volume {
1183 info!("Trigger avrcp volume update");
1184 callback.on_absolute_volume_changed(volume);
1185 }
1186 });
1187
1188 guard.insert(addr, None);
1189 }
1190 DeviceConnectionStates::Disconnecting => {}
1191 }
1192 }
1193
adapter_get_remote_name(&self, addr: RawAddress) -> String1194 fn adapter_get_remote_name(&self, addr: RawAddress) -> String {
1195 let device = BluetoothDevice::new(
1196 addr.to_string(),
1197 // get_remote_name needs a BluetoothDevice just for its address, the
1198 // name field is unused so construct one with a fake name.
1199 "Classic Device".to_string(),
1200 );
1201 if let Some(adapter) = &self.adapter {
1202 match adapter.lock().unwrap().get_remote_name(device).as_str() {
1203 "" => addr.to_string(),
1204 name => name.into(),
1205 }
1206 } else {
1207 addr.to_string()
1208 }
1209 }
1210
adapter_get_audio_profiles(&self, addr: RawAddress) -> HashSet<uuid::Profile>1211 fn adapter_get_audio_profiles(&self, addr: RawAddress) -> HashSet<uuid::Profile> {
1212 let device = BluetoothDevice::new(addr.to_string(), "".to_string());
1213 if let Some(adapter) = &self.adapter {
1214 adapter
1215 .lock()
1216 .unwrap()
1217 .get_remote_uuids(device)
1218 .into_iter()
1219 .map(|u| uuid::UuidHelper::is_known_profile(&u))
1220 .filter(|u| u.is_some())
1221 .map(|u| u.unwrap())
1222 .filter(|u| MEDIA_AUDIO_PROFILES.contains(&u))
1223 .collect()
1224 } else {
1225 HashSet::new()
1226 }
1227 }
1228
get_hfp_connection_state(&self) -> ProfileConnectionState1229 pub fn get_hfp_connection_state(&self) -> ProfileConnectionState {
1230 if self.hfp_audio_state.values().any(|state| *state == BthfAudioState::Connected) {
1231 ProfileConnectionState::Active
1232 } else {
1233 let mut winning_state = ProfileConnectionState::Disconnected;
1234 for state in self.hfp_states.values() {
1235 // Grab any state higher than the current state.
1236 match state {
1237 // Any SLC completed state means the profile is connected.
1238 BthfConnectionState::SlcConnected => {
1239 winning_state = ProfileConnectionState::Connected;
1240 }
1241
1242 // Connecting or Connected are both counted as connecting for profile state
1243 // since it's not a complete connection.
1244 BthfConnectionState::Connecting | BthfConnectionState::Connected
1245 if winning_state != ProfileConnectionState::Connected =>
1246 {
1247 winning_state = ProfileConnectionState::Connecting;
1248 }
1249
1250 BthfConnectionState::Disconnecting
1251 if winning_state == ProfileConnectionState::Disconnected =>
1252 {
1253 winning_state = ProfileConnectionState::Disconnecting;
1254 }
1255
1256 _ => (),
1257 }
1258 }
1259
1260 winning_state
1261 }
1262 }
1263
get_a2dp_connection_state(&self) -> ProfileConnectionState1264 pub fn get_a2dp_connection_state(&self) -> ProfileConnectionState {
1265 if self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
1266 ProfileConnectionState::Active
1267 } else {
1268 let mut winning_state = ProfileConnectionState::Disconnected;
1269 for state in self.a2dp_states.values() {
1270 // Grab any state higher than the current state.
1271 match state {
1272 BtavConnectionState::Connected => {
1273 winning_state = ProfileConnectionState::Connected;
1274 }
1275
1276 BtavConnectionState::Connecting
1277 if winning_state != ProfileConnectionState::Connected =>
1278 {
1279 winning_state = ProfileConnectionState::Connecting;
1280 }
1281
1282 BtavConnectionState::Disconnecting
1283 if winning_state == ProfileConnectionState::Disconnected =>
1284 {
1285 winning_state = ProfileConnectionState::Disconnecting;
1286 }
1287
1288 _ => (),
1289 }
1290 }
1291
1292 winning_state
1293 }
1294 }
1295
filter_to_connected_audio_devices_from( &self, devices: &Vec<BluetoothDevice>, ) -> Vec<BluetoothDevice>1296 pub fn filter_to_connected_audio_devices_from(
1297 &self,
1298 devices: &Vec<BluetoothDevice>,
1299 ) -> Vec<BluetoothDevice> {
1300 devices
1301 .iter()
1302 .filter(|d| {
1303 let addr = match RawAddress::from_string(&d.address) {
1304 None => return false,
1305 Some(a) => a,
1306 };
1307
1308 self.is_any_profile_connected(&addr, &MEDIA_AUDIO_PROFILES)
1309 })
1310 .cloned()
1311 .collect()
1312 }
1313
start_audio_request_impl(&mut self) -> bool1314 fn start_audio_request_impl(&mut self) -> bool {
1315 debug!("Start audio request");
1316
1317 match self.a2dp.as_mut() {
1318 Some(a2dp) => a2dp.start_audio_request(),
1319 None => {
1320 warn!("Uninitialized A2DP to start audio request");
1321 false
1322 }
1323 }
1324 }
1325
suspend_audio_request_impl(&mut self)1326 fn suspend_audio_request_impl(&mut self) {
1327 match self.a2dp.as_mut() {
1328 Some(a2dp) => a2dp.suspend_audio_request(),
1329 None => warn!("Uninitialized A2DP to suspend audio request"),
1330 };
1331 }
1332
try_a2dp_resume(&mut self)1333 fn try_a2dp_resume(&mut self) {
1334 if !self.phone_ops_enabled {
1335 return;
1336 }
1337 // Make sure there is no any SCO connection and then resume the A2DP stream.
1338 if self.a2dp_has_interrupted_stream
1339 && !self.hfp_audio_state.values().any(|state| *state == BthfAudioState::Connected)
1340 {
1341 self.a2dp_has_interrupted_stream = false;
1342 self.start_audio_request_impl();
1343 }
1344 }
1345
try_a2dp_suspend(&mut self)1346 fn try_a2dp_suspend(&mut self) {
1347 if !self.phone_ops_enabled {
1348 return;
1349 }
1350 // Suspend the A2DP stream if there is any.
1351 if self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
1352 self.a2dp_has_interrupted_stream = true;
1353 self.suspend_audio_request_impl();
1354 }
1355 }
1356
start_sco_call_impl( &mut self, address: String, sco_offload: bool, force_cvsd: bool, ) -> bool1357 fn start_sco_call_impl(
1358 &mut self,
1359 address: String,
1360 sco_offload: bool,
1361 force_cvsd: bool,
1362 ) -> bool {
1363 match (|| -> Result<(), &str> {
1364 let addr = RawAddress::from_string(address.clone())
1365 .ok_or("Can't start sco call with bad address")?;
1366 info!("Start sco call for {}", DisplayAddress(&addr));
1367
1368 let hfp = self.hfp.as_mut().ok_or("Uninitialized HFP to start the sco call")?;
1369 if hfp.connect_audio(addr, sco_offload, force_cvsd) != 0 {
1370 return Err("SCO connect_audio status failed");
1371 }
1372 info!("SCO connect_audio status success");
1373 Ok(())
1374 })() {
1375 Ok(_) => true,
1376 Err(msg) => {
1377 warn!("{}", msg);
1378 false
1379 }
1380 }
1381 }
1382
stop_sco_call_impl(&mut self, address: String)1383 fn stop_sco_call_impl(&mut self, address: String) {
1384 match (|| -> Result<(), &str> {
1385 let addr = RawAddress::from_string(address.clone())
1386 .ok_or("Can't stop sco call with bad address")?;
1387 info!("Stop sco call for {}", DisplayAddress(&addr));
1388 let hfp = self.hfp.as_mut().ok_or("Uninitialized HFP to stop the sco call")?;
1389 hfp.disconnect_audio(addr);
1390 Ok(())
1391 })() {
1392 Ok(_) => {}
1393 Err(msg) => warn!("{}", msg),
1394 }
1395 }
1396
device_status_notification(&mut self)1397 fn device_status_notification(&mut self) {
1398 match self.hfp.as_mut() {
1399 Some(hfp) => {
1400 for (addr, state) in self.hfp_states.iter() {
1401 if *state != BthfConnectionState::SlcConnected {
1402 continue;
1403 }
1404 debug!(
1405 "[{}]: Device status notification {:?}",
1406 DisplayAddress(addr),
1407 self.telephony_device_status
1408 );
1409 let status =
1410 hfp.device_status_notification(self.telephony_device_status, addr.clone());
1411 if status != BtStatus::Success {
1412 warn!(
1413 "[{}]: Device status notification failed, status={:?}",
1414 DisplayAddress(addr),
1415 status
1416 );
1417 }
1418 }
1419 }
1420 None => warn!("Uninitialized HFP to notify telephony status"),
1421 }
1422 }
1423
phone_state_change(&mut self, number: String)1424 fn phone_state_change(&mut self, number: String) {
1425 match self.hfp.as_mut() {
1426 Some(hfp) => {
1427 for (addr, state) in self.hfp_states.iter() {
1428 if *state != BthfConnectionState::SlcConnected {
1429 continue;
1430 }
1431 debug!(
1432 "[{}]: Phone state change state={:?} number={}",
1433 DisplayAddress(addr),
1434 self.phone_state,
1435 number
1436 );
1437 let status = hfp.phone_state_change(self.phone_state, &number, addr.clone());
1438 if status != BtStatus::Success {
1439 warn!(
1440 "[{}]: Device status notification failed, status={:?}",
1441 DisplayAddress(addr),
1442 status
1443 );
1444 }
1445 }
1446 }
1447 None => warn!("Uninitialized HFP to notify telephony status"),
1448 }
1449 }
1450
1451 // Returns the minimum unoccupied index starting from 1.
new_call_index(&self) -> i321452 fn new_call_index(&self) -> i32 {
1453 (1..)
1454 .find(|&index| self.call_list.iter().all(|x| x.index != index))
1455 .expect("There must be an unoccupied index")
1456 }
1457
simple_at_response(&mut self, ok: bool, addr: RawAddress)1458 fn simple_at_response(&mut self, ok: bool, addr: RawAddress) {
1459 match self.hfp.as_mut() {
1460 Some(hfp) => {
1461 let status = hfp.simple_at_response(ok, addr.clone());
1462 if status != BtStatus::Success {
1463 warn!("[{}]: AT response failed, status={:?}", DisplayAddress(&addr), status);
1464 }
1465 }
1466 None => warn!("Uninitialized HFP to send AT response"),
1467 }
1468 }
1469
answer_call_impl(&mut self) -> bool1470 fn answer_call_impl(&mut self) -> bool {
1471 if !self.phone_ops_enabled || self.phone_state.state == CallState::Idle {
1472 return false;
1473 }
1474 // There must be exactly one incoming/dialing call in the list.
1475 for c in self.call_list.iter_mut() {
1476 match c.state {
1477 CallState::Incoming | CallState::Dialing | CallState::Alerting => {
1478 c.state = CallState::Active;
1479 break;
1480 }
1481 _ => {}
1482 }
1483 }
1484 self.phone_state.state = CallState::Idle;
1485 self.phone_state.num_active += 1;
1486 true
1487 }
1488
hangup_call_impl(&mut self) -> bool1489 fn hangup_call_impl(&mut self) -> bool {
1490 if !self.phone_ops_enabled {
1491 return false;
1492 }
1493 match self.phone_state.state {
1494 CallState::Idle if self.phone_state.num_active > 0 => {
1495 self.phone_state.num_active -= 1;
1496 }
1497 CallState::Incoming | CallState::Dialing | CallState::Alerting => {
1498 self.phone_state.state = CallState::Idle;
1499 }
1500 _ => {
1501 return false;
1502 }
1503 }
1504 // At this point, there must be exactly one incoming/dialing/alerting/active call to be
1505 // removed.
1506 self.call_list.retain(|x| match x.state {
1507 CallState::Active | CallState::Incoming | CallState::Dialing | CallState::Alerting => {
1508 false
1509 }
1510 _ => true,
1511 });
1512 true
1513 }
1514
dialing_call_impl(&mut self, number: String) -> bool1515 fn dialing_call_impl(&mut self, number: String) -> bool {
1516 if !self.phone_ops_enabled
1517 || self.phone_state.state != CallState::Idle
1518 || self.phone_state.num_active > 0
1519 {
1520 return false;
1521 }
1522 self.call_list.push(CallInfo {
1523 index: self.new_call_index(),
1524 dir_incoming: false,
1525 state: CallState::Dialing,
1526 number: number.clone(),
1527 });
1528 self.phone_state.state = CallState::Dialing;
1529 true
1530 }
1531
dialing_to_alerting(&mut self) -> bool1532 fn dialing_to_alerting(&mut self) -> bool {
1533 if !self.phone_ops_enabled || self.phone_state.state != CallState::Dialing {
1534 return false;
1535 }
1536 for c in self.call_list.iter_mut() {
1537 if c.state == CallState::Dialing {
1538 c.state = CallState::Alerting;
1539 break;
1540 }
1541 }
1542 self.phone_state.state = CallState::Alerting;
1543 true
1544 }
1545
release_held_impl(&mut self) -> bool1546 fn release_held_impl(&mut self) -> bool {
1547 if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle {
1548 return false;
1549 }
1550 self.call_list.retain(|x| x.state != CallState::Held);
1551 self.phone_state.num_held = 0;
1552 true
1553 }
1554
release_active_accept_held_impl(&mut self) -> bool1555 fn release_active_accept_held_impl(&mut self) -> bool {
1556 if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle {
1557 return false;
1558 }
1559 self.call_list.retain(|x| x.state != CallState::Active);
1560 self.phone_state.num_active = 0;
1561 // Activate the first held call
1562 for c in self.call_list.iter_mut() {
1563 if c.state == CallState::Held {
1564 c.state = CallState::Active;
1565 self.phone_state.num_held -= 1;
1566 self.phone_state.num_active += 1;
1567 break;
1568 }
1569 }
1570 true
1571 }
1572
hold_active_accept_held_impl(&mut self) -> bool1573 fn hold_active_accept_held_impl(&mut self) -> bool {
1574 if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle {
1575 return false;
1576 }
1577
1578 self.phone_state.num_held += self.phone_state.num_active;
1579 self.phone_state.num_active = 0;
1580
1581 for c in self.call_list.iter_mut() {
1582 match c.state {
1583 // Activate at most one held call
1584 CallState::Held if self.phone_state.num_active == 0 => {
1585 c.state = CallState::Active;
1586 self.phone_state.num_held -= 1;
1587 self.phone_state.num_active = 1;
1588 }
1589 CallState::Active => {
1590 c.state = CallState::Held;
1591 }
1592 _ => {}
1593 }
1594 }
1595 true
1596 }
1597
1598 // Per MPS v1.0 (Multi-Profile Specification), disconnecting or failing to connect
1599 // a profile should not affect the others.
1600 // Allow partial profiles connection during qualification (phone operations are enabled).
is_complete_profiles_required(&self) -> bool1601 fn is_complete_profiles_required(&self) -> bool {
1602 !self.phone_ops_enabled
1603 }
1604
1605 // Force the media enters the FullyConnected state and then triggers a retry.
1606 // This function is only used for qualification as a replacement of normal retry.
1607 // Usually PTS initiates the connection of the necessary profiles, and Floss should notify
1608 // CRAS of the new audio device regardless of the unconnected profiles.
1609 // Still retry in the end because some test cases require that.
force_enter_connected(&mut self, address: String)1610 fn force_enter_connected(&mut self, address: String) {
1611 let addr = match RawAddress::from_string(address.clone()) {
1612 None => {
1613 warn!("Invalid device address for force_enter_connected");
1614 return;
1615 }
1616 Some(addr) => addr,
1617 };
1618 self.device_states
1619 .lock()
1620 .unwrap()
1621 .insert(addr.clone(), DeviceConnectionStates::FullyConnected);
1622 self.notify_media_capability_updated(addr);
1623 self.connect(address);
1624 }
add_player(&mut self, name: String, browsing_supported: bool)1625 pub fn add_player(&mut self, name: String, browsing_supported: bool) {
1626 self.avrcp.as_mut().unwrap().add_player(&name, browsing_supported);
1627 }
1628 }
1629
get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher1630 fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher {
1631 A2dpCallbacksDispatcher {
1632 dispatch: Box::new(move |cb| {
1633 let txl = tx.clone();
1634 topstack::get_runtime().spawn(async move {
1635 let _ = txl.send(Message::A2dp(cb)).await;
1636 });
1637 }),
1638 }
1639 }
1640
get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher1641 fn get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher {
1642 AvrcpCallbacksDispatcher {
1643 dispatch: Box::new(move |cb| {
1644 let txl = tx.clone();
1645 topstack::get_runtime().spawn(async move {
1646 let _ = txl.send(Message::Avrcp(cb)).await;
1647 });
1648 }),
1649 }
1650 }
1651
get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher1652 fn get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher {
1653 HfpCallbacksDispatcher {
1654 dispatch: Box::new(move |cb| {
1655 let txl = tx.clone();
1656 topstack::get_runtime().spawn(async move {
1657 let _ = txl.send(Message::Hfp(cb)).await;
1658 });
1659 }),
1660 }
1661 }
1662
1663 impl IBluetoothMedia for BluetoothMedia {
register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool1664 fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool {
1665 let _id = self.callbacks.lock().unwrap().add_callback(callback);
1666 true
1667 }
1668
initialize(&mut self) -> bool1669 fn initialize(&mut self) -> bool {
1670 if self.initialized {
1671 return false;
1672 }
1673 self.initialized = true;
1674
1675 // A2DP
1676 let a2dp_dispatcher = get_a2dp_dispatcher(self.tx.clone());
1677 self.a2dp = Some(A2dp::new(&self.intf.lock().unwrap()));
1678 self.a2dp.as_mut().unwrap().initialize(a2dp_dispatcher);
1679
1680 // AVRCP
1681 let avrcp_dispatcher = get_avrcp_dispatcher(self.tx.clone());
1682 self.avrcp = Some(Avrcp::new(&self.intf.lock().unwrap()));
1683 self.avrcp.as_mut().unwrap().initialize(avrcp_dispatcher);
1684
1685 // HFP
1686 let hfp_dispatcher = get_hfp_dispatcher(self.tx.clone());
1687 self.hfp = Some(Hfp::new(&self.intf.lock().unwrap()));
1688 self.hfp.as_mut().unwrap().initialize(hfp_dispatcher);
1689
1690 for profile in self.delay_enable_profiles.clone() {
1691 self.enable_profile(&profile);
1692 }
1693 true
1694 }
1695
connect(&mut self, address: String)1696 fn connect(&mut self, address: String) {
1697 let addr = match RawAddress::from_string(address.clone()) {
1698 None => {
1699 warn!("Invalid device address for connecting");
1700 return;
1701 }
1702 Some(addr) => addr,
1703 };
1704
1705 let available_profiles = self.adapter_get_audio_profiles(addr);
1706
1707 info!(
1708 "[{}]: Connecting to device, available profiles: {:?}.",
1709 DisplayAddress(&addr),
1710 available_profiles
1711 );
1712
1713 let connected_profiles = self.connected_profiles.entry(addr).or_insert_with(HashSet::new);
1714
1715 // Sort here so the order of connection is always consistent
1716 let missing_profiles =
1717 available_profiles.difference(&connected_profiles).sorted().collect::<Vec<_>>();
1718
1719 // Connect the profiles one-by-one so it won't stuck at the lower layer.
1720 // Therefore, just connect to one profile for now.
1721 // connect() will be called again after the first profile is successfully connected.
1722 let mut is_connect = false;
1723 for profile in missing_profiles {
1724 match profile {
1725 uuid::Profile::A2dpSink => {
1726 metrics::profile_connection_state_changed(
1727 addr,
1728 Profile::A2dpSink as u32,
1729 BtStatus::Success,
1730 BtavConnectionState::Connecting as u32,
1731 );
1732 match self.a2dp.as_mut() {
1733 Some(a2dp) => {
1734 let status: BtStatus = a2dp.connect(addr);
1735 if BtStatus::Success != status {
1736 metrics::profile_connection_state_changed(
1737 addr,
1738 Profile::A2dpSink as u32,
1739 status,
1740 BtavConnectionState::Disconnected as u32,
1741 );
1742 } else {
1743 is_connect = true;
1744 break;
1745 }
1746 }
1747 None => {
1748 warn!("Uninitialized A2DP to connect {}", DisplayAddress(&addr));
1749 metrics::profile_connection_state_changed(
1750 addr,
1751 Profile::A2dpSink as u32,
1752 BtStatus::NotReady,
1753 BtavConnectionState::Disconnected as u32,
1754 );
1755 }
1756 };
1757 }
1758 uuid::Profile::Hfp => {
1759 metrics::profile_connection_state_changed(
1760 addr,
1761 Profile::Hfp as u32,
1762 BtStatus::Success,
1763 BtavConnectionState::Connecting as u32,
1764 );
1765 match self.hfp.as_mut() {
1766 Some(hfp) => {
1767 let status: BtStatus = hfp.connect(addr);
1768 if BtStatus::Success != status {
1769 metrics::profile_connection_state_changed(
1770 addr,
1771 Profile::Hfp as u32,
1772 status,
1773 BthfConnectionState::Disconnected as u32,
1774 );
1775 } else {
1776 is_connect = true;
1777 break;
1778 }
1779 }
1780 None => {
1781 warn!("Uninitialized HFP to connect {}", DisplayAddress(&addr));
1782 metrics::profile_connection_state_changed(
1783 addr,
1784 Profile::Hfp as u32,
1785 BtStatus::NotReady,
1786 BthfConnectionState::Disconnected as u32,
1787 );
1788 }
1789 };
1790 }
1791 uuid::Profile::AvrcpController => {
1792 // Fluoride will resolve AVRCP as a part of A2DP connection request.
1793 // Explicitly connect to it only when it is considered missing, and don't
1794 // bother about it when A2DP is not connected.
1795 if !connected_profiles.contains(&Profile::A2dpSink) {
1796 continue;
1797 }
1798
1799 metrics::profile_connection_state_changed(
1800 addr,
1801 Profile::AvrcpController as u32,
1802 BtStatus::Success,
1803 BtavConnectionState::Connecting as u32,
1804 );
1805 match self.avrcp.as_mut() {
1806 Some(avrcp) => {
1807 self.avrcp_direction = BtConnectionDirection::Outgoing;
1808 let status: BtStatus = avrcp.connect(addr);
1809 if BtStatus::Success != status {
1810 // Reset direction to unknown.
1811 self.avrcp_direction = BtConnectionDirection::Unknown;
1812 metrics::profile_connection_state_changed(
1813 addr,
1814 Profile::AvrcpController as u32,
1815 status,
1816 BtavConnectionState::Disconnected as u32,
1817 );
1818 } else {
1819 is_connect = true;
1820 break;
1821 }
1822 }
1823
1824 None => {
1825 warn!("Uninitialized AVRCP to connect {}", DisplayAddress(&addr));
1826 metrics::profile_connection_state_changed(
1827 addr,
1828 Profile::AvrcpController as u32,
1829 BtStatus::NotReady,
1830 BtavConnectionState::Disconnected as u32,
1831 );
1832 }
1833 };
1834 }
1835 _ => warn!("Unknown profile: {:?}", profile),
1836 }
1837 }
1838
1839 if is_connect {
1840 let mut tasks = self.fallback_tasks.lock().unwrap();
1841 let mut states = self.device_states.lock().unwrap();
1842 if !tasks.contains_key(&addr) {
1843 states.insert(addr, DeviceConnectionStates::Initiating);
1844
1845 let fallback_tasks = self.fallback_tasks.clone();
1846 let device_states = self.device_states.clone();
1847 let now_ts = Instant::now();
1848 let task = topstack::get_runtime().spawn(async move {
1849 sleep(Duration::from_secs(CONNECT_AS_INITIATOR_TIMEOUT_SEC)).await;
1850
1851 // If here the task is not yet aborted, probably connection is failed,
1852 // therefore here we release the states. Even if later the connection is
1853 // actually successful, we will just treat this as if the connection is
1854 // initiated by the peer and will reconnect the missing profiles after
1855 // some time, so it's safe.
1856 {
1857 device_states.lock().unwrap().remove(&addr);
1858 fallback_tasks.lock().unwrap().remove(&addr);
1859 }
1860 });
1861 tasks.insert(addr, Some((task, now_ts)));
1862 }
1863 }
1864 }
1865
cleanup(&mut self) -> bool1866 fn cleanup(&mut self) -> bool {
1867 true
1868 }
1869
1870 // TODO(b/278963515): Currently this is designed to be called from both the
1871 // UI and via disconnection callbacks. Remove this workaround once the
1872 // proper fix has landed.
disconnect(&mut self, address: String)1873 fn disconnect(&mut self, address: String) {
1874 let addr = match RawAddress::from_string(address.clone()) {
1875 None => {
1876 warn!("Invalid device address for disconnecting");
1877 return;
1878 }
1879 Some(addr) => addr,
1880 };
1881
1882 let connected_profiles = match self.connected_profiles.get(&addr) {
1883 Some(profiles) => profiles,
1884 None => {
1885 warn!(
1886 "[{}]: Ignoring disconnection request since there is no connected profile.",
1887 DisplayAddress(&addr)
1888 );
1889 return;
1890 }
1891 };
1892
1893 for profile in connected_profiles {
1894 match profile {
1895 uuid::Profile::A2dpSink => {
1896 // Some headsets (b/278963515) will try reconnecting to A2DP
1897 // when HFP is running but (requested to be) disconnected.
1898 if connected_profiles.contains(&Profile::Hfp) {
1899 continue;
1900 }
1901 metrics::profile_connection_state_changed(
1902 addr,
1903 Profile::A2dpSink as u32,
1904 BtStatus::Success,
1905 BtavConnectionState::Disconnecting as u32,
1906 );
1907 match self.a2dp.as_mut() {
1908 Some(a2dp) => {
1909 let status: BtStatus = a2dp.disconnect(addr);
1910 if BtStatus::Success != status {
1911 metrics::profile_connection_state_changed(
1912 addr,
1913 Profile::A2dpSource as u32,
1914 status,
1915 BtavConnectionState::Disconnected as u32,
1916 );
1917 }
1918 }
1919 None => {
1920 warn!("Uninitialized A2DP to disconnect {}", DisplayAddress(&addr));
1921 metrics::profile_connection_state_changed(
1922 addr,
1923 Profile::A2dpSource as u32,
1924 BtStatus::NotReady,
1925 BtavConnectionState::Disconnected as u32,
1926 );
1927 }
1928 };
1929 }
1930 uuid::Profile::Hfp => {
1931 metrics::profile_connection_state_changed(
1932 addr,
1933 Profile::Hfp as u32,
1934 BtStatus::Success,
1935 BthfConnectionState::Disconnecting as u32,
1936 );
1937 match self.hfp.as_mut() {
1938 Some(hfp) => {
1939 let status: BtStatus = hfp.disconnect(addr);
1940 if BtStatus::Success != status {
1941 metrics::profile_connection_state_changed(
1942 addr,
1943 Profile::Hfp as u32,
1944 status,
1945 BthfConnectionState::Disconnected as u32,
1946 );
1947 }
1948 }
1949 None => {
1950 warn!("Uninitialized HFP to disconnect {}", DisplayAddress(&addr));
1951 metrics::profile_connection_state_changed(
1952 addr,
1953 Profile::Hfp as u32,
1954 BtStatus::NotReady,
1955 BthfConnectionState::Disconnected as u32,
1956 );
1957 }
1958 };
1959 }
1960 uuid::Profile::AvrcpController => {
1961 if connected_profiles.contains(&Profile::A2dpSink) {
1962 continue;
1963 }
1964 metrics::profile_connection_state_changed(
1965 addr,
1966 Profile::AvrcpController as u32,
1967 BtStatus::Success,
1968 BtavConnectionState::Disconnecting as u32,
1969 );
1970 match self.avrcp.as_mut() {
1971 Some(avrcp) => {
1972 self.avrcp_direction = BtConnectionDirection::Outgoing;
1973 let status: BtStatus = avrcp.disconnect(addr);
1974 if BtStatus::Success != status {
1975 // Reset direction to unknown.
1976 self.avrcp_direction = BtConnectionDirection::Unknown;
1977 metrics::profile_connection_state_changed(
1978 addr,
1979 Profile::AvrcpController as u32,
1980 status,
1981 BtavConnectionState::Disconnected as u32,
1982 );
1983 }
1984 }
1985
1986 None => {
1987 warn!("Uninitialized AVRCP to disconnect {}", DisplayAddress(&addr));
1988 metrics::profile_connection_state_changed(
1989 addr,
1990 Profile::AvrcpController as u32,
1991 BtStatus::NotReady,
1992 BtavConnectionState::Disconnected as u32,
1993 );
1994 }
1995 };
1996 }
1997 _ => warn!("Unknown profile: {:?}", profile),
1998 }
1999 }
2000 }
2001
set_active_device(&mut self, address: String)2002 fn set_active_device(&mut self, address: String) {
2003 let addr = match RawAddress::from_string(address.clone()) {
2004 None => {
2005 warn!("Invalid device address for set_active_device");
2006 return;
2007 }
2008 Some(addr) => addr,
2009 };
2010
2011 match self.a2dp_states.get(&addr) {
2012 Some(BtavConnectionState::Connected) => {
2013 if let Some(a2dp) = self.a2dp.as_mut() {
2014 a2dp.set_active_device(addr);
2015 self.uinput.set_active_device(addr.to_string());
2016 } else {
2017 warn!("Uninitialized A2DP to set active device");
2018 }
2019 }
2020 _ => warn!("[{}] Not connected or disconnected A2DP address", address),
2021 };
2022 }
2023
reset_active_device(&mut self)2024 fn reset_active_device(&mut self) {
2025 // During MPS tests, there might be some A2DP stream manipulation unexpected to CRAS.
2026 // CRAS would then attempt to reset the active device. Ignore it during test.
2027 if !self.is_complete_profiles_required() {
2028 return;
2029 }
2030
2031 if let Some(a2dp) = self.a2dp.as_mut() {
2032 a2dp.set_active_device(RawAddress::empty());
2033 } else {
2034 warn!("Uninitialized A2DP to set active device");
2035 }
2036 self.uinput.set_active_device(RawAddress::empty().to_string());
2037 }
2038
set_hfp_active_device(&mut self, address: String)2039 fn set_hfp_active_device(&mut self, address: String) {
2040 let addr = match RawAddress::from_string(address.clone()) {
2041 None => {
2042 warn!("Invalid device address for set_hfp_active_device");
2043 return;
2044 }
2045 Some(addr) => addr,
2046 };
2047
2048 match self.hfp_states.get(&addr) {
2049 Some(BthfConnectionState::SlcConnected) => {
2050 if let Some(hfp) = self.hfp.as_mut() {
2051 hfp.set_active_device(addr);
2052 } else {
2053 warn!("Uninitialized HFP to set active device");
2054 }
2055 }
2056 _ => warn!("[{}] Not connected or disconnected HFP address", address),
2057 }
2058 }
2059
set_audio_config( &mut self, sample_rate: i32, bits_per_sample: i32, channel_mode: i32, ) -> bool2060 fn set_audio_config(
2061 &mut self,
2062 sample_rate: i32,
2063 bits_per_sample: i32,
2064 channel_mode: i32,
2065 ) -> bool {
2066 if !A2dpCodecSampleRate::validate_bits(sample_rate)
2067 || !A2dpCodecBitsPerSample::validate_bits(bits_per_sample)
2068 || !A2dpCodecChannelMode::validate_bits(channel_mode)
2069 {
2070 return false;
2071 }
2072
2073 match self.a2dp.as_mut() {
2074 Some(a2dp) => {
2075 a2dp.set_audio_config(sample_rate, bits_per_sample, channel_mode);
2076 true
2077 }
2078 None => {
2079 warn!("Uninitialized A2DP to set audio config");
2080 false
2081 }
2082 }
2083 }
2084
set_volume(&mut self, volume: u8)2085 fn set_volume(&mut self, volume: u8) {
2086 // Guard the range 0-127 by the try_from cast from u8 to i8.
2087 let vol = match i8::try_from(volume) {
2088 Ok(val) => val,
2089 _ => {
2090 warn!("Ignore invalid volume {}", volume);
2091 return;
2092 }
2093 };
2094
2095 match self.avrcp.as_mut() {
2096 Some(avrcp) => avrcp.set_volume(vol),
2097 None => warn!("Uninitialized AVRCP to set volume"),
2098 };
2099 }
2100
set_hfp_volume(&mut self, volume: u8, address: String)2101 fn set_hfp_volume(&mut self, volume: u8, address: String) {
2102 let addr = match RawAddress::from_string(address.clone()) {
2103 None => {
2104 warn!("Invalid device address for set_hfp_volume");
2105 return;
2106 }
2107 Some(addr) => addr,
2108 };
2109
2110 let vol = match i8::try_from(volume) {
2111 Ok(val) if val <= 15 => val,
2112 _ => {
2113 warn!("[{}]: Ignore invalid volume {}", DisplayAddress(&addr), volume);
2114 return;
2115 }
2116 };
2117
2118 if self.hfp_states.get(&addr).is_none() {
2119 warn!(
2120 "[{}]: Ignore volume event for unconnected or disconnected HFP device",
2121 DisplayAddress(&addr)
2122 );
2123 return;
2124 }
2125
2126 match self.hfp.as_mut() {
2127 Some(hfp) => {
2128 hfp.set_volume(vol, addr);
2129 }
2130 None => warn!("Uninitialized HFP to set volume"),
2131 };
2132 }
2133
start_audio_request(&mut self) -> bool2134 fn start_audio_request(&mut self) -> bool {
2135 self.start_audio_request_impl()
2136 }
2137
stop_audio_request(&mut self)2138 fn stop_audio_request(&mut self) {
2139 if !self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
2140 info!("No active stream on A2DP device, ignoring request to stop audio.");
2141 return;
2142 }
2143
2144 debug!("Stop audio request");
2145
2146 match self.a2dp.as_mut() {
2147 Some(a2dp) => a2dp.stop_audio_request(),
2148 None => warn!("Uninitialized A2DP to stop audio request"),
2149 };
2150 }
2151
start_sco_call(&mut self, address: String, sco_offload: bool, force_cvsd: bool) -> bool2152 fn start_sco_call(&mut self, address: String, sco_offload: bool, force_cvsd: bool) -> bool {
2153 self.start_sco_call_impl(address, sco_offload, force_cvsd)
2154 }
2155
stop_sco_call(&mut self, address: String)2156 fn stop_sco_call(&mut self, address: String) {
2157 self.stop_sco_call_impl(address)
2158 }
2159
get_a2dp_audio_started(&mut self, address: String) -> bool2160 fn get_a2dp_audio_started(&mut self, address: String) -> bool {
2161 let addr = match RawAddress::from_string(address.clone()) {
2162 None => {
2163 warn!("Invalid device address for get_a2dp_audio_started");
2164 return false;
2165 }
2166 Some(addr) => addr,
2167 };
2168
2169 match self.a2dp_audio_state.get(&addr) {
2170 Some(BtavAudioState::Started) => true,
2171 _ => false,
2172 }
2173 }
2174
get_hfp_audio_final_codecs(&mut self, address: String) -> u82175 fn get_hfp_audio_final_codecs(&mut self, address: String) -> u8 {
2176 let addr = match RawAddress::from_string(address.clone()) {
2177 None => {
2178 warn!("Invalid device address for get_hfp_audio_final_codecs");
2179 return 0;
2180 }
2181 Some(addr) => addr,
2182 };
2183
2184 match self.hfp_audio_state.get(&addr) {
2185 Some(BthfAudioState::Connected) => match self.hfp_cap.get(&addr) {
2186 Some(caps) if (*caps & HfpCodecCapability::LC3) == HfpCodecCapability::LC3 => 4,
2187 Some(caps) if (*caps & HfpCodecCapability::MSBC) == HfpCodecCapability::MSBC => 2,
2188 Some(caps) if (*caps & HfpCodecCapability::CVSD) == HfpCodecCapability::CVSD => 1,
2189 _ => {
2190 warn!("hfp_cap not found, fallback to CVSD.");
2191 1
2192 }
2193 },
2194 _ => 0,
2195 }
2196 }
2197
get_presentation_position(&mut self) -> PresentationPosition2198 fn get_presentation_position(&mut self) -> PresentationPosition {
2199 let position = match self.a2dp.as_mut() {
2200 Some(a2dp) => a2dp.get_presentation_position(),
2201 None => {
2202 warn!("Uninitialized A2DP to get presentation position");
2203 Default::default()
2204 }
2205 };
2206 PresentationPosition {
2207 remote_delay_report_ns: position.remote_delay_report_ns,
2208 total_bytes_read: position.total_bytes_read,
2209 data_position_sec: position.data_position_sec,
2210 data_position_nsec: position.data_position_nsec,
2211 }
2212 }
2213
set_player_playback_status(&mut self, status: String)2214 fn set_player_playback_status(&mut self, status: String) {
2215 debug!("AVRCP received player playback status: {}", status);
2216 match self.avrcp.as_mut() {
2217 Some(avrcp) => avrcp.set_playback_status(&status),
2218 None => warn!("Uninitialized AVRCP to set player playback status"),
2219 };
2220 }
set_player_position(&mut self, position_us: i64)2221 fn set_player_position(&mut self, position_us: i64) {
2222 debug!("AVRCP received player position: {}", position_us);
2223 match self.avrcp.as_mut() {
2224 Some(avrcp) => avrcp.set_position(position_us),
2225 None => warn!("Uninitialized AVRCP to set player position"),
2226 };
2227 }
set_player_metadata(&mut self, metadata: PlayerMetadata)2228 fn set_player_metadata(&mut self, metadata: PlayerMetadata) {
2229 debug!("AVRCP received player metadata: {:?}", metadata);
2230 match self.avrcp.as_mut() {
2231 Some(avrcp) => avrcp.set_metadata(&metadata),
2232 None => warn!("Uninitialized AVRCP to set player playback status"),
2233 };
2234 }
2235 }
2236
2237 impl IBluetoothTelephony for BluetoothMedia {
set_network_available(&mut self, network_available: bool)2238 fn set_network_available(&mut self, network_available: bool) {
2239 if self.telephony_device_status.network_available == network_available {
2240 return;
2241 }
2242 self.telephony_device_status.network_available = network_available;
2243 self.device_status_notification();
2244 }
2245
set_roaming(&mut self, roaming: bool)2246 fn set_roaming(&mut self, roaming: bool) {
2247 if self.telephony_device_status.roaming == roaming {
2248 return;
2249 }
2250 self.telephony_device_status.roaming = roaming;
2251 self.device_status_notification();
2252 }
2253
set_signal_strength(&mut self, signal_strength: i32) -> bool2254 fn set_signal_strength(&mut self, signal_strength: i32) -> bool {
2255 if signal_strength < 0 || signal_strength > 5 {
2256 warn!("Invalid signal strength, got {}, want 0 to 5", signal_strength);
2257 return false;
2258 }
2259 if self.telephony_device_status.signal_strength == signal_strength {
2260 return true;
2261 }
2262
2263 self.telephony_device_status.signal_strength = signal_strength;
2264 self.device_status_notification();
2265
2266 true
2267 }
2268
set_battery_level(&mut self, battery_level: i32) -> bool2269 fn set_battery_level(&mut self, battery_level: i32) -> bool {
2270 if battery_level < 0 || battery_level > 5 {
2271 warn!("Invalid battery level, got {}, want 0 to 5", battery_level);
2272 return false;
2273 }
2274 if self.telephony_device_status.battery_level == battery_level {
2275 return true;
2276 }
2277
2278 self.telephony_device_status.battery_level = battery_level;
2279 self.device_status_notification();
2280
2281 true
2282 }
2283
set_phone_ops_enabled(&mut self, enable: bool)2284 fn set_phone_ops_enabled(&mut self, enable: bool) {
2285 if self.phone_ops_enabled == enable {
2286 return;
2287 }
2288
2289 self.call_list = vec![];
2290 self.phone_state.num_active = 0;
2291 self.phone_state.num_held = 0;
2292 self.phone_state.state = CallState::Idle;
2293 self.memory_dialing_number = None;
2294 self.last_dialing_number = None;
2295 self.a2dp_has_interrupted_stream = false;
2296
2297 if !enable {
2298 if self.hfp_states.values().any(|x| x == &BthfConnectionState::SlcConnected) {
2299 self.call_list.push(CallInfo {
2300 index: 1,
2301 dir_incoming: false,
2302 state: CallState::Active,
2303 number: "".into(),
2304 });
2305 self.phone_state.num_active = 1;
2306 }
2307 }
2308
2309 self.phone_ops_enabled = enable;
2310 self.phone_state_change("".into());
2311 }
2312
incoming_call(&mut self, number: String) -> bool2313 fn incoming_call(&mut self, number: String) -> bool {
2314 if !self.phone_ops_enabled
2315 || self.phone_state.state != CallState::Idle
2316 || self.phone_state.num_active > 0
2317 {
2318 return false;
2319 }
2320 self.call_list.push(CallInfo {
2321 index: self.new_call_index(),
2322 dir_incoming: true,
2323 state: CallState::Incoming,
2324 number: number.clone(),
2325 });
2326 self.phone_state.state = CallState::Incoming;
2327 self.phone_state_change(number);
2328 self.try_a2dp_suspend();
2329 true
2330 }
2331
dialing_call(&mut self, number: String) -> bool2332 fn dialing_call(&mut self, number: String) -> bool {
2333 if !self.dialing_call_impl(number) {
2334 return false;
2335 }
2336 self.phone_state_change("".into());
2337 self.try_a2dp_suspend();
2338 // Change to alerting state and inform libbluetooth.
2339 self.dialing_to_alerting();
2340 self.phone_state_change("".into());
2341 true
2342 }
2343
answer_call(&mut self) -> bool2344 fn answer_call(&mut self) -> bool {
2345 if !self.answer_call_impl() {
2346 return false;
2347 }
2348 self.phone_state_change("".into());
2349
2350 // Find a connected HFP and try to establish an SCO.
2351 if let Some(addr) = self.hfp_states.iter().find_map(|(addr, state)| {
2352 if *state == BthfConnectionState::SlcConnected {
2353 Some(addr.clone())
2354 } else {
2355 None
2356 }
2357 }) {
2358 info!("Start SCO call due to call answered");
2359 self.start_sco_call_impl(addr.to_string(), false, false);
2360 }
2361
2362 true
2363 }
2364
hangup_call(&mut self) -> bool2365 fn hangup_call(&mut self) -> bool {
2366 if !self.hangup_call_impl() {
2367 return false;
2368 }
2369 self.phone_state_change("".into());
2370 // Try resume the A2DP stream (per MPS v1.0) on rejecting an incoming call or an
2371 // outgoing call is rejected.
2372 // It may fail if a SCO connection is still active (terminate call case), in that
2373 // case we will retry on SCO disconnected.
2374 self.try_a2dp_resume();
2375 true
2376 }
2377
set_memory_call(&mut self, number: Option<String>) -> bool2378 fn set_memory_call(&mut self, number: Option<String>) -> bool {
2379 if !self.phone_ops_enabled {
2380 return false;
2381 }
2382 self.memory_dialing_number = number;
2383 true
2384 }
2385
set_last_call(&mut self, number: Option<String>) -> bool2386 fn set_last_call(&mut self, number: Option<String>) -> bool {
2387 if !self.phone_ops_enabled {
2388 return false;
2389 }
2390 self.last_dialing_number = number;
2391 true
2392 }
2393
release_held(&mut self) -> bool2394 fn release_held(&mut self) -> bool {
2395 if !self.release_held_impl() {
2396 return false;
2397 }
2398 self.phone_state_change("".into());
2399 true
2400 }
2401
release_active_accept_held(&mut self) -> bool2402 fn release_active_accept_held(&mut self) -> bool {
2403 if !self.release_active_accept_held_impl() {
2404 return false;
2405 }
2406 self.phone_state_change("".into());
2407 true
2408 }
2409
hold_active_accept_held(&mut self) -> bool2410 fn hold_active_accept_held(&mut self) -> bool {
2411 if !self.hold_active_accept_held_impl() {
2412 return false;
2413 }
2414 self.phone_state_change("".into());
2415 true
2416 }
2417
audio_connect(&mut self, address: String) -> bool2418 fn audio_connect(&mut self, address: String) -> bool {
2419 self.start_sco_call_impl(address, false, false)
2420 }
2421
audio_disconnect(&mut self, address: String)2422 fn audio_disconnect(&mut self, address: String) {
2423 self.stop_sco_call_impl(address)
2424 }
2425 }
2426
2427 struct BatteryProviderCallback {}
2428
2429 impl BatteryProviderCallback {
new() -> Self2430 fn new() -> Self {
2431 Self {}
2432 }
2433 }
2434
2435 impl IBatteryProviderCallback for BatteryProviderCallback {
2436 // We do not support refreshing HFP battery information.
refresh_battery_info(&mut self)2437 fn refresh_battery_info(&mut self) {}
2438 }
2439
2440 impl RPCProxy for BatteryProviderCallback {
get_object_id(&self) -> String2441 fn get_object_id(&self) -> String {
2442 "HFP BatteryProvider Callback".to_string()
2443 }
2444 }
2445