1 //! Anything related to audio and media API.
2
3 use bt_topshim::btif::{
4 BluetoothInterface, BtBondState, BtConnectionDirection, BtStatus, BtTransport, DisplayAddress,
5 RawAddress, ToggleableProfile,
6 };
7 use bt_topshim::profiles::a2dp::{
8 A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, A2dpCodecBitsPerSample, A2dpCodecChannelMode,
9 A2dpCodecConfig, A2dpCodecIndex, A2dpCodecPriority, A2dpCodecSampleRate, BtavAudioState,
10 BtavConnectionState, PresentationPosition,
11 };
12 use bt_topshim::profiles::avrcp::{
13 Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher, PlayerMetadata,
14 };
15 use bt_topshim::profiles::csis::{
16 BtCsisConnectionState, CsisClient, CsisClientCallbacks, CsisClientCallbacksDispatcher,
17 };
18 use bt_topshim::profiles::hfp::interop_insert_call_when_sco_start;
19 use bt_topshim::profiles::hfp::{
20 BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallState, EscoCodingFormat,
21 Hfp, HfpCallbacks, HfpCallbacksDispatcher, HfpCodecBitId, HfpCodecFormat, HfpCodecId,
22 PhoneState, TelephonyDeviceStatus,
23 };
24 use bt_topshim::profiles::le_audio::{
25 BtLeAudioConnectionState, BtLeAudioContentType, BtLeAudioDirection, BtLeAudioGroupNodeStatus,
26 BtLeAudioGroupStatus, BtLeAudioGroupStreamStatus, BtLeAudioSource,
27 BtLeAudioUnicastMonitorModeStatus, BtLeAudioUsage, BtLePcmConfig, BtLeStreamStartedStatus,
28 LeAudioClient, LeAudioClientCallbacks, LeAudioClientCallbacksDispatcher, SinkMetadata,
29 SourceMetadata,
30 };
31 use bt_topshim::profiles::vc::{
32 BtVcConnectionState, VolumeControl, VolumeControlCallbacks, VolumeControlCallbacksDispatcher,
33 };
34 use bt_topshim::profiles::ProfileConnectionState;
35 use bt_topshim::{metrics, topstack};
36 use bt_utils::at_command_parser::{calculate_battery_percent, parse_at_command_data};
37 use bt_utils::features;
38 use bt_utils::uhid_hfp::{
39 OutputEvent, UHidHfp, BLUETOOTH_TELEPHONY_UHID_REPORT_ID, UHID_INPUT_DROP,
40 UHID_INPUT_HOOK_SWITCH, UHID_INPUT_NONE, UHID_INPUT_PHONE_MUTE, UHID_OUTPUT_MUTE,
41 UHID_OUTPUT_NONE, UHID_OUTPUT_OFF_HOOK, UHID_OUTPUT_RING,
42 };
43 use bt_utils::uinput::UInput;
44
45 use itertools::Itertools;
46 use log::{debug, info, warn};
47 use std::collections::{HashMap, HashSet};
48 use std::convert::{TryFrom, TryInto};
49 use std::sync::Arc;
50 use std::sync::Mutex;
51
52 use tokio::sync::mpsc::Sender;
53 use tokio::task::JoinHandle;
54 use tokio::time::{sleep, Duration, Instant};
55
56 use crate::battery_manager::{Battery, BatterySet};
57 use crate::battery_provider_manager::{
58 BatteryProviderManager, IBatteryProviderCallback, IBatteryProviderManager,
59 };
60 use crate::bluetooth::{Bluetooth, BluetoothDevice, IBluetooth};
61 use crate::callbacks::Callbacks;
62 use crate::uuid;
63 use crate::uuid::{Profile, UuidHelper};
64 use crate::{Message, RPCProxy};
65
66 use num_derive::FromPrimitive;
67
68 // The timeout we have to wait for all supported profiles to connect after we
69 // receive the first profile connected event. The host shall disconnect or
70 // force connect the potentially partially connected device after this many
71 // seconds of timeout.
72 const PROFILE_DISCOVERY_TIMEOUT_SEC: u64 = 10;
73 // The timeout we have to wait for the initiator peer device to complete the
74 // initial profile connection. After this many seconds, we will begin to
75 // connect the missing profiles.
76 // 6s is set to align with Android's default. See "btservice/PhonePolicy".
77 const CONNECT_MISSING_PROFILES_TIMEOUT_SEC: u64 = 6;
78 // The duration we assume the role of the initiator, i.e. the side that starts
79 // the profile connection. If the profile is connected before this many seconds,
80 // we assume we are the initiator and can keep connecting the remaining
81 // profiles, otherwise we wait for the peer initiator.
82 // Set to 5s to align with default page timeout (BT spec vol 4 part E sec 6.6)
83 const CONNECT_AS_INITIATOR_TIMEOUT_SEC: u64 = 5;
84
85 /// The list of profiles we consider as classic audio profiles for media.
86 const MEDIA_CLASSIC_AUDIO_PROFILES: &[Profile] =
87 &[Profile::A2dpSink, Profile::Hfp, Profile::AvrcpController];
88
89 /// The list of profiles we consider as LE audio profiles for media.
90 const MEDIA_LE_AUDIO_PROFILES: &[Profile] =
91 &[Profile::LeAudio, Profile::VolumeControl, Profile::CoordinatedSet];
92
93 /// Group ID used to identify unknown/non-existent groups.
94 pub const LEA_UNKNOWN_GROUP_ID: i32 = -1;
95
96 /// Refer to |pairDeviceByCsip| in |CachedBluetoothDeviceManager.java|.
97 /// Number of attempts for CSIS to bond set members of a connected group.
98 const CSIS_BONDING_NUM_ATTEMPTS: u32 = 30;
99 /// The delay for bonding retries when pairing is busy, in milliseconds.
100 const CSIS_BONDING_RETRY_DELAY_MS: u64 = 500;
101
102 pub trait IBluetoothMedia {
103 ///
register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool104 fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool;
105
106 /// initializes media (both A2dp and AVRCP) stack
initialize(&mut self) -> bool107 fn initialize(&mut self) -> bool;
108
109 /// clean up media stack
cleanup(&mut self) -> bool110 fn cleanup(&mut self) -> bool;
111
112 /// connect to available but missing classic media profiles
connect(&mut self, address: RawAddress)113 fn connect(&mut self, address: RawAddress);
114
115 /// disconnect all profiles from the device
116 /// NOTE: do not call this function from outside unless `is_complete_profiles_required`
disconnect(&mut self, address: RawAddress)117 fn disconnect(&mut self, address: RawAddress);
118
connect_lea_group_by_member_address(&mut self, address: RawAddress)119 fn connect_lea_group_by_member_address(&mut self, address: RawAddress);
disconnect_lea_group_by_member_address(&mut self, address: RawAddress)120 fn disconnect_lea_group_by_member_address(&mut self, address: RawAddress);
121
connect_lea(&mut self, address: RawAddress)122 fn connect_lea(&mut self, address: RawAddress);
disconnect_lea(&mut self, address: RawAddress)123 fn disconnect_lea(&mut self, address: RawAddress);
connect_vc(&mut self, address: RawAddress)124 fn connect_vc(&mut self, address: RawAddress);
disconnect_vc(&mut self, address: RawAddress)125 fn disconnect_vc(&mut self, address: RawAddress);
connect_csis(&mut self, address: RawAddress)126 fn connect_csis(&mut self, address: RawAddress);
disconnect_csis(&mut self, address: RawAddress)127 fn disconnect_csis(&mut self, address: RawAddress);
128
129 // Set the device as the active A2DP device
set_active_device(&mut self, address: RawAddress)130 fn set_active_device(&mut self, address: RawAddress);
131
132 // Reset the active A2DP device
reset_active_device(&mut self)133 fn reset_active_device(&mut self);
134
135 // Set the device as the active HFP device
set_hfp_active_device(&mut self, address: RawAddress)136 fn set_hfp_active_device(&mut self, address: RawAddress);
137
set_audio_config( &mut self, address: RawAddress, codec_type: A2dpCodecIndex, sample_rate: A2dpCodecSampleRate, bits_per_sample: A2dpCodecBitsPerSample, channel_mode: A2dpCodecChannelMode, ) -> bool138 fn set_audio_config(
139 &mut self,
140 address: RawAddress,
141 codec_type: A2dpCodecIndex,
142 sample_rate: A2dpCodecSampleRate,
143 bits_per_sample: A2dpCodecBitsPerSample,
144 channel_mode: A2dpCodecChannelMode,
145 ) -> bool;
146
147 // Set the A2DP/AVRCP volume. Valid volume specified by the spec should be
148 // in the range of 0-127.
set_volume(&mut self, volume: u8)149 fn set_volume(&mut self, volume: u8);
150
151 // Set the HFP speaker volume. Valid volume specified by the HFP spec should
152 // be in the range of 0-15.
set_hfp_volume(&mut self, volume: u8, address: RawAddress)153 fn set_hfp_volume(&mut self, volume: u8, address: RawAddress);
start_audio_request(&mut self) -> bool154 fn start_audio_request(&mut self) -> bool;
stop_audio_request(&mut self)155 fn stop_audio_request(&mut self);
156
157 /// Returns true iff A2DP audio has started.
get_a2dp_audio_started(&mut self, address: RawAddress) -> bool158 fn get_a2dp_audio_started(&mut self, address: RawAddress) -> bool;
159
160 /// Returns the negotiated codec (CVSD=1, mSBC=2, LC3=4) to use if HFP audio has started.
161 /// Returns 0 if HFP audio hasn't started.
get_hfp_audio_final_codecs(&mut self, address: RawAddress) -> u8162 fn get_hfp_audio_final_codecs(&mut self, address: RawAddress) -> u8;
163
get_presentation_position(&mut self) -> PresentationPosition164 fn get_presentation_position(&mut self) -> PresentationPosition;
165
166 /// Start the SCO setup to connect audio
start_sco_call( &mut self, address: RawAddress, sco_offload: bool, disabled_codecs: HfpCodecBitId, ) -> bool167 fn start_sco_call(
168 &mut self,
169 address: RawAddress,
170 sco_offload: bool,
171 disabled_codecs: HfpCodecBitId,
172 ) -> bool;
stop_sco_call(&mut self, address: RawAddress)173 fn stop_sco_call(&mut self, address: RawAddress);
174
175 /// Set the current playback status: e.g., playing, paused, stopped, etc. The method is a copy
176 /// of the existing CRAS API, hence not following Floss API conventions.
set_player_playback_status(&mut self, status: String)177 fn set_player_playback_status(&mut self, status: String);
178 /// Set the position of the current media in microseconds. The method is a copy of the existing
179 /// CRAS API, hence not following Floss API conventions.
set_player_position(&mut self, position: i64)180 fn set_player_position(&mut self, position: i64);
181 /// Set the media metadata, including title, artist, album, and length. The method is a
182 /// copy of the existing CRAS API, hence not following Floss API conventions. PlayerMetadata is
183 /// a custom data type that requires special handlng.
set_player_metadata(&mut self, metadata: PlayerMetadata)184 fn set_player_metadata(&mut self, metadata: PlayerMetadata);
185
186 // Trigger a debug log dump.
trigger_debug_dump(&mut self)187 fn trigger_debug_dump(&mut self);
188
189 /// LE Audio Commands
group_set_active(&mut self, group_id: i32)190 fn group_set_active(&mut self, group_id: i32);
host_start_audio_request(&mut self) -> bool191 fn host_start_audio_request(&mut self) -> bool;
host_stop_audio_request(&mut self)192 fn host_stop_audio_request(&mut self);
peer_start_audio_request(&mut self) -> bool193 fn peer_start_audio_request(&mut self) -> bool;
peer_stop_audio_request(&mut self)194 fn peer_stop_audio_request(&mut self);
get_host_pcm_config(&mut self) -> BtLePcmConfig195 fn get_host_pcm_config(&mut self) -> BtLePcmConfig;
get_peer_pcm_config(&mut self) -> BtLePcmConfig196 fn get_peer_pcm_config(&mut self) -> BtLePcmConfig;
get_host_stream_started(&mut self) -> BtLeStreamStartedStatus197 fn get_host_stream_started(&mut self) -> BtLeStreamStartedStatus;
get_peer_stream_started(&mut self) -> BtLeStreamStartedStatus198 fn get_peer_stream_started(&mut self) -> BtLeStreamStartedStatus;
source_metadata_changed( &mut self, usage: BtLeAudioUsage, content_type: BtLeAudioContentType, gain: f64, ) -> bool199 fn source_metadata_changed(
200 &mut self,
201 usage: BtLeAudioUsage,
202 content_type: BtLeAudioContentType,
203 gain: f64,
204 ) -> bool;
sink_metadata_changed(&mut self, source: BtLeAudioSource, gain: f64) -> bool205 fn sink_metadata_changed(&mut self, source: BtLeAudioSource, gain: f64) -> bool;
get_unicast_monitor_mode_status( &mut self, direction: BtLeAudioDirection, ) -> BtLeAudioUnicastMonitorModeStatus206 fn get_unicast_monitor_mode_status(
207 &mut self,
208 direction: BtLeAudioDirection,
209 ) -> BtLeAudioUnicastMonitorModeStatus;
get_group_stream_status(&mut self, group_id: i32) -> BtLeAudioGroupStreamStatus210 fn get_group_stream_status(&mut self, group_id: i32) -> BtLeAudioGroupStreamStatus;
get_group_status(&mut self, group_id: i32) -> BtLeAudioGroupStatus211 fn get_group_status(&mut self, group_id: i32) -> BtLeAudioGroupStatus;
212
213 /// Valid volume range is [0, 255], see 2.3.1.1, VCS v1.
set_group_volume(&mut self, group_id: i32, volume: u8)214 fn set_group_volume(&mut self, group_id: i32, volume: u8);
215 }
216
217 pub trait IBluetoothMediaCallback: RPCProxy {
218 /// Triggered when a Bluetooth audio device is ready to be used. This should
219 /// only be triggered once for a device and send an event to clients. If the
220 /// device supports both HFP and A2DP, both should be ready when this is
221 /// triggered.
on_bluetooth_audio_device_added(&mut self, device: BluetoothAudioDevice)222 fn on_bluetooth_audio_device_added(&mut self, device: BluetoothAudioDevice);
223
224 ///
on_bluetooth_audio_device_removed(&mut self, addr: RawAddress)225 fn on_bluetooth_audio_device_removed(&mut self, addr: RawAddress);
226
227 ///
on_absolute_volume_supported_changed(&mut self, supported: bool)228 fn on_absolute_volume_supported_changed(&mut self, supported: bool);
229
230 /// Triggered when a Bluetooth device triggers an AVRCP/A2DP volume change
231 /// event. We need to notify audio client to reflect the change on the audio
232 /// stack. The volume should be in the range of 0 to 127.
on_absolute_volume_changed(&mut self, volume: u8)233 fn on_absolute_volume_changed(&mut self, volume: u8);
234
235 /// Triggered when a Bluetooth device triggers a HFP AT command (AT+VGS) to
236 /// notify AG about its speaker volume change. We need to notify audio
237 /// client to reflect the change on the audio stack. The volume should be
238 /// in the range of 0 to 15.
on_hfp_volume_changed(&mut self, volume: u8, addr: RawAddress)239 fn on_hfp_volume_changed(&mut self, volume: u8, addr: RawAddress);
240
241 /// Triggered when HFP audio is disconnected, in which case it could be
242 /// waiting for the audio client to issue a reconnection request. We need
243 /// to notify audio client of this event for it to do appropriate handling.
on_hfp_audio_disconnected(&mut self, addr: RawAddress)244 fn on_hfp_audio_disconnected(&mut self, addr: RawAddress);
245
246 /// Triggered when there is a HFP dump is received. This should only be used
247 /// for debugging and testing purpose.
on_hfp_debug_dump( &mut self, active: bool, codec_id: u16, total_num_decoded_frames: i32, pkt_loss_ratio: f64, begin_ts: u64, end_ts: u64, pkt_status_in_hex: String, pkt_status_in_binary: String, )248 fn on_hfp_debug_dump(
249 &mut self,
250 active: bool,
251 codec_id: u16,
252 total_num_decoded_frames: i32,
253 pkt_loss_ratio: f64,
254 begin_ts: u64,
255 end_ts: u64,
256 pkt_status_in_hex: String,
257 pkt_status_in_binary: String,
258 );
259
260 /// Triggered when the first member of the specified LEA group has connected
261 /// the LE audio profile. This is the earliest meaningful timing to notify
262 /// the audio server that the group as an audio device is available.
on_lea_group_connected(&mut self, group_id: i32, name: String)263 fn on_lea_group_connected(&mut self, group_id: i32, name: String);
264
265 /// Triggered when the last connected member of the specified LEA group has
266 /// disconnected the LE audio profile. This is when we should notify the
267 /// audio server that the group is no longer available as an audio device.
on_lea_group_disconnected(&mut self, group_id: i32)268 fn on_lea_group_disconnected(&mut self, group_id: i32);
269
on_lea_group_status(&mut self, group_id: i32, status: BtLeAudioGroupStatus)270 fn on_lea_group_status(&mut self, group_id: i32, status: BtLeAudioGroupStatus);
271
on_lea_group_node_status( &mut self, addr: RawAddress, group_id: i32, status: BtLeAudioGroupNodeStatus, )272 fn on_lea_group_node_status(
273 &mut self,
274 addr: RawAddress,
275 group_id: i32,
276 status: BtLeAudioGroupNodeStatus,
277 );
278
on_lea_audio_conf( &mut self, direction: u8, group_id: i32, snk_audio_location: u32, src_audio_location: u32, avail_cont: u16, )279 fn on_lea_audio_conf(
280 &mut self,
281 direction: u8,
282 group_id: i32,
283 snk_audio_location: u32,
284 src_audio_location: u32,
285 avail_cont: u16,
286 );
287
on_lea_unicast_monitor_mode_status( &mut self, direction: BtLeAudioDirection, status: BtLeAudioUnicastMonitorModeStatus, )288 fn on_lea_unicast_monitor_mode_status(
289 &mut self,
290 direction: BtLeAudioDirection,
291 status: BtLeAudioUnicastMonitorModeStatus,
292 );
293
on_lea_group_stream_status(&mut self, group_id: i32, status: BtLeAudioGroupStreamStatus)294 fn on_lea_group_stream_status(&mut self, group_id: i32, status: BtLeAudioGroupStreamStatus);
295
on_lea_vc_connected(&mut self, addr: RawAddress, group_id: i32)296 fn on_lea_vc_connected(&mut self, addr: RawAddress, group_id: i32);
297
on_lea_group_volume_changed(&mut self, group_id: i32, volume: u8)298 fn on_lea_group_volume_changed(&mut self, group_id: i32, volume: u8);
299 }
300
301 pub trait IBluetoothTelephony {
302 ///
register_telephony_callback( &mut self, callback: Box<dyn IBluetoothTelephonyCallback + Send>, ) -> bool303 fn register_telephony_callback(
304 &mut self,
305 callback: Box<dyn IBluetoothTelephonyCallback + Send>,
306 ) -> bool;
307
308 /// Sets whether the device is connected to the cellular network.
set_network_available(&mut self, network_available: bool)309 fn set_network_available(&mut self, network_available: bool);
310 /// Sets whether the device is roaming.
set_roaming(&mut self, roaming: bool)311 fn set_roaming(&mut self, roaming: bool);
312 /// Sets the device signal strength, 0 to 5.
set_signal_strength(&mut self, signal_strength: i32) -> bool313 fn set_signal_strength(&mut self, signal_strength: i32) -> bool;
314 /// Sets the device battery level, 0 to 5.
set_battery_level(&mut self, battery_level: i32) -> bool315 fn set_battery_level(&mut self, battery_level: i32) -> bool;
316 /// Enables/disables phone operations.
set_phone_ops_enabled(&mut self, enable: bool)317 fn set_phone_ops_enabled(&mut self, enable: bool);
318 /// Enables/disables phone operations for mps qualification.
319 /// The call state is fully reset whenever this is called.
set_mps_qualification_enabled(&mut self, enable: bool)320 fn set_mps_qualification_enabled(&mut self, enable: bool);
321 /// Acts like the AG received an incoming call.
incoming_call(&mut self, number: String) -> bool322 fn incoming_call(&mut self, number: String) -> bool;
323 /// Acts like dialing a call from the AG.
dialing_call(&mut self, number: String) -> bool324 fn dialing_call(&mut self, number: String) -> bool;
325 /// Acts like answering an incoming/dialing call from the AG.
answer_call(&mut self) -> bool326 fn answer_call(&mut self) -> bool;
327 /// Acts like hanging up an active/incoming/dialing call from the AG.
hangup_call(&mut self) -> bool328 fn hangup_call(&mut self) -> bool;
329 /// Sets/unsets the memory slot. Note that we store at most one memory
330 /// number and return it regardless of which slot is specified by HF.
set_memory_call(&mut self, number: Option<String>) -> bool331 fn set_memory_call(&mut self, number: Option<String>) -> bool;
332 /// Sets/unsets the last call.
set_last_call(&mut self, number: Option<String>) -> bool333 fn set_last_call(&mut self, number: Option<String>) -> bool;
334 /// Releases all of the held calls.
release_held(&mut self) -> bool335 fn release_held(&mut self) -> bool;
336 /// Releases the active call and accepts a held call.
release_active_accept_held(&mut self) -> bool337 fn release_active_accept_held(&mut self) -> bool;
338 /// Holds the active call and accepts a held call.
hold_active_accept_held(&mut self) -> bool339 fn hold_active_accept_held(&mut self) -> bool;
340 /// Establishes an audio connection to <address>.
audio_connect(&mut self, address: RawAddress) -> bool341 fn audio_connect(&mut self, address: RawAddress) -> bool;
342 /// Stops the audio connection to <address>.
audio_disconnect(&mut self, address: RawAddress)343 fn audio_disconnect(&mut self, address: RawAddress);
344 }
345
346 pub trait IBluetoothTelephonyCallback: RPCProxy {
on_telephony_event(&mut self, addr: RawAddress, event: u8, state: u8)347 fn on_telephony_event(&mut self, addr: RawAddress, event: u8, state: u8);
348 }
349
350 /// Serializable device used in.
351 #[derive(Debug, Default, Clone)]
352 pub struct BluetoothAudioDevice {
353 pub address: RawAddress,
354 pub name: String,
355 pub a2dp_caps: Vec<A2dpCodecConfig>,
356 pub hfp_cap: HfpCodecFormat,
357 pub absolute_volume: bool,
358 }
359
360 impl BluetoothAudioDevice {
new( address: RawAddress, name: String, a2dp_caps: Vec<A2dpCodecConfig>, hfp_cap: HfpCodecFormat, absolute_volume: bool, ) -> Self361 pub(crate) fn new(
362 address: RawAddress,
363 name: String,
364 a2dp_caps: Vec<A2dpCodecConfig>,
365 hfp_cap: HfpCodecFormat,
366 absolute_volume: bool,
367 ) -> Self {
368 Self { address, name, a2dp_caps, hfp_cap, absolute_volume }
369 }
370 }
371 /// Actions that `BluetoothMedia` can take on behalf of the stack.
372 pub enum MediaActions {
373 Connect(RawAddress),
374 Disconnect(RawAddress),
375 ForceEnterConnected(RawAddress), // Only used for qualification.
376
377 ConnectLeaGroupByMemberAddress(RawAddress),
378 DisconnectLeaGroupByMemberAddress(RawAddress),
379 ConnectLea(RawAddress),
380 DisconnectLea(RawAddress),
381 ConnectVc(RawAddress),
382 DisconnectVc(RawAddress),
383 ConnectCsis(RawAddress),
384 DisconnectCsis(RawAddress),
385 }
386
387 #[derive(Debug, Clone, PartialEq)]
388 enum DeviceConnectionStates {
389 Initiating, // Some profile is connected, initiated from host side
390 ConnectingBeforeRetry, // Some profile is connected, probably initiated from peer side
391 ConnectingAfterRetry, // Host initiated requests to missing profiles after timeout
392 FullyConnected, // All profiles (excluding AVRCP) are connected
393 Disconnecting, // Working towards disconnection of each connected profile
394 WaitingConnection, // Waiting for new connections initiated by peer
395 }
396
397 struct UHid {
398 pub handle: UHidHfp,
399 pub volume: u8,
400 pub muted: bool,
401 pub is_open: bool,
402 }
403
404 struct LEAAudioConf {
405 pub direction: u8,
406 pub group_id: i32,
407 pub snk_audio_location: u32,
408 pub src_audio_location: u32,
409 pub avail_cont: u16,
410 }
411
412 #[derive(Default, Clone)]
413 struct LeAudioGroup {
414 pub devices: HashSet<RawAddress>,
415 pub status: BtLeAudioGroupStatus,
416 pub stream_status: BtLeAudioGroupStreamStatus,
417 pub volume: Option<u8>,
418 }
419
420 #[derive(Debug, Copy, Clone, FromPrimitive)]
421 #[repr(u8)]
422 enum TelephonyEvent {
423 UHidCreate = 0,
424 UHidDestroy,
425 UHidOpen,
426 UHidClose,
427 UHidIncomingCall,
428 UHidAnswerCall,
429 UHidHangupCall,
430 UHidPlaceActiveCall,
431 UHidMicMute,
432 UHidMicUnmute,
433 CRASPlaceActiveCall,
434 CRASRemoveActiveCall,
435 HFAnswerCall,
436 HFHangupCall,
437 HFMicMute,
438 HFMicUnmute,
439 HFCurrentCallsQuery,
440 }
441
442 impl From<TelephonyEvent> for u8 {
from(telephony_event: TelephonyEvent) -> Self443 fn from(telephony_event: TelephonyEvent) -> Self {
444 telephony_event as u8
445 }
446 }
447
448 pub struct BluetoothMedia {
449 intf: Arc<Mutex<BluetoothInterface>>,
450 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
451 battery_provider_id: u32,
452 initialized: bool,
453 callbacks: Arc<Mutex<Callbacks<dyn IBluetoothMediaCallback + Send>>>,
454 telephony_callbacks: Arc<Mutex<Callbacks<dyn IBluetoothTelephonyCallback + Send>>>,
455 tx: Sender<Message>,
456 adapter: Option<Arc<Mutex<Box<Bluetooth>>>>,
457 a2dp: Option<A2dp>,
458 avrcp: Option<Avrcp>,
459 avrcp_direction: BtConnectionDirection,
460 a2dp_states: HashMap<RawAddress, BtavConnectionState>,
461 a2dp_audio_state: HashMap<RawAddress, BtavAudioState>,
462 a2dp_has_interrupted_stream: bool, // Only used for qualification.
463 hfp: Option<Hfp>,
464 hfp_states: HashMap<RawAddress, BthfConnectionState>,
465 hfp_audio_state: HashMap<RawAddress, BthfAudioState>,
466 a2dp_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>,
467 hfp_cap: HashMap<RawAddress, HfpCodecFormat>,
468 fallback_tasks: Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>,
469 absolute_volume: bool,
470 uinput: UInput,
471 delay_enable_profiles: HashSet<Profile>,
472 connected_profiles: HashMap<RawAddress, HashSet<Profile>>,
473 device_states: Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>,
474 delay_volume_update: HashMap<Profile, u8>,
475 telephony_device_status: TelephonyDeviceStatus,
476 phone_state: PhoneState,
477 call_list: Vec<CallInfo>,
478 phone_ops_enabled: bool,
479 mps_qualification_enabled: bool,
480 memory_dialing_number: Option<String>,
481 last_dialing_number: Option<String>,
482 uhid: HashMap<RawAddress, UHid>,
483 le_audio: Option<LeAudioClient>,
484 le_audio_groups: HashMap<i32, LeAudioGroup>,
485 le_audio_node_to_group: HashMap<RawAddress, i32>,
486 le_audio_states: HashMap<RawAddress, BtLeAudioConnectionState>,
487 le_audio_unicast_monitor_mode_status: HashMap<i32, BtLeAudioUnicastMonitorModeStatus>,
488 le_audio_delayed_audio_conf_updates: HashMap<i32, LEAAudioConf>,
489 le_audio_delayed_vc_connection_updates: HashSet<RawAddress>,
490 vc: Option<VolumeControl>,
491 vc_states: HashMap<RawAddress, BtVcConnectionState>,
492 csis: Option<CsisClient>,
493 csis_states: HashMap<RawAddress, BtCsisConnectionState>,
494 is_le_audio_only_enabled: bool, // TODO: remove this once there is dual mode.
495 }
496
497 impl BluetoothMedia {
new( tx: Sender<Message>, intf: Arc<Mutex<BluetoothInterface>>, battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>, ) -> BluetoothMedia498 pub fn new(
499 tx: Sender<Message>,
500 intf: Arc<Mutex<BluetoothInterface>>,
501 battery_provider_manager: Arc<Mutex<Box<BatteryProviderManager>>>,
502 ) -> BluetoothMedia {
503 let battery_provider_id = battery_provider_manager
504 .lock()
505 .unwrap()
506 .register_battery_provider(Box::new(BatteryProviderCallback::new()));
507 BluetoothMedia {
508 intf,
509 battery_provider_manager,
510 battery_provider_id,
511 initialized: false,
512 callbacks: Arc::new(Mutex::new(Callbacks::new(
513 tx.clone(),
514 Message::MediaCallbackDisconnected,
515 ))),
516 telephony_callbacks: Arc::new(Mutex::new(Callbacks::new(
517 tx.clone(),
518 Message::TelephonyCallbackDisconnected,
519 ))),
520 tx,
521 adapter: None,
522 a2dp: None,
523 avrcp: None,
524 avrcp_direction: BtConnectionDirection::Unknown,
525 a2dp_states: HashMap::new(),
526 a2dp_audio_state: HashMap::new(),
527 a2dp_has_interrupted_stream: false,
528 hfp: None,
529 hfp_states: HashMap::new(),
530 hfp_audio_state: HashMap::new(),
531 a2dp_caps: HashMap::new(),
532 hfp_cap: HashMap::new(),
533 fallback_tasks: Arc::new(Mutex::new(HashMap::new())),
534 absolute_volume: false,
535 uinput: UInput::new(),
536 delay_enable_profiles: HashSet::new(),
537 connected_profiles: HashMap::new(),
538 device_states: Arc::new(Mutex::new(HashMap::new())),
539 delay_volume_update: HashMap::new(),
540 telephony_device_status: TelephonyDeviceStatus::new(),
541 phone_state: PhoneState { num_active: 0, num_held: 0, state: CallState::Idle },
542 call_list: vec![],
543 phone_ops_enabled: false,
544 mps_qualification_enabled: false,
545 memory_dialing_number: None,
546 last_dialing_number: None,
547 uhid: HashMap::new(),
548 le_audio: None,
549 le_audio_groups: HashMap::new(),
550 le_audio_node_to_group: HashMap::new(),
551 le_audio_states: HashMap::new(),
552 le_audio_unicast_monitor_mode_status: HashMap::new(),
553 le_audio_delayed_audio_conf_updates: HashMap::new(),
554 le_audio_delayed_vc_connection_updates: HashSet::new(),
555 vc: None,
556 vc_states: HashMap::new(),
557 csis: None,
558 csis_states: HashMap::new(),
559 is_le_audio_only_enabled: false,
560 }
561 }
562
is_profile_connected(&self, addr: &RawAddress, profile: &Profile) -> bool563 fn is_profile_connected(&self, addr: &RawAddress, profile: &Profile) -> bool {
564 self.is_any_profile_connected(addr, &[profile.clone()])
565 }
566
is_any_profile_connected(&self, addr: &RawAddress, profiles: &[Profile]) -> bool567 fn is_any_profile_connected(&self, addr: &RawAddress, profiles: &[Profile]) -> bool {
568 if let Some(connected_profiles) = self.connected_profiles.get(addr) {
569 return profiles.iter().any(|p| connected_profiles.contains(&p));
570 }
571
572 return false;
573 }
574
add_connected_profile(&mut self, addr: RawAddress, profile: Profile)575 fn add_connected_profile(&mut self, addr: RawAddress, profile: Profile) {
576 if self.is_profile_connected(&addr, &profile) {
577 warn!("[{}]: profile is already connected", DisplayAddress(&addr));
578 return;
579 }
580
581 self.connected_profiles.entry(addr).or_insert_with(HashSet::new).insert(profile);
582
583 self.notify_media_capability_updated(addr);
584 }
585
rm_connected_profile( &mut self, addr: RawAddress, profile: Profile, is_profile_critical: bool, )586 fn rm_connected_profile(
587 &mut self,
588 addr: RawAddress,
589 profile: Profile,
590 is_profile_critical: bool,
591 ) {
592 if !self.is_profile_connected(&addr, &profile) {
593 warn!("[{}]: profile is already disconnected", DisplayAddress(&addr));
594 return;
595 }
596
597 self.connected_profiles.entry(addr).or_insert_with(HashSet::new).remove(&profile);
598 self.delay_volume_update.remove(&profile);
599
600 if is_profile_critical && self.is_complete_profiles_required() {
601 BluetoothMedia::disconnect_device(self.tx.clone(), addr);
602 self.notify_critical_profile_disconnected(addr);
603 }
604
605 self.notify_media_capability_updated(addr);
606 }
607
is_group_connected(&self, group: &LeAudioGroup) -> bool608 fn is_group_connected(&self, group: &LeAudioGroup) -> bool {
609 group.devices.iter().any(|&addr| {
610 *self.le_audio_states.get(&addr).unwrap_or(&BtLeAudioConnectionState::Disconnected)
611 == BtLeAudioConnectionState::Connected
612 })
613 }
614
remove_device_from_group(&mut self, addr: RawAddress)615 fn remove_device_from_group(&mut self, addr: RawAddress) {
616 let group_id = match self.le_audio_node_to_group.get(&addr) {
617 Some(group_id) => group_id,
618 None => {
619 warn!("Cannot remove device {} that belongs to no group", DisplayAddress(&addr));
620 return;
621 }
622 };
623
624 match self.le_audio_groups.get_mut(&group_id) {
625 Some(group) => {
626 group.devices.remove(&addr);
627 if group.devices.is_empty() {
628 self.le_audio_groups.remove(&group_id);
629 }
630 }
631 None => {
632 warn!(
633 "{} claims to be in group {} which does not exist",
634 DisplayAddress(&addr),
635 group_id
636 );
637 return;
638 }
639 }
640 }
641
set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>)642 pub fn set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>) {
643 self.adapter = Some(adapter);
644 }
645
enable_profile(&mut self, profile: &Profile)646 pub fn enable_profile(&mut self, profile: &Profile) {
647 match profile {
648 Profile::A2dpSource | Profile::AvrcpTarget | Profile::Hfp => {
649 if self.is_le_audio_only_enabled {
650 info!("LeAudioEnableLeAudioOnly is set, skip enabling {:?}", profile);
651 return;
652 }
653 }
654 Profile::LeAudio | Profile::VolumeControl | Profile::CoordinatedSet => {
655 if !self.is_le_audio_only_enabled {
656 info!("LeAudioEnableLeAudioOnly is not set, skip enabling {:?}", profile);
657 return;
658 }
659 }
660 _ => {}
661 }
662
663 match profile {
664 &Profile::A2dpSource => {
665 if let Some(a2dp) = &mut self.a2dp {
666 a2dp.enable();
667 }
668 }
669 &Profile::AvrcpTarget => {
670 if let Some(avrcp) = &mut self.avrcp {
671 avrcp.enable();
672 }
673 }
674 &Profile::Hfp => {
675 if let Some(hfp) = &mut self.hfp {
676 hfp.enable();
677 }
678 }
679 &Profile::LeAudio => {
680 if let Some(le_audio) = &mut self.le_audio {
681 le_audio.enable();
682 }
683 }
684 &Profile::VolumeControl => {
685 if let Some(vc) = &mut self.vc {
686 vc.enable();
687 }
688 }
689 &Profile::CoordinatedSet => {
690 if let Some(csis) = &mut self.csis {
691 csis.enable();
692 }
693 }
694 _ => {
695 warn!("Tried to enable {} in bluetooth_media", profile);
696 return;
697 }
698 }
699
700 if self.is_profile_enabled(profile).unwrap() {
701 self.delay_enable_profiles.remove(profile);
702 } else {
703 self.delay_enable_profiles.insert(profile.clone());
704 }
705 }
706
disable_profile(&mut self, profile: &Profile)707 pub fn disable_profile(&mut self, profile: &Profile) {
708 match profile {
709 &Profile::A2dpSource => {
710 if let Some(a2dp) = &mut self.a2dp {
711 a2dp.disable();
712 }
713 }
714 &Profile::AvrcpTarget => {
715 if let Some(avrcp) = &mut self.avrcp {
716 avrcp.disable();
717 }
718 }
719 &Profile::Hfp => {
720 if let Some(hfp) = &mut self.hfp {
721 hfp.disable();
722 }
723 }
724 &Profile::LeAudio => {
725 if let Some(le_audio) = &mut self.le_audio {
726 le_audio.disable();
727 }
728 }
729 &Profile::VolumeControl => {
730 if let Some(vc) = &mut self.vc {
731 vc.disable();
732 }
733 }
734 &Profile::CoordinatedSet => {
735 if let Some(csis) = &mut self.csis {
736 csis.disable();
737 }
738 }
739 _ => {
740 warn!("Tried to disable {} in bluetooth_media", profile);
741 return;
742 }
743 }
744
745 self.delay_enable_profiles.remove(profile);
746 }
747
is_profile_enabled(&self, profile: &Profile) -> Option<bool>748 pub fn is_profile_enabled(&self, profile: &Profile) -> Option<bool> {
749 match profile {
750 &Profile::A2dpSource => {
751 Some(self.a2dp.as_ref().map_or(false, |a2dp| a2dp.is_enabled()))
752 }
753 &Profile::AvrcpTarget => {
754 Some(self.avrcp.as_ref().map_or(false, |avrcp| avrcp.is_enabled()))
755 }
756 &Profile::Hfp => Some(self.hfp.as_ref().map_or(false, |hfp| hfp.is_enabled())),
757 &Profile::LeAudio => {
758 Some(self.le_audio.as_ref().map_or(false, |le_audio| le_audio.is_enabled()))
759 }
760 &Profile::VolumeControl => Some(self.vc.as_ref().map_or(false, |vc| vc.is_enabled())),
761 &Profile::CoordinatedSet => {
762 Some(self.csis.as_ref().map_or(false, |csis| csis.is_enabled()))
763 }
764 _ => {
765 warn!("Tried to query enablement status of {} in bluetooth_media", profile);
766 None
767 }
768 }
769 }
770
dispatch_csis_callbacks(&mut self, cb: CsisClientCallbacks)771 pub fn dispatch_csis_callbacks(&mut self, cb: CsisClientCallbacks) {
772 match cb {
773 CsisClientCallbacks::ConnectionState(addr, state) => {
774 if !self.csis_states.get(&addr).is_none()
775 && state == *self.csis_states.get(&addr).unwrap()
776 {
777 return;
778 }
779
780 info!(
781 "CsisClientCallbacks::ConnectionState: [{}]: state={:?}",
782 DisplayAddress(&addr),
783 state
784 );
785
786 match state {
787 BtCsisConnectionState::Connected => {
788 self.csis_states.insert(addr, state);
789 }
790 BtCsisConnectionState::Disconnected => {
791 self.csis_states.remove(&addr);
792 }
793 _ => {
794 self.csis_states.insert(addr, state);
795 }
796 }
797 }
798 CsisClientCallbacks::DeviceAvailable(addr, group_id, group_size, rank, uuid) => {
799 info!(
800 "CsisClientCallbacks::DeviceAvailable: [{}]: group_id={}, group_size={}, rank={}, uuid={:?}",
801 DisplayAddress(&addr),
802 group_id,
803 group_size,
804 rank,
805 uuid,
806 );
807 }
808 CsisClientCallbacks::SetMemberAvailable(addr, group_id) => {
809 info!(
810 "CsisClientCallbacks::SetMemberAvailable: [{}]: group_id={}",
811 DisplayAddress(&addr),
812 group_id
813 );
814 let device = BluetoothDevice::new(addr, "".to_string());
815 let txl = self.tx.clone();
816 topstack::get_runtime().spawn(async move {
817 let _ = txl
818 .send(Message::CreateBondWithRetry(
819 device,
820 BtTransport::Le,
821 CSIS_BONDING_NUM_ATTEMPTS,
822 Duration::from_millis(CSIS_BONDING_RETRY_DELAY_MS),
823 ))
824 .await;
825 });
826 }
827 CsisClientCallbacks::GroupLockChanged(group_id, locked, status) => {
828 info!(
829 "CsisClientCallbacks::GroupLockChanged: group_id={}, locked={}, status={:?}",
830 group_id, locked, status
831 );
832 }
833 }
834 }
835
dispatch_vc_callbacks(&mut self, cb: VolumeControlCallbacks)836 pub fn dispatch_vc_callbacks(&mut self, cb: VolumeControlCallbacks) {
837 match cb {
838 VolumeControlCallbacks::ConnectionState(state, addr) => {
839 if !self.vc_states.get(&addr).is_none()
840 && state == *self.vc_states.get(&addr).unwrap()
841 {
842 return;
843 }
844
845 info!(
846 "VolumeControlCallbacks::ConnectionState: [{}]: state={:?}",
847 DisplayAddress(&addr),
848 state
849 );
850
851 match state {
852 BtVcConnectionState::Connected => {
853 self.vc_states.insert(addr, state);
854
855 let group_id = self.get_group_id(addr);
856 match self.le_audio_groups.get(&group_id) {
857 Some(group) if self.is_group_connected(group) => {
858 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
859 callback.on_lea_vc_connected(addr, group_id);
860 });
861
862 // Sync group volume in case this new member has not been adjusted.
863 if let Some(volume) = group.volume {
864 self.set_group_volume(group_id, volume);
865 }
866 }
867 _ => {
868 self.le_audio_delayed_vc_connection_updates.insert(addr);
869 }
870 }
871 }
872 BtVcConnectionState::Disconnected => {
873 self.vc_states.remove(&addr);
874 }
875 _ => {
876 self.vc_states.insert(addr, state);
877 }
878 }
879 }
880 VolumeControlCallbacks::VolumeState(addr, volume, mute, is_autonomous) => {
881 info!(
882 "VolumeControlCallbacks::VolumeState: [{}]: volume={}, mute={}, is_autonomous={}",
883 DisplayAddress(&addr),
884 volume,
885 mute,
886 is_autonomous
887 );
888 }
889 VolumeControlCallbacks::GroupVolumeState(group_id, volume, mute, is_autonomous) => {
890 info!(
891 "VolumeControlCallbacks::GroupVolumeState: group_id={}, volume={}, mute={}, is_autonomous={}",
892 group_id, volume, mute, is_autonomous
893 );
894
895 // This can come with ~300ms delay, thus notify only when
896 // triggered by the headset. Otherwise expect the audio server
897 // to know the expected volume.
898 if is_autonomous {
899 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
900 callback.on_lea_group_volume_changed(group_id, volume);
901 });
902 }
903
904 self.le_audio_groups.entry(group_id).or_default().volume = Some(volume);
905 }
906 VolumeControlCallbacks::DeviceAvailable(addr, num_offset) => {
907 info!(
908 "VolumeControlCallbacks::DeviceAvailable: [{}]: num_offset={}",
909 DisplayAddress(&addr),
910 num_offset
911 );
912 }
913 VolumeControlCallbacks::ExtAudioOutVolume(addr, ext_output_id, offset) => {
914 info!(
915 "VolumeControlCallbacks::ExtAudioOutVolume: [{}]: ext_output_id={}, offset={}",
916 DisplayAddress(&addr),
917 ext_output_id,
918 offset
919 );
920 }
921 VolumeControlCallbacks::ExtAudioOutLocation(addr, ext_output_id, location) => {
922 info!(
923 "VolumeControlCallbacks::ExtAudioOutLocation: [{}]: ext_output_id={}, location={}",
924 DisplayAddress(&addr),
925 ext_output_id,
926 location
927 );
928 }
929 VolumeControlCallbacks::ExtAudioOutDescription(addr, ext_output_id, descr) => {
930 info!(
931 "VolumeControlCallbacks::ExtAudioOutDescription: [{}]: ext_output_id={}, descr={}",
932 DisplayAddress(&addr),
933 ext_output_id,
934 descr
935 );
936 }
937 }
938 }
939
dispatch_le_audio_callbacks(&mut self, cb: LeAudioClientCallbacks)940 pub fn dispatch_le_audio_callbacks(&mut self, cb: LeAudioClientCallbacks) {
941 match cb {
942 LeAudioClientCallbacks::Initialized() => {
943 info!("LeAudioClientCallbacks::Initialized: ");
944 }
945 LeAudioClientCallbacks::ConnectionState(state, addr) => {
946 if !self.le_audio_states.get(&addr).is_none()
947 && state == *self.le_audio_states.get(&addr).unwrap()
948 {
949 return;
950 }
951
952 let group_id = self.get_group_id(addr);
953 if group_id == LEA_UNKNOWN_GROUP_ID {
954 warn!(
955 "LeAudioClientCallbacks::ConnectionState: [{}] Ignored dispatching of LeAudio callback on a device with no group",
956 DisplayAddress(&addr)
957 );
958 return;
959 }
960
961 let is_only_connected_member = match self.le_audio_groups.get(&group_id) {
962 Some(group) => group.devices.iter().all(|&member_addr| {
963 member_addr == addr
964 || *self
965 .le_audio_states
966 .get(&member_addr)
967 .unwrap_or(&BtLeAudioConnectionState::Disconnected)
968 != BtLeAudioConnectionState::Connected
969 }),
970 _ => true,
971 };
972
973 info!(
974 "LeAudioClientCallbacks::ConnectionState: [{}]: state={:?}, group_id={}, is_only_connected_member={}",
975 DisplayAddress(&addr),
976 state,
977 group_id,
978 is_only_connected_member
979 );
980
981 match state {
982 BtLeAudioConnectionState::Connected => {
983 if is_only_connected_member {
984 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
985 callback.on_lea_group_connected(
986 group_id,
987 self.adapter_get_remote_name(addr),
988 );
989 });
990
991 match self.le_audio_delayed_audio_conf_updates.remove(&group_id) {
992 Some(conf) => {
993 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
994 callback.on_lea_audio_conf(
995 conf.direction,
996 conf.group_id,
997 conf.snk_audio_location,
998 conf.src_audio_location,
999 conf.avail_cont,
1000 );
1001 });
1002 }
1003 _ => {}
1004 }
1005 }
1006
1007 if self.le_audio_delayed_vc_connection_updates.remove(&addr) {
1008 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1009 callback.on_lea_vc_connected(addr, group_id);
1010 });
1011 }
1012
1013 self.le_audio_states.insert(addr, state);
1014 }
1015 BtLeAudioConnectionState::Disconnected => {
1016 if self.le_audio_states.remove(&addr).is_some() {
1017 if is_only_connected_member {
1018 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1019 callback.on_lea_group_disconnected(group_id);
1020 });
1021 }
1022 }
1023
1024 // In anticipation that it could possibly never be connected.
1025 self.le_audio_delayed_vc_connection_updates.remove(&addr);
1026 }
1027 _ => {
1028 self.le_audio_states.insert(addr, state);
1029 }
1030 }
1031 }
1032 LeAudioClientCallbacks::GroupStatus(group_id, status) => {
1033 if !self.le_audio_groups.get(&group_id).is_none()
1034 && status == self.le_audio_groups.get(&group_id).unwrap().status
1035 {
1036 return;
1037 }
1038
1039 info!(
1040 "LeAudioClientCallbacks::GroupStatus: group_id={}, status={:?}",
1041 group_id, status
1042 );
1043
1044 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1045 callback.on_lea_group_status(group_id, status);
1046 });
1047
1048 self.le_audio_groups.entry(group_id).or_default().status = status;
1049 }
1050 LeAudioClientCallbacks::GroupNodeStatus(addr, group_id, status) => {
1051 info!(
1052 "LeAudioClientCallbacks::GroupNodeStatus: [{}]: group_id={}, status={:?}",
1053 DisplayAddress(&addr),
1054 group_id,
1055 status
1056 );
1057
1058 match status {
1059 BtLeAudioGroupNodeStatus::Added => {
1060 match self.le_audio_node_to_group.get(&addr) {
1061 Some(old_group_id) if *old_group_id != group_id => {
1062 warn!(
1063 "LeAudioClientCallbacks::GroupNodeStatus: [{}]: node already belongs to another group {}",
1064 DisplayAddress(&addr),
1065 old_group_id,
1066 );
1067
1068 self.remove_device_from_group(addr);
1069 }
1070 _ => {}
1071 }
1072
1073 self.le_audio_node_to_group.insert(addr, group_id);
1074
1075 let group = self.le_audio_groups.entry(group_id).or_default();
1076
1077 group.devices.insert(addr);
1078
1079 if let Some(volume) = group.volume {
1080 self.set_group_volume(group_id, volume);
1081 }
1082 }
1083 BtLeAudioGroupNodeStatus::Removed => {
1084 match self.le_audio_node_to_group.get(&addr) {
1085 Some(old_group_id) if *old_group_id == group_id => {
1086 self.remove_device_from_group(addr);
1087 }
1088 Some(old_group_id) if *old_group_id != group_id => {
1089 warn!(
1090 "LeAudioClientCallbacks::GroupNodeStatus: [{}]: cannot remove node from group {} because it is in group {}",
1091 DisplayAddress(&addr),
1092 group_id,
1093 old_group_id,
1094 );
1095
1096 return;
1097 }
1098 _ => {}
1099 }
1100
1101 self.le_audio_node_to_group.remove(&addr);
1102 }
1103 _ => {
1104 warn!("LeAudioClientCallbacks::GroupNodeStatus: Unknown status for GroupNodeStatus {:?}", status);
1105 }
1106 }
1107
1108 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1109 callback.on_lea_group_node_status(addr, group_id, status);
1110 });
1111 }
1112 LeAudioClientCallbacks::AudioConf(
1113 direction,
1114 group_id,
1115 snk_audio_location,
1116 src_audio_location,
1117 avail_cont,
1118 ) => {
1119 info!(
1120 "LeAudioClientCallbacks::AudioConf: direction={}, group_id={}, snk_audio_location={}, src_audio_location={}, avail_cont={}",
1121 direction, group_id, snk_audio_location, src_audio_location, avail_cont,
1122 );
1123
1124 match self.le_audio_groups.get(&group_id) {
1125 Some(group) if self.is_group_connected(group) => {
1126 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1127 callback.on_lea_audio_conf(
1128 direction,
1129 group_id,
1130 snk_audio_location,
1131 src_audio_location,
1132 avail_cont,
1133 );
1134 });
1135 }
1136 _ => {
1137 self.le_audio_delayed_audio_conf_updates.insert(
1138 group_id,
1139 LEAAudioConf {
1140 direction,
1141 group_id,
1142 snk_audio_location,
1143 src_audio_location,
1144 avail_cont,
1145 },
1146 );
1147 }
1148 }
1149 }
1150 LeAudioClientCallbacks::SinkAudioLocationAvailable(addr, snk_audio_locations) => {
1151 info!("LeAudioClientCallbacks::SinkAudioLocationAvailable: [{}]: snk_audio_locations={:?}", DisplayAddress(&addr), snk_audio_locations);
1152 }
1153 LeAudioClientCallbacks::AudioLocalCodecCapabilities(
1154 local_input_codec_conf,
1155 local_output_codec_conf,
1156 ) => {
1157 info!(
1158 "LeAudioClientCallbacks::AudioLocalCodecCapabilities: local_input_codec_conf={:?}, local_output_codec_conf={:?}",
1159 local_input_codec_conf, local_output_codec_conf
1160 );
1161 }
1162 LeAudioClientCallbacks::AudioGroupCodecConf(
1163 group_id,
1164 input_codec_conf,
1165 output_codec_conf,
1166 input_caps,
1167 output_caps,
1168 ) => {
1169 info!("LeAudioClientCallbacks::AudioGroupCodecConf: group_id={}, input_codec_conf={:?}, output_codec_conf={:?}, input_caps={:?}, output_caps={:?}",
1170 group_id, input_codec_conf, output_codec_conf, input_caps, output_caps);
1171 }
1172 LeAudioClientCallbacks::UnicastMonitorModeStatus(direction, status) => {
1173 if !self.le_audio_unicast_monitor_mode_status.get(&direction.into()).is_none()
1174 && status
1175 == *self
1176 .le_audio_unicast_monitor_mode_status
1177 .get(&direction.into())
1178 .unwrap()
1179 {
1180 return;
1181 }
1182
1183 info!(
1184 "LeAudioClientCallbacks::UnicastMonitorModeStatus: direction={:?}, status={:?}",
1185 direction, status
1186 );
1187
1188 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1189 callback.on_lea_unicast_monitor_mode_status(direction, status);
1190 });
1191
1192 self.le_audio_unicast_monitor_mode_status.insert(direction.into(), status);
1193 }
1194 LeAudioClientCallbacks::GroupStreamStatus(group_id, status) => {
1195 if !self.le_audio_groups.get(&group_id).is_none()
1196 && status == self.le_audio_groups.get(&group_id).unwrap().stream_status
1197 {
1198 return;
1199 }
1200
1201 info!(
1202 "LeAudioClientCallbacks::GroupStreamStatus: group_id={} status {:?}",
1203 group_id, status
1204 );
1205
1206 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1207 callback.on_lea_group_stream_status(group_id, status);
1208 });
1209
1210 self.le_audio_groups.entry(group_id).or_default().stream_status = status;
1211 }
1212 }
1213 }
1214
dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks)1215 pub fn dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks) {
1216 match cb {
1217 A2dpCallbacks::ConnectionState(addr, state, error) => {
1218 if !self.a2dp_states.get(&addr).is_none()
1219 && state == *self.a2dp_states.get(&addr).unwrap()
1220 {
1221 return;
1222 }
1223 metrics::profile_connection_state_changed(
1224 addr,
1225 Profile::A2dpSink as u32,
1226 error.status,
1227 state.clone() as u32,
1228 );
1229 match state {
1230 BtavConnectionState::Connected => {
1231 info!("[{}]: a2dp connected.", DisplayAddress(&addr));
1232 self.a2dp_states.insert(addr, state);
1233 self.add_connected_profile(addr, Profile::A2dpSink);
1234 }
1235 BtavConnectionState::Disconnected => {
1236 info!("[{}]: a2dp disconnected.", DisplayAddress(&addr));
1237 self.a2dp_states.remove(&addr);
1238 self.a2dp_caps.remove(&addr);
1239 self.a2dp_audio_state.remove(&addr);
1240 self.rm_connected_profile(addr, Profile::A2dpSink, true);
1241 }
1242 _ => {
1243 self.a2dp_states.insert(addr, state);
1244 }
1245 }
1246 }
1247 A2dpCallbacks::AudioState(addr, state) => {
1248 info!("[{}]: a2dp audio state: {:?}", DisplayAddress(&addr), state);
1249 self.a2dp_audio_state.insert(addr, state);
1250 }
1251 A2dpCallbacks::AudioConfig(addr, _config, _local_caps, a2dp_caps) => {
1252 debug!("[{}]: a2dp updated audio config: {:?}", DisplayAddress(&addr), a2dp_caps);
1253 self.a2dp_caps.insert(addr, a2dp_caps);
1254 }
1255 A2dpCallbacks::MandatoryCodecPreferred(_addr) => {}
1256 }
1257 }
1258
disconnect_device(txl: Sender<Message>, addr: RawAddress)1259 fn disconnect_device(txl: Sender<Message>, addr: RawAddress) {
1260 let device = BluetoothDevice::new(addr, "".to_string());
1261 topstack::get_runtime().spawn(async move {
1262 let _ = txl.send(Message::DisconnectDevice(device)).await;
1263 });
1264 }
1265
dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks)1266 pub fn dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks) {
1267 match cb {
1268 AvrcpCallbacks::AvrcpDeviceConnected(addr, supported) => {
1269 info!(
1270 "[{}]: avrcp connected. Absolute volume support: {}.",
1271 DisplayAddress(&addr),
1272 supported
1273 );
1274
1275 match self.uinput.create(self.adapter_get_remote_name(addr), addr.to_string()) {
1276 Ok(()) => info!("uinput device created for: {}", DisplayAddress(&addr)),
1277 Err(e) => warn!("{}", e),
1278 }
1279
1280 // Notify change via callback if device is added.
1281 if self.absolute_volume != supported {
1282 let guard = self.fallback_tasks.lock().unwrap();
1283 if let Some(task) = guard.get(&addr) {
1284 if task.is_none() {
1285 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1286 callback.on_absolute_volume_supported_changed(supported);
1287 });
1288 }
1289 }
1290 }
1291
1292 self.absolute_volume = supported;
1293
1294 // If is device initiated the AVRCP connection, emit a fake connecting state as
1295 // stack don't receive one.
1296 if self.avrcp_direction != BtConnectionDirection::Outgoing {
1297 metrics::profile_connection_state_changed(
1298 addr,
1299 Profile::AvrcpController as u32,
1300 BtStatus::Success,
1301 BtavConnectionState::Connecting as u32,
1302 );
1303 }
1304 metrics::profile_connection_state_changed(
1305 addr,
1306 Profile::AvrcpController as u32,
1307 BtStatus::Success,
1308 BtavConnectionState::Connected as u32,
1309 );
1310 // Reset direction to unknown.
1311 self.avrcp_direction = BtConnectionDirection::Unknown;
1312
1313 self.add_connected_profile(addr, Profile::AvrcpController);
1314 }
1315 AvrcpCallbacks::AvrcpDeviceDisconnected(addr) => {
1316 info!("[{}]: avrcp disconnected.", DisplayAddress(&addr));
1317
1318 self.uinput.close(addr.to_string());
1319
1320 // TODO: better support for multi-device
1321 self.absolute_volume = false;
1322
1323 // This may be considered a critical profile in the extreme case
1324 // where only AVRCP was connected.
1325 let is_profile_critical = match self.connected_profiles.get(&addr) {
1326 Some(profiles) => *profiles == HashSet::from([Profile::AvrcpController]),
1327 None => false,
1328 };
1329
1330 // If the peer device initiated the AVRCP disconnection, emit a fake connecting
1331 // state as stack don't receive one.
1332 if self.avrcp_direction != BtConnectionDirection::Outgoing {
1333 metrics::profile_connection_state_changed(
1334 addr,
1335 Profile::AvrcpController as u32,
1336 BtStatus::Success,
1337 BtavConnectionState::Disconnecting as u32,
1338 );
1339 }
1340 metrics::profile_connection_state_changed(
1341 addr,
1342 Profile::AvrcpController as u32,
1343 BtStatus::Success,
1344 BtavConnectionState::Disconnected as u32,
1345 );
1346 // Reset direction to unknown.
1347 self.avrcp_direction = BtConnectionDirection::Unknown;
1348
1349 self.rm_connected_profile(addr, Profile::AvrcpController, is_profile_critical);
1350 }
1351 AvrcpCallbacks::AvrcpAbsoluteVolumeUpdate(volume) => {
1352 for (addr, state) in self.device_states.lock().unwrap().iter() {
1353 info!("[{}]: state {:?}", DisplayAddress(&addr), state);
1354 match state {
1355 DeviceConnectionStates::ConnectingBeforeRetry
1356 | DeviceConnectionStates::ConnectingAfterRetry
1357 | DeviceConnectionStates::WaitingConnection => {
1358 self.delay_volume_update.insert(Profile::AvrcpController, volume);
1359 }
1360 DeviceConnectionStates::FullyConnected => {
1361 self.delay_volume_update.remove(&Profile::AvrcpController);
1362 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1363 callback.on_absolute_volume_changed(volume);
1364 });
1365 return;
1366 }
1367 _ => {}
1368 }
1369 }
1370 }
1371 AvrcpCallbacks::AvrcpSendKeyEvent(key, value) => {
1372 match self.uinput.send_key(key, value) {
1373 Ok(()) => (),
1374 Err(e) => warn!("{}", e),
1375 }
1376
1377 const AVRCP_ID_PAUSE: u8 = 0x46;
1378 const AVRCP_STATE_PRESS: u8 = 0;
1379
1380 // Per MPS v1.0, on receiving a pause key through AVRCP,
1381 // central should pause the A2DP stream with an AVDTP suspend command.
1382 if self.mps_qualification_enabled
1383 && key == AVRCP_ID_PAUSE
1384 && value == AVRCP_STATE_PRESS
1385 {
1386 self.suspend_audio_request_impl();
1387 }
1388 }
1389 AvrcpCallbacks::AvrcpSetActiveDevice(addr) => {
1390 self.uinput.set_active_device(addr.to_string());
1391 }
1392 }
1393 }
1394
dispatch_media_actions(&mut self, action: MediaActions)1395 pub fn dispatch_media_actions(&mut self, action: MediaActions) {
1396 match action {
1397 MediaActions::Connect(address) => self.connect(address),
1398 MediaActions::Disconnect(address) => self.disconnect(address),
1399 MediaActions::ForceEnterConnected(address) => self.force_enter_connected(address),
1400
1401 MediaActions::ConnectLea(address) => self.connect_lea(address),
1402 MediaActions::DisconnectLea(address) => self.disconnect_lea(address),
1403 MediaActions::ConnectVc(address) => self.connect_vc(address),
1404 MediaActions::DisconnectVc(address) => self.disconnect_vc(address),
1405 MediaActions::ConnectCsis(address) => self.connect_csis(address),
1406 MediaActions::DisconnectCsis(address) => self.disconnect_csis(address),
1407
1408 MediaActions::ConnectLeaGroupByMemberAddress(address) => {
1409 self.connect_lea_group_by_member_address(address)
1410 }
1411 MediaActions::DisconnectLeaGroupByMemberAddress(address) => {
1412 self.disconnect_lea_group_by_member_address(address)
1413 }
1414 }
1415 }
1416
dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks)1417 pub fn dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks) {
1418 match cb {
1419 HfpCallbacks::ConnectionState(state, addr) => {
1420 if !self.hfp_states.get(&addr).is_none()
1421 && state == *self.hfp_states.get(&addr).unwrap()
1422 {
1423 return;
1424 }
1425 metrics::profile_connection_state_changed(
1426 addr,
1427 Profile::Hfp as u32,
1428 BtStatus::Success,
1429 state.clone() as u32,
1430 );
1431 match state {
1432 BthfConnectionState::Connected => {
1433 info!("[{}]: hfp connected.", DisplayAddress(&addr));
1434 }
1435 BthfConnectionState::SlcConnected => {
1436 info!("[{}]: hfp slc connected.", DisplayAddress(&addr));
1437 // The device may not support codec-negotiation,
1438 // in which case we shall assume it supports CVSD at this point.
1439 if !self.hfp_cap.contains_key(&addr) {
1440 self.hfp_cap.insert(addr, HfpCodecFormat::CVSD);
1441 }
1442 self.add_connected_profile(addr, Profile::Hfp);
1443
1444 // Connect SCO if phone operations are enabled and an active call exists.
1445 // This is only used for Bluetooth HFP qualification.
1446 if self.mps_qualification_enabled && self.phone_state.num_active > 0 {
1447 debug!("[{}]: Connect SCO due to active call.", DisplayAddress(&addr));
1448 self.start_sco_call_impl(addr, false, HfpCodecBitId::NONE);
1449 }
1450
1451 if self.phone_ops_enabled {
1452 self.uhid_create(addr);
1453 }
1454 }
1455 BthfConnectionState::Disconnected => {
1456 info!("[{}]: hfp disconnected.", DisplayAddress(&addr));
1457 self.uhid_destroy(&addr);
1458 self.hfp_states.remove(&addr);
1459 self.hfp_cap.remove(&addr);
1460 self.hfp_audio_state.remove(&addr);
1461 self.rm_connected_profile(addr, Profile::Hfp, true);
1462 }
1463 BthfConnectionState::Connecting => {
1464 info!("[{}]: hfp connecting.", DisplayAddress(&addr));
1465 }
1466 BthfConnectionState::Disconnecting => {
1467 info!("[{}]: hfp disconnecting.", DisplayAddress(&addr));
1468 }
1469 }
1470
1471 self.hfp_states.insert(addr, state);
1472 }
1473 HfpCallbacks::AudioState(state, addr) => {
1474 if self.hfp_states.get(&addr).is_none()
1475 || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap()
1476 {
1477 warn!("[{}]: Unknown address hfp or slc not ready", DisplayAddress(&addr));
1478 return;
1479 }
1480
1481 match state {
1482 BthfAudioState::Connected => {
1483 info!("[{}]: hfp audio connected.", DisplayAddress(&addr));
1484
1485 self.hfp_audio_state.insert(addr, state);
1486
1487 if self.should_insert_call_when_sco_start(addr) {
1488 // This triggers a +CIEV command to set the call status for HFP devices.
1489 // It is required for some devices to provide sound.
1490 self.place_active_call();
1491 self.notify_telephony_event(&addr, TelephonyEvent::CRASPlaceActiveCall);
1492 }
1493 }
1494 BthfAudioState::Disconnected => {
1495 info!("[{}]: hfp audio disconnected.", DisplayAddress(&addr));
1496
1497 // Ignore disconnected -> disconnected
1498 if let Some(BthfAudioState::Connected) =
1499 self.hfp_audio_state.insert(addr, state)
1500 {
1501 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1502 callback.on_hfp_audio_disconnected(addr);
1503 });
1504 }
1505
1506 if self.should_insert_call_when_sco_start(addr) {
1507 // Remove the only call related to the one added for devices requesting to force +CIEV command
1508 self.call_list = vec![];
1509 self.phone_state.num_active = 0;
1510 self.phone_state_change("".into());
1511 self.notify_telephony_event(
1512 &addr,
1513 TelephonyEvent::CRASRemoveActiveCall,
1514 );
1515 }
1516
1517 // Resume the A2DP stream when a phone call ended (per MPS v1.0).
1518 self.try_a2dp_resume();
1519 }
1520 BthfAudioState::Connecting => {
1521 info!("[{}]: hfp audio connecting.", DisplayAddress(&addr));
1522 }
1523 BthfAudioState::Disconnecting => {
1524 info!("[{}]: hfp audio disconnecting.", DisplayAddress(&addr));
1525 }
1526 }
1527 }
1528 HfpCallbacks::VolumeUpdate(volume, addr) => {
1529 if self.hfp_states.get(&addr).is_none()
1530 || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap()
1531 {
1532 warn!("[{}]: Unknown address hfp or slc not ready", DisplayAddress(&addr));
1533 return;
1534 }
1535
1536 let states = self.device_states.lock().unwrap();
1537 info!(
1538 "[{}]: VolumeUpdate state: {:?}",
1539 DisplayAddress(&addr),
1540 states.get(&addr).unwrap()
1541 );
1542 match states.get(&addr).unwrap() {
1543 DeviceConnectionStates::ConnectingBeforeRetry
1544 | DeviceConnectionStates::ConnectingAfterRetry
1545 | DeviceConnectionStates::WaitingConnection => {
1546 self.delay_volume_update.insert(Profile::Hfp, volume);
1547 }
1548 DeviceConnectionStates::FullyConnected => {
1549 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1550 callback.on_hfp_volume_changed(volume, addr);
1551 });
1552 }
1553 _ => {}
1554 }
1555 }
1556 HfpCallbacks::MicVolumeUpdate(volume, addr) => {
1557 if !self.phone_ops_enabled {
1558 return;
1559 }
1560
1561 if self.hfp_states.get(&addr).is_none()
1562 || BthfConnectionState::SlcConnected != *self.hfp_states.get(&addr).unwrap()
1563 {
1564 warn!("[{}]: Unknown address hfp or slc not ready", DisplayAddress(&addr));
1565 return;
1566 }
1567
1568 if let Some(uhid) = self.uhid.get_mut(&addr) {
1569 if volume == 0 && !uhid.muted {
1570 // We expect the application to send back UHID output report and
1571 // update uhid.mute in dispatch_uhid_hfp_output_callback later.
1572 self.uhid_send_phone_mute_input_report(&addr, true);
1573 self.notify_telephony_event(&addr, TelephonyEvent::HFMicMute);
1574 } else if volume > 0 {
1575 uhid.volume = volume;
1576 if uhid.muted {
1577 // We expect the application to send back UHID output report and
1578 // update uhid.mute in dispatch_uhid_hfp_output_callback later.
1579 self.uhid_send_phone_mute_input_report(&addr, false);
1580 self.notify_telephony_event(&addr, TelephonyEvent::HFMicUnmute);
1581 }
1582 }
1583 }
1584 }
1585 HfpCallbacks::VendorSpecificAtCommand(at_string, addr) => {
1586 let at_command = match parse_at_command_data(at_string) {
1587 Ok(command) => command,
1588 Err(e) => {
1589 debug!("{}", e);
1590 return;
1591 }
1592 };
1593 let battery_level = match calculate_battery_percent(at_command.clone()) {
1594 Ok(level) => level,
1595 Err(e) => {
1596 debug!("{}", e);
1597 return;
1598 }
1599 };
1600 let source_info = match at_command.vendor {
1601 Some(vendor) => format!("HFP - {}", vendor),
1602 _ => "HFP - UnknownAtCommand".to_string(),
1603 };
1604 self.battery_provider_manager.lock().unwrap().set_battery_info(
1605 self.battery_provider_id,
1606 BatterySet::new(
1607 addr,
1608 uuid::HFP.to_string(),
1609 source_info,
1610 vec![Battery { percentage: battery_level, variant: "".to_string() }],
1611 ),
1612 );
1613 }
1614 HfpCallbacks::BatteryLevelUpdate(battery_level, addr) => {
1615 let battery_set = BatterySet::new(
1616 addr,
1617 uuid::HFP.to_string(),
1618 "HFP".to_string(),
1619 vec![Battery { percentage: battery_level as u32, variant: "".to_string() }],
1620 );
1621 self.battery_provider_manager
1622 .lock()
1623 .unwrap()
1624 .set_battery_info(self.battery_provider_id, battery_set);
1625 }
1626 HfpCallbacks::WbsCapsUpdate(wbs_supported, addr) => {
1627 let is_transparent_coding_format_supported = match &self.adapter {
1628 Some(adapter) => adapter
1629 .lock()
1630 .unwrap()
1631 .is_coding_format_supported(EscoCodingFormat::TRANSPARENT),
1632 _ => false,
1633 };
1634
1635 let is_msbc_coding_format_supported = match &self.adapter {
1636 Some(adapter) => {
1637 adapter.lock().unwrap().is_coding_format_supported(EscoCodingFormat::MSBC)
1638 }
1639 _ => false,
1640 };
1641
1642 let mut codec_diff = HfpCodecFormat::NONE;
1643 if is_transparent_coding_format_supported {
1644 codec_diff |= HfpCodecFormat::MSBC_TRANSPARENT;
1645 }
1646 if is_msbc_coding_format_supported {
1647 codec_diff |= HfpCodecFormat::MSBC;
1648 }
1649
1650 if let Some(cur_hfp_cap) = self.hfp_cap.get_mut(&addr) {
1651 if wbs_supported {
1652 *cur_hfp_cap |= codec_diff;
1653 } else {
1654 *cur_hfp_cap &= !codec_diff;
1655 }
1656 } else {
1657 let new_hfp_cap = match wbs_supported {
1658 true => HfpCodecFormat::CVSD | codec_diff,
1659 false => HfpCodecFormat::CVSD,
1660 };
1661 self.hfp_cap.insert(addr, new_hfp_cap);
1662 }
1663 }
1664 HfpCallbacks::SwbCapsUpdate(swb_supported, addr) => {
1665 // LC3 can be propagated to this point only if adapter supports transparent mode.
1666 if let Some(cur_hfp_cap) = self.hfp_cap.get_mut(&addr) {
1667 if swb_supported {
1668 *cur_hfp_cap |= HfpCodecFormat::LC3_TRANSPARENT;
1669 } else {
1670 *cur_hfp_cap &= !HfpCodecFormat::LC3_TRANSPARENT;
1671 }
1672 } else {
1673 let new_hfp_cap = match swb_supported {
1674 true => HfpCodecFormat::CVSD | HfpCodecFormat::LC3_TRANSPARENT,
1675 false => HfpCodecFormat::CVSD,
1676 };
1677 self.hfp_cap.insert(addr, new_hfp_cap);
1678 }
1679 }
1680 HfpCallbacks::IndicatorQuery(addr) => {
1681 match self.hfp.as_mut() {
1682 Some(hfp) => {
1683 debug!(
1684 "[{}]: Responding CIND query with device={:?} phone={:?}",
1685 DisplayAddress(&addr),
1686 self.telephony_device_status,
1687 self.phone_state,
1688 );
1689 let status = hfp.indicator_query_response(
1690 self.telephony_device_status,
1691 self.phone_state,
1692 addr,
1693 );
1694 if status != BtStatus::Success {
1695 warn!(
1696 "[{}]: CIND response failed, status={:?}",
1697 DisplayAddress(&addr),
1698 status
1699 );
1700 }
1701 }
1702 None => warn!("Uninitialized HFP to notify telephony status"),
1703 };
1704 }
1705 HfpCallbacks::CurrentCallsQuery(addr) => {
1706 match self.hfp.as_mut() {
1707 Some(hfp) => {
1708 debug!(
1709 "[{}]: Responding CLCC query with call_list={:?}",
1710 DisplayAddress(&addr),
1711 self.call_list,
1712 );
1713 let status = hfp.current_calls_query_response(&self.call_list, addr);
1714 if status != BtStatus::Success {
1715 warn!(
1716 "[{}]: CLCC response failed, status={:?}",
1717 DisplayAddress(&addr),
1718 status
1719 );
1720 }
1721 self.notify_telephony_event(&addr, TelephonyEvent::HFCurrentCallsQuery);
1722 }
1723 None => warn!("Uninitialized HFP to notify telephony status"),
1724 };
1725 }
1726 HfpCallbacks::AnswerCall(addr) => {
1727 if !self.phone_ops_enabled && !self.mps_qualification_enabled {
1728 warn!("Unexpected answer call. phone_ops_enabled and mps_qualification_enabled does not enabled.");
1729 return;
1730 }
1731 if self.mps_qualification_enabled {
1732 // In qualification mode we expect no application to interact with.
1733 // So we just jump right in to the telephony ops implementation.
1734 let id = BLUETOOTH_TELEPHONY_UHID_REPORT_ID;
1735 let mut data = UHID_OUTPUT_NONE;
1736 data |= UHID_OUTPUT_OFF_HOOK;
1737 self.dispatch_uhid_hfp_output_callback(addr, id, data);
1738 } else {
1739 // We expect the application to send back UHID output report and
1740 // trigger dispatch_uhid_hfp_output_callback later.
1741 self.uhid_send_hook_switch_input_report(&addr, true);
1742 self.notify_telephony_event(&addr, TelephonyEvent::HFAnswerCall);
1743 }
1744 }
1745 HfpCallbacks::HangupCall(addr) => {
1746 if !self.phone_ops_enabled && !self.mps_qualification_enabled {
1747 warn!("Unexpected hangup call. phone_ops_enabled and mps_qualification_enabled does not enabled.");
1748 return;
1749 }
1750 if self.mps_qualification_enabled {
1751 // In qualification mode we expect no application to interact with.
1752 // So we just jump right in to the telephony ops implementation.
1753 let id = BLUETOOTH_TELEPHONY_UHID_REPORT_ID;
1754 let mut data = UHID_OUTPUT_NONE;
1755 data &= !UHID_OUTPUT_OFF_HOOK;
1756 self.dispatch_uhid_hfp_output_callback(addr, id, data);
1757 } else {
1758 // We expect the application to send back UHID output report and
1759 // trigger dispatch_uhid_hfp_output_callback later.
1760 self.uhid_send_hook_switch_input_report(&addr, false);
1761 self.notify_telephony_event(&addr, TelephonyEvent::HFHangupCall);
1762 }
1763 }
1764 HfpCallbacks::DialCall(number, addr) => {
1765 if !self.mps_qualification_enabled {
1766 warn!("Unexpected dail call. mps_qualification_enabled does not enabled.");
1767 self.simple_at_response(false, addr);
1768 return;
1769 }
1770 let number = if number == "" {
1771 self.last_dialing_number.clone()
1772 } else if number.starts_with(">") {
1773 self.memory_dialing_number.clone()
1774 } else {
1775 Some(number)
1776 };
1777
1778 if let Some(number) = number {
1779 self.dialing_call_impl(number, Some(addr));
1780 } else {
1781 self.simple_at_response(false, addr);
1782 }
1783 }
1784 HfpCallbacks::CallHold(command, addr) => {
1785 if !self.mps_qualification_enabled {
1786 warn!("Unexpected call hold. mps_qualification_enabled does not enabled.");
1787 self.simple_at_response(false, addr);
1788 return;
1789 }
1790 let success = match command {
1791 CallHoldCommand::ReleaseHeld => self.release_held_impl(Some(addr)),
1792 CallHoldCommand::ReleaseActiveAcceptHeld => {
1793 self.release_active_accept_held_impl(Some(addr))
1794 }
1795 CallHoldCommand::HoldActiveAcceptHeld => {
1796 self.hold_active_accept_held_impl(Some(addr))
1797 }
1798 _ => false, // We only support the 3 operations above.
1799 };
1800 if !success {
1801 warn!(
1802 "[{}]: Unexpected or unsupported CHLD command {:?} from HF",
1803 DisplayAddress(&addr),
1804 command
1805 );
1806 }
1807 }
1808 HfpCallbacks::DebugDump(
1809 active,
1810 codec_id,
1811 total_num_decoded_frames,
1812 pkt_loss_ratio,
1813 begin_ts,
1814 end_ts,
1815 pkt_status_in_hex,
1816 pkt_status_in_binary,
1817 ) => {
1818 let is_wbs = codec_id == HfpCodecId::MSBC as u16;
1819 let is_swb = codec_id == HfpCodecId::LC3 as u16;
1820 debug!("[HFP] DebugDump: active:{}, codec_id:{}", active, codec_id);
1821 if is_wbs || is_swb {
1822 debug!(
1823 "total_num_decoded_frames:{} pkt_loss_ratio:{}",
1824 total_num_decoded_frames, pkt_loss_ratio
1825 );
1826 debug!("begin_ts:{} end_ts:{}", begin_ts, end_ts);
1827 debug!(
1828 "pkt_status_in_hex:{} pkt_status_in_binary:{}",
1829 pkt_status_in_hex, pkt_status_in_binary
1830 );
1831 }
1832 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
1833 callback.on_hfp_debug_dump(
1834 active,
1835 codec_id,
1836 total_num_decoded_frames,
1837 pkt_loss_ratio,
1838 begin_ts,
1839 end_ts,
1840 pkt_status_in_hex.clone(),
1841 pkt_status_in_binary.clone(),
1842 );
1843 });
1844 }
1845 }
1846 }
1847
remove_callback(&mut self, id: u32) -> bool1848 pub fn remove_callback(&mut self, id: u32) -> bool {
1849 self.callbacks.lock().unwrap().remove_callback(id)
1850 }
1851
remove_telephony_callback(&mut self, id: u32) -> bool1852 pub fn remove_telephony_callback(&mut self, id: u32) -> bool {
1853 self.telephony_callbacks.lock().unwrap().remove_callback(id)
1854 }
1855
uhid_create(&mut self, addr: RawAddress)1856 fn uhid_create(&mut self, addr: RawAddress) {
1857 debug!(
1858 "[{}]: UHID create: PhoneOpsEnabled {}",
1859 DisplayAddress(&addr),
1860 self.phone_ops_enabled,
1861 );
1862 // To change the value of phone_ops_enabled, you need to toggle the BluetoothFlossTelephony feature flag on chrome://flags.
1863 if !self.phone_ops_enabled {
1864 return;
1865 }
1866 if self.uhid.contains_key(&addr) {
1867 warn!("[{}]: UHID create: entry already created", DisplayAddress(&addr));
1868 return;
1869 }
1870 let adapter_addr = match &self.adapter {
1871 Some(adapter) => adapter.lock().unwrap().get_address().to_string().to_lowercase(),
1872 _ => "".to_string(),
1873 };
1874 let txl = self.tx.clone();
1875 self.uhid.insert(
1876 addr,
1877 UHid {
1878 handle: UHidHfp::create(
1879 adapter_addr,
1880 addr.to_string(),
1881 self.adapter_get_remote_name(addr),
1882 move |m| {
1883 match m {
1884 OutputEvent::Close => {
1885 txl.blocking_send(Message::UHidTelephonyUseCallback(addr, false))
1886 .unwrap();
1887 }
1888 OutputEvent::Open => {
1889 txl.blocking_send(Message::UHidTelephonyUseCallback(addr, true))
1890 .unwrap();
1891 }
1892 OutputEvent::Output { data } => {
1893 txl.blocking_send(Message::UHidHfpOutputCallback(
1894 addr, data[0], data[1],
1895 ))
1896 .unwrap();
1897 }
1898 _ => (),
1899 };
1900 },
1901 ),
1902 volume: 15, // By default use maximum volume in case microphone gain has not been received
1903 muted: false,
1904 is_open: false,
1905 },
1906 );
1907 self.notify_telephony_event(&addr, TelephonyEvent::UHidCreate);
1908 }
1909
uhid_destroy(&mut self, addr: &RawAddress)1910 fn uhid_destroy(&mut self, addr: &RawAddress) {
1911 if let Some(uhid) = self.uhid.get_mut(addr) {
1912 debug!("[{}]: UHID destroy", DisplayAddress(&addr));
1913 match uhid.handle.destroy() {
1914 Err(e) => log::error!(
1915 "[{}]: UHID destroy: Fail to destroy uhid {}",
1916 DisplayAddress(&addr),
1917 e
1918 ),
1919 Ok(_) => (),
1920 };
1921 self.uhid.remove(addr);
1922 self.notify_telephony_event(&addr, TelephonyEvent::UHidDestroy);
1923 } else {
1924 debug!("[{}]: UHID destroy: not a UHID device", DisplayAddress(&addr));
1925 }
1926 }
1927
uhid_send_input_event_report(&mut self, addr: &RawAddress, data: u8)1928 fn uhid_send_input_event_report(&mut self, addr: &RawAddress, data: u8) {
1929 if !self.phone_ops_enabled {
1930 return;
1931 }
1932 if let Some(uhid) = self.uhid.get_mut(addr) {
1933 info!(
1934 "[{}]: UHID: Send telephony hid input report. hook_switch({}), mute({}), drop({})",
1935 DisplayAddress(&addr),
1936 (data & UHID_INPUT_HOOK_SWITCH) != 0,
1937 (data & UHID_INPUT_PHONE_MUTE) != 0,
1938 (data & UHID_INPUT_DROP) != 0,
1939 );
1940 match uhid.handle.send_input(data) {
1941 Err(e) => log::error!(
1942 "[{}]: UHID: Fail to send hid input report. err:{}",
1943 DisplayAddress(&addr),
1944 e
1945 ),
1946 Ok(_) => (),
1947 };
1948 }
1949 }
1950
uhid_send_hook_switch_input_report(&mut self, addr: &RawAddress, hook: bool)1951 fn uhid_send_hook_switch_input_report(&mut self, addr: &RawAddress, hook: bool) {
1952 if !self.phone_ops_enabled {
1953 return;
1954 }
1955 if let Some(uhid) = self.uhid.get(addr) {
1956 let mut data = UHID_INPUT_NONE;
1957 if hook {
1958 data |= UHID_INPUT_HOOK_SWITCH;
1959 } else if self.phone_state.state == CallState::Incoming {
1960 data |= UHID_INPUT_DROP;
1961 }
1962 // Preserve the muted state when sending the hook switch event.
1963 if uhid.muted {
1964 data |= UHID_INPUT_PHONE_MUTE;
1965 }
1966 self.uhid_send_input_event_report(&addr, data);
1967 };
1968 }
uhid_send_phone_mute_input_report(&mut self, addr: &RawAddress, muted: bool)1969 fn uhid_send_phone_mute_input_report(&mut self, addr: &RawAddress, muted: bool) {
1970 if !self.phone_ops_enabled {
1971 return;
1972 }
1973 if self.uhid.get(addr).is_some() {
1974 let mut data = UHID_INPUT_NONE;
1975 // Preserve the hook switch state when sending the microphone mute event.
1976 let call_active = self.phone_state.num_active > 0;
1977 if call_active {
1978 data |= UHID_INPUT_HOOK_SWITCH;
1979 }
1980 info!(
1981 "[{}]: UHID: Send phone_mute({}) hid input report. hook-switch({})",
1982 DisplayAddress(&addr),
1983 muted,
1984 call_active
1985 );
1986 if muted {
1987 data |= UHID_INPUT_PHONE_MUTE;
1988 self.uhid_send_input_event_report(&addr, data);
1989 } else {
1990 // We follow the same pattern as the USB headset, which sends an
1991 // additional phone mute=1 event when unmuting the microphone.
1992 // Based on our testing, Some applications do not respond to phone
1993 // mute=0 and treat the phone mute=1 event as a toggle rather than
1994 // an on off control.
1995 data |= UHID_INPUT_PHONE_MUTE;
1996 self.uhid_send_input_event_report(&addr, data);
1997 data &= !UHID_INPUT_PHONE_MUTE;
1998 self.uhid_send_input_event_report(&addr, data);
1999 }
2000 };
2001 }
2002
dispatch_uhid_hfp_output_callback(&mut self, addr: RawAddress, id: u8, data: u8)2003 pub fn dispatch_uhid_hfp_output_callback(&mut self, addr: RawAddress, id: u8, data: u8) {
2004 if !self.phone_ops_enabled {
2005 warn!("Unexpected dispatch_uhid_hfp_output_callback uhid output. phone_ops_enabled does not enabled.");
2006 return;
2007 }
2008
2009 debug!(
2010 "[{}]: UHID: Received output report: id {}, data {}",
2011 DisplayAddress(&addr),
2012 id,
2013 data
2014 );
2015
2016 let uhid = match self.uhid.get_mut(&addr) {
2017 Some(uhid) => uhid,
2018 None => {
2019 warn!("[{}]: UHID: No valid UHID", DisplayAddress(&addr));
2020 return;
2021 }
2022 };
2023
2024 if id == BLUETOOTH_TELEPHONY_UHID_REPORT_ID {
2025 let mute = data & UHID_OUTPUT_MUTE;
2026 if mute == UHID_OUTPUT_MUTE && !uhid.muted {
2027 uhid.muted = true;
2028 self.set_hfp_mic_volume(0, addr);
2029 self.notify_telephony_event(&addr, TelephonyEvent::UHidMicMute);
2030 } else if mute != UHID_OUTPUT_MUTE && uhid.muted {
2031 uhid.muted = false;
2032 let saved_volume = uhid.volume;
2033 self.set_hfp_mic_volume(saved_volume, addr);
2034 self.notify_telephony_event(&addr, TelephonyEvent::UHidMicUnmute);
2035 }
2036
2037 let call_state = data & (UHID_OUTPUT_RING | UHID_OUTPUT_OFF_HOOK);
2038 if call_state == UHID_OUTPUT_NONE {
2039 self.hangup_call_impl();
2040 self.notify_telephony_event(&addr, TelephonyEvent::UHidHangupCall);
2041 } else if call_state == UHID_OUTPUT_RING {
2042 self.incoming_call_impl("".into());
2043 self.notify_telephony_event(&addr, TelephonyEvent::UHidIncomingCall);
2044 } else if call_state == UHID_OUTPUT_OFF_HOOK {
2045 if self.phone_state.state == CallState::Incoming {
2046 self.answer_call_impl();
2047 self.notify_telephony_event(&addr, TelephonyEvent::UHidAnswerCall);
2048 } else if self.phone_state.state == CallState::Idle {
2049 self.place_active_call();
2050 self.notify_telephony_event(&addr, TelephonyEvent::UHidPlaceActiveCall);
2051 }
2052 self.uhid_send_hook_switch_input_report(&addr, true);
2053 }
2054 }
2055 }
2056
dispatch_uhid_telephony_use_callback(&mut self, addr: RawAddress, state: bool)2057 pub fn dispatch_uhid_telephony_use_callback(&mut self, addr: RawAddress, state: bool) {
2058 let uhid = match self.uhid.get_mut(&addr) {
2059 Some(uhid) => uhid,
2060 None => {
2061 warn!("[{}]: UHID: No valid UHID", DisplayAddress(&addr));
2062 return;
2063 }
2064 };
2065
2066 uhid.is_open = state;
2067
2068 info!("[{}]: UHID: floss telephony device is open: {}", DisplayAddress(&addr), state);
2069 // A hangup call is necessary both when opening and closing the UHID device,
2070 // although for different reasons:
2071 // - On open: To prevent conflicts with existing SCO calls in CRAS and establish
2072 // a clean environment for Bluetooth Telephony operations.
2073 // - On close: As there's a HID call for each WebHID call, even if it has been
2074 // answered in the app or pre-exists, and that an app which disconnects
2075 // from WebHID may not have trigger the UHID_OUTPUT_NONE, we need to
2076 // remove all pending HID calls on telephony use release to keep lower
2077 // HF layer in sync and not prevent A2DP streaming.
2078 self.hangup_call_impl();
2079
2080 if state {
2081 self.notify_telephony_event(&addr, TelephonyEvent::UHidOpen);
2082 } else {
2083 self.notify_telephony_event(&addr, TelephonyEvent::UHidClose);
2084 }
2085 }
2086
notify_telephony_event(&mut self, addr: &RawAddress, event: TelephonyEvent)2087 fn notify_telephony_event(&mut self, addr: &RawAddress, event: TelephonyEvent) {
2088 // Simplified call status: Assumes at most one call in the list.
2089 // Defaults to Idle if no calls are present.
2090 // Revisit this logic if the system supports multiple concurrent calls in the future (e.g., three-way-call).
2091 let mut call_state = CallState::Idle;
2092 self.call_list.first().map(|c| call_state = c.state);
2093 self.telephony_callbacks.lock().unwrap().for_all_callbacks(|callback| {
2094 callback.on_telephony_event(*addr, u8::from(event), u8::from(call_state));
2095 });
2096 }
2097
set_hfp_mic_volume(&mut self, volume: u8, addr: RawAddress)2098 fn set_hfp_mic_volume(&mut self, volume: u8, addr: RawAddress) {
2099 let vol = match i8::try_from(volume) {
2100 Ok(val) if val <= 15 => val,
2101 _ => {
2102 warn!("[{}]: Ignore invalid mic volume {}", DisplayAddress(&addr), volume);
2103 return;
2104 }
2105 };
2106
2107 if self.hfp_states.get(&addr).is_none() {
2108 warn!(
2109 "[{}]: Ignore mic volume event for unconnected or disconnected HFP device",
2110 DisplayAddress(&addr)
2111 );
2112 return;
2113 }
2114
2115 match self.hfp.as_mut() {
2116 Some(hfp) => {
2117 let status = hfp.set_mic_volume(vol, addr);
2118 if status != BtStatus::Success {
2119 warn!("[{}]: Failed to set mic volume to {}", DisplayAddress(&addr), vol);
2120 }
2121 }
2122 None => warn!("Uninitialized HFP to set mic volume"),
2123 };
2124 }
2125
notify_critical_profile_disconnected(&mut self, addr: RawAddress)2126 fn notify_critical_profile_disconnected(&mut self, addr: RawAddress) {
2127 info!(
2128 "[{}]: Device connection state: {:?}.",
2129 DisplayAddress(&addr),
2130 DeviceConnectionStates::Disconnecting
2131 );
2132
2133 let mut states = self.device_states.lock().unwrap();
2134 let prev_state = states.insert(addr, DeviceConnectionStates::Disconnecting).unwrap();
2135 if prev_state != DeviceConnectionStates::Disconnecting {
2136 let mut guard = self.fallback_tasks.lock().unwrap();
2137 if let Some(task) = guard.get(&addr) {
2138 match task {
2139 // Abort pending task if there is any.
2140 Some((handler, _ts)) => {
2141 warn!(
2142 "[{}]: Device disconnected a critical profile before it was added.",
2143 DisplayAddress(&addr)
2144 );
2145 handler.abort();
2146 guard.insert(addr, None);
2147 }
2148 // Notify device removal if it has been added.
2149 None => {
2150 info!(
2151 "[{}]: Device disconnected a critical profile, removing the device.",
2152 DisplayAddress(&addr)
2153 );
2154 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
2155 callback.on_bluetooth_audio_device_removed(addr);
2156 });
2157 }
2158 };
2159 }
2160 self.delay_volume_update.clear();
2161 }
2162 }
2163
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, )2164 async fn wait_retry(
2165 _fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>,
2166 device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>,
2167 txl: &Sender<Message>,
2168 addr: &RawAddress,
2169 first_conn_ts: Instant,
2170 ) {
2171 let now_ts = Instant::now();
2172 let total_duration = Duration::from_secs(CONNECT_MISSING_PROFILES_TIMEOUT_SEC);
2173 let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts);
2174 sleep(sleep_duration).await;
2175
2176 device_states.lock().unwrap().insert(*addr, DeviceConnectionStates::ConnectingAfterRetry);
2177
2178 info!(
2179 "[{}]: Device connection state: {:?}.",
2180 DisplayAddress(addr),
2181 DeviceConnectionStates::ConnectingAfterRetry
2182 );
2183
2184 let _ = txl.send(Message::Media(MediaActions::Connect(*addr))).await;
2185 }
2186
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, )2187 async fn wait_disconnect(
2188 fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>,
2189 device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>,
2190 txl: &Sender<Message>,
2191 addr: &RawAddress,
2192 first_conn_ts: Instant,
2193 ) {
2194 let now_ts = Instant::now();
2195 let total_duration = Duration::from_secs(PROFILE_DISCOVERY_TIMEOUT_SEC);
2196 let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts);
2197 sleep(sleep_duration).await;
2198
2199 Self::async_disconnect(fallback_tasks, device_states, txl, addr).await;
2200 }
2201
async_disconnect( fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>, device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>, txl: &Sender<Message>, addr: &RawAddress, )2202 async fn async_disconnect(
2203 fallback_tasks: &Arc<Mutex<HashMap<RawAddress, Option<(JoinHandle<()>, Instant)>>>>,
2204 device_states: &Arc<Mutex<HashMap<RawAddress, DeviceConnectionStates>>>,
2205 txl: &Sender<Message>,
2206 addr: &RawAddress,
2207 ) {
2208 device_states.lock().unwrap().insert(*addr, DeviceConnectionStates::Disconnecting);
2209 fallback_tasks.lock().unwrap().insert(*addr, None);
2210
2211 info!(
2212 "[{}]: Device connection state: {:?}.",
2213 DisplayAddress(addr),
2214 DeviceConnectionStates::Disconnecting
2215 );
2216
2217 let _ = txl.send(Message::Media(MediaActions::Disconnect(*addr))).await;
2218 }
2219
wait_force_enter_connected( txl: &Sender<Message>, addr: &RawAddress, first_conn_ts: Instant, )2220 async fn wait_force_enter_connected(
2221 txl: &Sender<Message>,
2222 addr: &RawAddress,
2223 first_conn_ts: Instant,
2224 ) {
2225 let now_ts = Instant::now();
2226 let total_duration = Duration::from_secs(PROFILE_DISCOVERY_TIMEOUT_SEC);
2227 let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts);
2228 sleep(sleep_duration).await;
2229 let _ = txl.send(Message::Media(MediaActions::ForceEnterConnected(*addr))).await;
2230 }
2231
is_bonded(&self, addr: &RawAddress) -> bool2232 fn is_bonded(&self, addr: &RawAddress) -> bool {
2233 match &self.adapter {
2234 Some(adapter) => {
2235 BtBondState::Bonded == adapter.lock().unwrap().get_bond_state_by_addr(&addr)
2236 }
2237 _ => false,
2238 }
2239 }
2240
notify_media_capability_updated(&mut self, addr: RawAddress)2241 fn notify_media_capability_updated(&mut self, addr: RawAddress) {
2242 let mut guard = self.fallback_tasks.lock().unwrap();
2243 let mut states = self.device_states.lock().unwrap();
2244 let mut first_conn_ts = Instant::now();
2245
2246 let is_profile_cleared = self.connected_profiles.get(&addr).unwrap().is_empty();
2247
2248 if let Some(task) = guard.get(&addr) {
2249 if let Some((handler, ts)) = task {
2250 // Abort the pending task. It may be updated or
2251 // removed depending on whether all profiles are cleared.
2252 handler.abort();
2253 first_conn_ts = *ts;
2254 guard.insert(addr, None);
2255 } else {
2256 // The device is already added or is disconnecting.
2257 // Ignore unless all profiles are cleared, where we need to do some clean up.
2258 if !is_profile_cleared {
2259 // Unbonded device is special, we need to reject the connection from them.
2260 if !self.is_bonded(&addr) {
2261 let tasks = self.fallback_tasks.clone();
2262 let states = self.device_states.clone();
2263 let txl = self.tx.clone();
2264 let task = topstack::get_runtime().spawn(async move {
2265 warn!(
2266 "[{}]: Rejecting an unbonded device's attempt to connect media",
2267 DisplayAddress(&addr)
2268 );
2269 BluetoothMedia::async_disconnect(&tasks, &states, &txl, &addr).await;
2270 });
2271 guard.insert(addr, Some((task, first_conn_ts)));
2272 }
2273 return;
2274 }
2275 }
2276 }
2277
2278 // Cleanup if transitioning to empty set.
2279 if is_profile_cleared {
2280 info!("[{}]: Device connection state: Disconnected.", DisplayAddress(&addr));
2281 self.connected_profiles.remove(&addr);
2282 states.remove(&addr);
2283 guard.remove(&addr);
2284 return;
2285 }
2286
2287 let available_profiles = self.adapter_get_classic_audio_profiles(addr);
2288 let connected_profiles = self.connected_profiles.get(&addr).unwrap();
2289 let missing_profiles =
2290 available_profiles.difference(&connected_profiles).cloned().collect::<HashSet<_>>();
2291
2292 // Update device states
2293 if states.get(&addr).is_none() {
2294 states.insert(addr, DeviceConnectionStates::ConnectingBeforeRetry);
2295 }
2296
2297 if states.get(&addr).unwrap() != &DeviceConnectionStates::FullyConnected {
2298 if available_profiles.is_empty() {
2299 // Some headsets may start initiating connections to audio profiles before they are
2300 // exposed to the stack. In this case, wait for either all critical profiles have been
2301 // connected or some timeout to enter the |FullyConnected| state.
2302 if connected_profiles.contains(&Profile::Hfp)
2303 && connected_profiles.contains(&Profile::A2dpSink)
2304 {
2305 info!(
2306 "[{}]: Fully connected, available profiles: {:?}, connected profiles: {:?}.",
2307 DisplayAddress(&addr),
2308 available_profiles,
2309 connected_profiles
2310 );
2311
2312 states.insert(addr, DeviceConnectionStates::FullyConnected);
2313 } else {
2314 warn!(
2315 "[{}]: Connected profiles: {:?}, waiting for peer to initiate remaining connections.",
2316 DisplayAddress(&addr),
2317 connected_profiles
2318 );
2319
2320 states.insert(addr, DeviceConnectionStates::WaitingConnection);
2321 }
2322 } else {
2323 if missing_profiles.is_empty()
2324 || missing_profiles == HashSet::from([Profile::AvrcpController])
2325 {
2326 info!(
2327 "[{}]: Fully connected, available profiles: {:?}, connected profiles: {:?}.",
2328 DisplayAddress(&addr),
2329 available_profiles,
2330 connected_profiles
2331 );
2332
2333 states.insert(addr, DeviceConnectionStates::FullyConnected);
2334 }
2335 }
2336 }
2337
2338 info!(
2339 "[{}]: Device connection state: {:?}.",
2340 DisplayAddress(&addr),
2341 states.get(&addr).unwrap()
2342 );
2343
2344 // React on updated device states
2345 let tasks = self.fallback_tasks.clone();
2346 let device_states = self.device_states.clone();
2347 let txl = self.tx.clone();
2348 let ts = first_conn_ts;
2349 let is_complete_profiles_required = self.is_complete_profiles_required();
2350 match states.get(&addr).unwrap() {
2351 DeviceConnectionStates::Initiating => {
2352 let task = topstack::get_runtime().spawn(async move {
2353 // As initiator we can just immediately start connecting
2354 let _ = txl.send(Message::Media(MediaActions::Connect(addr))).await;
2355 if !is_complete_profiles_required {
2356 BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
2357 return;
2358 }
2359 BluetoothMedia::wait_retry(&tasks, &device_states, &txl, &addr, ts).await;
2360 BluetoothMedia::wait_disconnect(&tasks, &device_states, &txl, &addr, ts).await;
2361 });
2362 guard.insert(addr, Some((task, ts)));
2363 }
2364 DeviceConnectionStates::ConnectingBeforeRetry => {
2365 let task = topstack::get_runtime().spawn(async move {
2366 if !is_complete_profiles_required {
2367 BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
2368 return;
2369 }
2370 BluetoothMedia::wait_retry(&tasks, &device_states, &txl, &addr, ts).await;
2371 BluetoothMedia::wait_disconnect(&tasks, &device_states, &txl, &addr, ts).await;
2372 });
2373 guard.insert(addr, Some((task, ts)));
2374 }
2375 DeviceConnectionStates::ConnectingAfterRetry => {
2376 let task = topstack::get_runtime().spawn(async move {
2377 if !is_complete_profiles_required {
2378 BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
2379 return;
2380 }
2381 BluetoothMedia::wait_disconnect(&tasks, &device_states, &txl, &addr, ts).await;
2382 });
2383 guard.insert(addr, Some((task, ts)));
2384 }
2385 DeviceConnectionStates::FullyConnected => {
2386 // Rejecting the unbonded connection after we finished our profile
2387 // reconnecting logic to avoid a collision.
2388 if !self.is_bonded(&addr) {
2389 warn!(
2390 "[{}]: Rejecting a unbonded device's attempt to connect to media profiles",
2391 DisplayAddress(&addr)
2392 );
2393
2394 let task = topstack::get_runtime().spawn(async move {
2395 BluetoothMedia::async_disconnect(&tasks, &device_states, &txl, &addr).await;
2396 });
2397 guard.insert(addr, Some((task, ts)));
2398 return;
2399 }
2400
2401 let cur_a2dp_caps = self.a2dp_caps.get(&addr);
2402 let cur_hfp_cap = self.hfp_cap.get(&addr);
2403 let name = self.adapter_get_remote_name(addr);
2404 let absolute_volume = self.absolute_volume;
2405 let device = BluetoothAudioDevice::new(
2406 addr,
2407 name.clone(),
2408 cur_a2dp_caps.unwrap_or(&Vec::new()).to_vec(),
2409 *cur_hfp_cap.unwrap_or(&HfpCodecFormat::NONE),
2410 absolute_volume,
2411 );
2412
2413 let hfp_volume = self.delay_volume_update.remove(&Profile::Hfp);
2414 let avrcp_volume = self.delay_volume_update.remove(&Profile::AvrcpController);
2415
2416 self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
2417 callback.on_bluetooth_audio_device_added(device.clone());
2418 if let Some(volume) = hfp_volume {
2419 info!("Trigger HFP volume update to {}", DisplayAddress(&addr));
2420 callback.on_hfp_volume_changed(volume, addr);
2421 }
2422
2423 if let Some(volume) = avrcp_volume {
2424 info!("Trigger avrcp volume update");
2425 callback.on_absolute_volume_changed(volume);
2426 }
2427 });
2428
2429 guard.insert(addr, None);
2430 }
2431 DeviceConnectionStates::Disconnecting => {}
2432 DeviceConnectionStates::WaitingConnection => {
2433 let task = topstack::get_runtime().spawn(async move {
2434 BluetoothMedia::wait_retry(&tasks, &device_states, &txl, &addr, ts).await;
2435 BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
2436 });
2437 guard.insert(addr, Some((task, ts)));
2438 }
2439 }
2440 }
2441
adapter_get_remote_name(&self, addr: RawAddress) -> String2442 fn adapter_get_remote_name(&self, addr: RawAddress) -> String {
2443 let device = BluetoothDevice::new(
2444 addr,
2445 // get_remote_name needs a BluetoothDevice just for its address, the
2446 // name field is unused so construct one with a fake name.
2447 "Classic Device".to_string(),
2448 );
2449 if let Some(adapter) = &self.adapter {
2450 match adapter.lock().unwrap().get_remote_name(device).as_str() {
2451 "" => addr.to_string(),
2452 name => name.into(),
2453 }
2454 } else {
2455 addr.to_string()
2456 }
2457 }
2458
adapter_get_le_audio_profiles(&self, addr: RawAddress) -> HashSet<Profile>2459 fn adapter_get_le_audio_profiles(&self, addr: RawAddress) -> HashSet<Profile> {
2460 let device = BluetoothDevice::new(addr, "".to_string());
2461 if let Some(adapter) = &self.adapter {
2462 adapter
2463 .lock()
2464 .unwrap()
2465 .get_remote_uuids(device)
2466 .into_iter()
2467 .filter_map(|u| UuidHelper::is_known_profile(&u))
2468 .filter(|u| MEDIA_LE_AUDIO_PROFILES.contains(&u))
2469 .collect()
2470 } else {
2471 HashSet::new()
2472 }
2473 }
2474
adapter_get_classic_audio_profiles(&self, addr: RawAddress) -> HashSet<Profile>2475 fn adapter_get_classic_audio_profiles(&self, addr: RawAddress) -> HashSet<Profile> {
2476 let device = BluetoothDevice::new(addr, "".to_string());
2477 if let Some(adapter) = &self.adapter {
2478 adapter
2479 .lock()
2480 .unwrap()
2481 .get_remote_uuids(device)
2482 .into_iter()
2483 .filter_map(|u| UuidHelper::is_known_profile(&u))
2484 .filter(|u| MEDIA_CLASSIC_AUDIO_PROFILES.contains(&u))
2485 .collect()
2486 } else {
2487 HashSet::new()
2488 }
2489 }
2490
get_hfp_connection_state(&self) -> ProfileConnectionState2491 pub fn get_hfp_connection_state(&self) -> ProfileConnectionState {
2492 if self.hfp_audio_state.values().any(|state| *state == BthfAudioState::Connected) {
2493 ProfileConnectionState::Active
2494 } else {
2495 let mut winning_state = ProfileConnectionState::Disconnected;
2496 for state in self.hfp_states.values() {
2497 // Grab any state higher than the current state.
2498 match state {
2499 // Any SLC completed state means the profile is connected.
2500 BthfConnectionState::SlcConnected => {
2501 winning_state = ProfileConnectionState::Connected;
2502 }
2503
2504 // Connecting or Connected are both counted as connecting for profile state
2505 // since it's not a complete connection.
2506 BthfConnectionState::Connecting | BthfConnectionState::Connected
2507 if winning_state != ProfileConnectionState::Connected =>
2508 {
2509 winning_state = ProfileConnectionState::Connecting;
2510 }
2511
2512 BthfConnectionState::Disconnecting
2513 if winning_state == ProfileConnectionState::Disconnected =>
2514 {
2515 winning_state = ProfileConnectionState::Disconnecting;
2516 }
2517
2518 _ => (),
2519 }
2520 }
2521
2522 winning_state
2523 }
2524 }
2525
get_a2dp_connection_state(&self) -> ProfileConnectionState2526 pub fn get_a2dp_connection_state(&self) -> ProfileConnectionState {
2527 if self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
2528 ProfileConnectionState::Active
2529 } else {
2530 let mut winning_state = ProfileConnectionState::Disconnected;
2531 for state in self.a2dp_states.values() {
2532 // Grab any state higher than the current state.
2533 match state {
2534 BtavConnectionState::Connected => {
2535 winning_state = ProfileConnectionState::Connected;
2536 }
2537
2538 BtavConnectionState::Connecting
2539 if winning_state != ProfileConnectionState::Connected =>
2540 {
2541 winning_state = ProfileConnectionState::Connecting;
2542 }
2543
2544 BtavConnectionState::Disconnecting
2545 if winning_state == ProfileConnectionState::Disconnected =>
2546 {
2547 winning_state = ProfileConnectionState::Disconnecting;
2548 }
2549
2550 _ => (),
2551 }
2552 }
2553
2554 winning_state
2555 }
2556 }
2557
filter_to_connected_audio_devices_from( &self, devices: &Vec<BluetoothDevice>, ) -> Vec<BluetoothDevice>2558 pub fn filter_to_connected_audio_devices_from(
2559 &self,
2560 devices: &Vec<BluetoothDevice>,
2561 ) -> Vec<BluetoothDevice> {
2562 devices
2563 .iter()
2564 .filter(|d| {
2565 self.is_any_profile_connected(&d.address, &MEDIA_CLASSIC_AUDIO_PROFILES)
2566 || self.is_any_profile_connected(&d.address, &MEDIA_LE_AUDIO_PROFILES)
2567 })
2568 .cloned()
2569 .collect()
2570 }
2571
start_audio_request_impl(&mut self) -> bool2572 fn start_audio_request_impl(&mut self) -> bool {
2573 debug!("Start audio request");
2574
2575 match self.a2dp.as_mut() {
2576 Some(a2dp) => a2dp.start_audio_request(),
2577 None => {
2578 warn!("Uninitialized A2DP to start audio request");
2579 false
2580 }
2581 }
2582 }
2583
suspend_audio_request_impl(&mut self)2584 fn suspend_audio_request_impl(&mut self) {
2585 match self.a2dp.as_mut() {
2586 Some(a2dp) => a2dp.suspend_audio_request(),
2587 None => warn!("Uninitialized A2DP to suspend audio request"),
2588 };
2589 }
2590
try_a2dp_resume(&mut self)2591 fn try_a2dp_resume(&mut self) {
2592 // Try resume the A2DP stream (per MPS v1.0) on rejecting an incoming call or an
2593 // outgoing call is rejected.
2594 // It may fail if a SCO connection is still active (terminate call case), in that
2595 // case we will retry on SCO disconnected.
2596 if !self.mps_qualification_enabled {
2597 return;
2598 }
2599 // Make sure there is no any SCO connection and then resume the A2DP stream.
2600 if self.a2dp_has_interrupted_stream
2601 && !self.hfp_audio_state.values().any(|state| *state == BthfAudioState::Connected)
2602 {
2603 self.a2dp_has_interrupted_stream = false;
2604 self.start_audio_request_impl();
2605 }
2606 }
2607
try_a2dp_suspend(&mut self)2608 fn try_a2dp_suspend(&mut self) {
2609 // Try suspend the A2DP stream (per MPS v1.0) when receiving an incoming call
2610 if !self.mps_qualification_enabled {
2611 return;
2612 }
2613 // Suspend the A2DP stream if there is any.
2614 if self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
2615 self.a2dp_has_interrupted_stream = true;
2616 self.suspend_audio_request_impl();
2617 }
2618 }
2619
start_sco_call_impl( &mut self, addr: RawAddress, sco_offload: bool, disabled_codecs: HfpCodecBitId, ) -> bool2620 fn start_sco_call_impl(
2621 &mut self,
2622 addr: RawAddress,
2623 sco_offload: bool,
2624 disabled_codecs: HfpCodecBitId,
2625 ) -> bool {
2626 match (|| -> Result<(), &str> {
2627 info!("Start sco call for {}", DisplayAddress(&addr));
2628
2629 let hfp = self.hfp.as_mut().ok_or("Uninitialized HFP to start the sco call")?;
2630 let disabled_codecs = disabled_codecs.try_into().expect("Can't parse disabled_codecs");
2631 if hfp.connect_audio(addr, sco_offload, disabled_codecs) != 0 {
2632 return Err("SCO connect_audio status failed");
2633 }
2634 info!("SCO connect_audio status success");
2635 Ok(())
2636 })() {
2637 Ok(_) => true,
2638 Err(msg) => {
2639 warn!("{}", msg);
2640 false
2641 }
2642 }
2643 }
2644
stop_sco_call_impl(&mut self, addr: RawAddress)2645 fn stop_sco_call_impl(&mut self, addr: RawAddress) {
2646 info!("Stop sco call for {}", DisplayAddress(&addr));
2647 if let Some(hfp) = self.hfp.as_mut() {
2648 hfp.disconnect_audio(addr);
2649 } else {
2650 warn!("Uninitialized HFP to stop the sco call");
2651 }
2652 }
2653
device_status_notification(&mut self)2654 fn device_status_notification(&mut self) {
2655 match self.hfp.as_mut() {
2656 Some(hfp) => {
2657 for (addr, state) in self.hfp_states.iter() {
2658 if *state != BthfConnectionState::SlcConnected {
2659 continue;
2660 }
2661 debug!(
2662 "[{}]: Device status notification {:?}",
2663 DisplayAddress(addr),
2664 self.telephony_device_status
2665 );
2666 let status =
2667 hfp.device_status_notification(self.telephony_device_status, *addr);
2668 if status != BtStatus::Success {
2669 warn!(
2670 "[{}]: Device status notification failed, status={:?}",
2671 DisplayAddress(addr),
2672 status
2673 );
2674 }
2675 }
2676 }
2677 None => warn!("Uninitialized HFP to notify telephony status"),
2678 }
2679 }
2680
phone_state_change(&mut self, number: String)2681 fn phone_state_change(&mut self, number: String) {
2682 match self.hfp.as_mut() {
2683 Some(hfp) => {
2684 for (addr, state) in self.hfp_states.iter() {
2685 if *state != BthfConnectionState::SlcConnected {
2686 continue;
2687 }
2688 debug!(
2689 "[{}]: Phone state change state={:?} number={}",
2690 DisplayAddress(addr),
2691 self.phone_state,
2692 number
2693 );
2694 let status = hfp.phone_state_change(self.phone_state, &number, *addr);
2695 if status != BtStatus::Success {
2696 warn!(
2697 "[{}]: Device status notification failed, status={:?}",
2698 DisplayAddress(addr),
2699 status
2700 );
2701 }
2702 }
2703 }
2704 None => warn!("Uninitialized HFP to notify telephony status"),
2705 }
2706 }
2707
2708 // Returns the minimum unoccupied index starting from 1.
new_call_index(&self) -> i322709 fn new_call_index(&self) -> i32 {
2710 (1..)
2711 .find(|&index| self.call_list.iter().all(|x| x.index != index))
2712 .expect("There must be an unoccupied index")
2713 }
2714
simple_at_response(&mut self, ok: bool, addr: RawAddress)2715 fn simple_at_response(&mut self, ok: bool, addr: RawAddress) {
2716 match self.hfp.as_mut() {
2717 Some(hfp) => {
2718 let status = hfp.simple_at_response(ok, addr);
2719 if status != BtStatus::Success {
2720 warn!("[{}]: AT response failed, status={:?}", DisplayAddress(&addr), status);
2721 }
2722 }
2723 None => warn!("Uninitialized HFP to send AT response"),
2724 }
2725 }
2726
incoming_call_impl(&mut self, number: String) -> bool2727 fn incoming_call_impl(&mut self, number: String) -> bool {
2728 if self.phone_state.state != CallState::Idle {
2729 return false;
2730 }
2731
2732 if self.phone_state.num_active > 0 {
2733 return false;
2734 }
2735
2736 self.call_list.push(CallInfo {
2737 index: self.new_call_index(),
2738 dir_incoming: true,
2739 state: CallState::Incoming,
2740 number: number.clone(),
2741 });
2742 self.phone_state.state = CallState::Incoming;
2743 self.phone_state_change(number);
2744 self.try_a2dp_suspend();
2745 true
2746 }
2747
answer_call_impl(&mut self) -> bool2748 fn answer_call_impl(&mut self) -> bool {
2749 if self.phone_state.state == CallState::Idle {
2750 return false;
2751 }
2752 // There must be exactly one incoming/dialing call in the list.
2753 for c in self.call_list.iter_mut() {
2754 match c.state {
2755 CallState::Incoming | CallState::Dialing | CallState::Alerting => {
2756 c.state = CallState::Active;
2757 break;
2758 }
2759 _ => {}
2760 }
2761 }
2762 self.phone_state.state = CallState::Idle;
2763 self.phone_state.num_active += 1;
2764
2765 self.phone_state_change("".into());
2766
2767 if self.mps_qualification_enabled {
2768 // Find a connected HFP and try to establish an SCO.
2769 if let Some(addr) = self.hfp_states.iter().find_map(|(addr, state)| {
2770 if *state == BthfConnectionState::SlcConnected {
2771 Some(addr)
2772 } else {
2773 None
2774 }
2775 }) {
2776 info!("Start SCO call due to call answered");
2777 self.start_sco_call_impl(*addr, false, HfpCodecBitId::NONE);
2778 }
2779 }
2780
2781 true
2782 }
2783
hangup_call_impl(&mut self) -> bool2784 fn hangup_call_impl(&mut self) -> bool {
2785 if !self.phone_ops_enabled && !self.mps_qualification_enabled {
2786 return false;
2787 }
2788
2789 match self.phone_state.state {
2790 CallState::Idle if self.phone_state.num_active > 0 => {
2791 self.phone_state.num_active -= 1;
2792 }
2793 CallState::Incoming | CallState::Dialing | CallState::Alerting => {
2794 self.phone_state.state = CallState::Idle;
2795 }
2796 _ => return false,
2797 }
2798 // At this point, there must be exactly one incoming/dialing/alerting/active call to be
2799 // removed.
2800 self.call_list.retain(|x| match x.state {
2801 CallState::Active | CallState::Incoming | CallState::Dialing | CallState::Alerting => {
2802 false
2803 }
2804 _ => true,
2805 });
2806
2807 self.phone_state_change("".into());
2808 self.try_a2dp_resume();
2809
2810 true
2811 }
2812
dialing_call_impl(&mut self, number: String, addr: Option<RawAddress>) -> bool2813 fn dialing_call_impl(&mut self, number: String, addr: Option<RawAddress>) -> bool {
2814 if self.phone_state.num_active > 0 || self.phone_state.state != CallState::Idle {
2815 if let Some(addr) = addr {
2816 self.simple_at_response(false, addr);
2817 warn!("[{}]: Unexpected dialing command from HF", DisplayAddress(&addr));
2818 }
2819 return false;
2820 }
2821
2822 self.call_list.push(CallInfo {
2823 index: self.new_call_index(),
2824 dir_incoming: false,
2825 state: CallState::Dialing,
2826 number: number.clone(),
2827 });
2828 self.phone_state.state = CallState::Dialing;
2829
2830 if let Some(addr) = addr {
2831 self.simple_at_response(true, addr);
2832 warn!("[{}]: Unexpected dialing command from HF", DisplayAddress(&addr));
2833 }
2834
2835 // Inform libbluetooth that the state has changed to dialing.
2836 self.phone_state_change("".into());
2837 self.try_a2dp_suspend();
2838 // Change to alerting state and inform libbluetooth.
2839 self.dialing_to_alerting();
2840 true
2841 }
2842
dialing_to_alerting(&mut self) -> bool2843 fn dialing_to_alerting(&mut self) -> bool {
2844 if !(self.phone_ops_enabled || self.mps_qualification_enabled)
2845 || self.phone_state.state != CallState::Dialing
2846 {
2847 return false;
2848 }
2849 for c in self.call_list.iter_mut() {
2850 if c.state == CallState::Dialing {
2851 c.state = CallState::Alerting;
2852 break;
2853 }
2854 }
2855 self.phone_state.state = CallState::Alerting;
2856 self.phone_state_change("".into());
2857 true
2858 }
2859
release_held_impl(&mut self, addr: Option<RawAddress>) -> bool2860 fn release_held_impl(&mut self, addr: Option<RawAddress>) -> bool {
2861 if self.phone_state.state != CallState::Idle {
2862 if let Some(addr) = addr {
2863 // Respond ERROR to the HF which sent the command.
2864 self.simple_at_response(false, addr);
2865 }
2866 return false;
2867 }
2868 self.call_list.retain(|x| x.state != CallState::Held);
2869 self.phone_state.num_held = 0;
2870
2871 if let Some(addr) = addr {
2872 // This should be called before calling phone_state_change.
2873 self.simple_at_response(true, addr);
2874 }
2875 // Success means the call state has changed. Inform libbluetooth.
2876 self.phone_state_change("".into());
2877 true
2878 }
2879
release_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool2880 fn release_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool {
2881 self.call_list.retain(|x| x.state != CallState::Active);
2882 self.phone_state.num_active = 0;
2883 // Activate the first held call
2884 if self.phone_state.state != CallState::Idle {
2885 if let Some(addr) = addr {
2886 // Respond ERROR to the HF which sent the command.
2887 self.simple_at_response(false, addr);
2888 }
2889 return false;
2890 }
2891 for c in self.call_list.iter_mut() {
2892 if c.state == CallState::Held {
2893 c.state = CallState::Active;
2894 self.phone_state.num_held -= 1;
2895 self.phone_state.num_active += 1;
2896 break;
2897 }
2898 }
2899 if let Some(addr) = addr {
2900 // This should be called before calling phone_state_change.
2901 self.simple_at_response(true, addr);
2902 }
2903 // Success means the call state has changed. Inform libbluetooth.
2904 self.phone_state_change("".into());
2905 true
2906 }
2907
hold_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool2908 fn hold_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool {
2909 if self.phone_state.state != CallState::Idle {
2910 if let Some(addr) = addr {
2911 // Respond ERROR to the HF which sent the command.
2912 self.simple_at_response(false, addr);
2913 }
2914 return false;
2915 }
2916 self.phone_state.num_held += self.phone_state.num_active;
2917 self.phone_state.num_active = 0;
2918
2919 for c in self.call_list.iter_mut() {
2920 match c.state {
2921 // Activate at most one held call
2922 CallState::Held if self.phone_state.num_active == 0 => {
2923 c.state = CallState::Active;
2924 self.phone_state.num_held -= 1;
2925 self.phone_state.num_active = 1;
2926 }
2927 CallState::Active => {
2928 c.state = CallState::Held;
2929 }
2930 _ => {}
2931 }
2932 }
2933 if let Some(addr) = addr {
2934 // This should be called before calling phone_state_change.
2935 self.simple_at_response(true, addr);
2936 }
2937 // Success means the call state has changed. Inform libbluetooth.
2938 self.phone_state_change("".into());
2939 true
2940 }
2941
2942 // Per MPS v1.0 (Multi-Profile Specification), disconnecting or failing to connect
2943 // a profile should not affect the others.
2944 // Allow partial profiles connection during qualification (MPS qualification mode is enabled).
is_complete_profiles_required(&self) -> bool2945 fn is_complete_profiles_required(&self) -> bool {
2946 !self.mps_qualification_enabled
2947 }
2948
2949 // Force the media enters the FullyConnected state and then triggers a retry.
2950 // When this function is used for qualification as a replacement of normal retry,
2951 // PTS could initiate the connection of the necessary profiles, and Floss should
2952 // notify CRAS of the new audio device regardless of the unconnected profiles.
2953 // Still retry in the end because some test cases require that.
force_enter_connected(&mut self, addr: RawAddress)2954 fn force_enter_connected(&mut self, addr: RawAddress) {
2955 self.device_states.lock().unwrap().insert(addr, DeviceConnectionStates::FullyConnected);
2956 self.notify_media_capability_updated(addr);
2957 self.connect(addr);
2958 }
add_player(&mut self, name: String, browsing_supported: bool)2959 pub fn add_player(&mut self, name: String, browsing_supported: bool) {
2960 self.avrcp.as_mut().unwrap().add_player(&name, browsing_supported);
2961 }
2962
2963 // This function determines if it's safe to send a +CIEV command to an HFP device when SCO starts.
2964
2965 // The +CIEV command should NOT be sent if:
2966 // - MPS qualification mode is enabled, as it may cause qualification failures.
2967 // - Uhid device is open, as it may conflict with ongoing telephony operations.
2968
2969 // The +CIEV command is safe to send if:
2970 // - Both MPS qualification and Bluetooth telephony are disabled.
2971 // - Uhid device is closed, preventing any telephony conflicts.
2972 // - The headset is listed in interop_database.conf, indicating it requires +CIEV for audio.
should_insert_call_when_sco_start(&self, address: RawAddress) -> bool2973 fn should_insert_call_when_sco_start(&self, address: RawAddress) -> bool {
2974 if self.mps_qualification_enabled {
2975 return false;
2976 }
2977 if !self.phone_ops_enabled {
2978 return true;
2979 }
2980
2981 match self.uhid.get(&address) {
2982 Some(uhid) => {
2983 if !uhid.is_open {
2984 return true;
2985 }
2986 }
2987 None => {
2988 return true;
2989 }
2990 };
2991
2992 return interop_insert_call_when_sco_start(address);
2993 }
2994 // Places an active call into the call list and triggers a headset update (+CIEV).
2995 // Preconditions:
2996 // - No active calls in progress (phone_state.num_active == 0)
2997 // - Phone state is idle (phone_state.state == CallState::Idle)
place_active_call(&mut self)2998 fn place_active_call(&mut self) {
2999 if self.phone_state.num_active != 0 {
3000 warn!("Unexpected usage. phone_state.num_active can only be 0 when calling place_active_call");
3001 return;
3002 }
3003
3004 if self.phone_state.state != CallState::Idle {
3005 warn!("Unexpected usage. phone_state.state can only be idle when calling place_active_call");
3006 return;
3007 }
3008
3009 self.call_list.push(CallInfo {
3010 index: 1,
3011 dir_incoming: false,
3012 state: CallState::Active,
3013 number: "".into(),
3014 });
3015 self.phone_state.num_active = 1;
3016 self.phone_state_change("".into());
3017 }
3018
get_group_devices(&self, group_id: i32) -> HashSet<RawAddress>3019 pub fn get_group_devices(&self, group_id: i32) -> HashSet<RawAddress> {
3020 match self.le_audio_groups.get(&group_id) {
3021 Some(g) => g.devices.clone(),
3022 _ => HashSet::new(),
3023 }
3024 }
3025
get_group_id(&self, addr: RawAddress) -> i323026 pub fn get_group_id(&self, addr: RawAddress) -> i32 {
3027 *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID)
3028 }
3029 }
3030
get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher3031 fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher {
3032 A2dpCallbacksDispatcher {
3033 dispatch: Box::new(move |cb| {
3034 let txl = tx.clone();
3035 topstack::get_runtime().spawn(async move {
3036 let _ = txl.send(Message::A2dp(cb)).await;
3037 });
3038 }),
3039 }
3040 }
3041
get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher3042 fn get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher {
3043 AvrcpCallbacksDispatcher {
3044 dispatch: Box::new(move |cb| {
3045 let txl = tx.clone();
3046 topstack::get_runtime().spawn(async move {
3047 let _ = txl.send(Message::Avrcp(cb)).await;
3048 });
3049 }),
3050 }
3051 }
3052
get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher3053 fn get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher {
3054 HfpCallbacksDispatcher {
3055 dispatch: Box::new(move |cb| {
3056 let txl = tx.clone();
3057 topstack::get_runtime().spawn(async move {
3058 let _ = txl.send(Message::Hfp(cb)).await;
3059 });
3060 }),
3061 }
3062 }
3063
get_le_audio_dispatcher(tx: Sender<Message>) -> LeAudioClientCallbacksDispatcher3064 fn get_le_audio_dispatcher(tx: Sender<Message>) -> LeAudioClientCallbacksDispatcher {
3065 LeAudioClientCallbacksDispatcher {
3066 dispatch: Box::new(move |cb| {
3067 let txl = tx.clone();
3068 topstack::get_runtime().spawn(async move {
3069 let _ = txl.send(Message::LeAudioClient(cb)).await;
3070 });
3071 }),
3072 }
3073 }
3074
get_vc_dispatcher(tx: Sender<Message>) -> VolumeControlCallbacksDispatcher3075 fn get_vc_dispatcher(tx: Sender<Message>) -> VolumeControlCallbacksDispatcher {
3076 VolumeControlCallbacksDispatcher {
3077 dispatch: Box::new(move |cb| {
3078 let txl = tx.clone();
3079 topstack::get_runtime().spawn(async move {
3080 let _ = txl.send(Message::VolumeControl(cb)).await;
3081 });
3082 }),
3083 }
3084 }
3085
get_csis_dispatcher(tx: Sender<Message>) -> CsisClientCallbacksDispatcher3086 fn get_csis_dispatcher(tx: Sender<Message>) -> CsisClientCallbacksDispatcher {
3087 CsisClientCallbacksDispatcher {
3088 dispatch: Box::new(move |cb| {
3089 let txl = tx.clone();
3090 topstack::get_runtime().spawn(async move {
3091 let _ = txl.send(Message::CsisClient(cb)).await;
3092 });
3093 }),
3094 }
3095 }
3096
3097 impl IBluetoothMedia for BluetoothMedia {
register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool3098 fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool {
3099 let _id = self.callbacks.lock().unwrap().add_callback(callback);
3100 true
3101 }
3102
initialize(&mut self) -> bool3103 fn initialize(&mut self) -> bool {
3104 if self.initialized {
3105 return false;
3106 }
3107 self.initialized = true;
3108
3109 self.is_le_audio_only_enabled =
3110 features::is_feature_enabled("CrOSLateBootBluetoothAudioLEAudioOnly").unwrap_or(false);
3111
3112 // A2DP
3113 let a2dp_dispatcher = get_a2dp_dispatcher(self.tx.clone());
3114 self.a2dp = Some(A2dp::new(&self.intf.lock().unwrap()));
3115 self.a2dp.as_mut().unwrap().initialize(a2dp_dispatcher);
3116
3117 // AVRCP
3118 let avrcp_dispatcher = get_avrcp_dispatcher(self.tx.clone());
3119 self.avrcp = Some(Avrcp::new(&self.intf.lock().unwrap()));
3120 self.avrcp.as_mut().unwrap().initialize(avrcp_dispatcher);
3121
3122 // HFP
3123 let hfp_dispatcher = get_hfp_dispatcher(self.tx.clone());
3124 self.hfp = Some(Hfp::new(&self.intf.lock().unwrap()));
3125 self.hfp.as_mut().unwrap().initialize(hfp_dispatcher);
3126
3127 // LEA
3128 let le_audio_dispatcher = get_le_audio_dispatcher(self.tx.clone());
3129 self.le_audio = Some(LeAudioClient::new(&self.intf.lock().unwrap()));
3130 self.le_audio.as_mut().unwrap().initialize(le_audio_dispatcher);
3131
3132 // VC
3133 let vc_dispatcher = get_vc_dispatcher(self.tx.clone());
3134 self.vc = Some(VolumeControl::new(&self.intf.lock().unwrap()));
3135 self.vc.as_mut().unwrap().initialize(vc_dispatcher);
3136
3137 // CSIS
3138 let csis_dispatcher = get_csis_dispatcher(self.tx.clone());
3139 self.csis = Some(CsisClient::new(&self.intf.lock().unwrap()));
3140 self.csis.as_mut().unwrap().initialize(csis_dispatcher);
3141
3142 // TODO(b/284811956) A2DP needs to be enabled before AVRCP otherwise AVRCP gets memset'd.
3143 // Iterate the delay_enable_profiles hashmap directly when this is fixed.
3144 let profile_order = vec![
3145 Profile::A2dpSource,
3146 Profile::AvrcpTarget,
3147 Profile::Hfp,
3148 Profile::LeAudio,
3149 Profile::VolumeControl,
3150 Profile::CoordinatedSet,
3151 ];
3152 for profile in profile_order {
3153 if self.delay_enable_profiles.contains(&profile) {
3154 self.enable_profile(&profile);
3155 }
3156 }
3157 true
3158 }
3159
connect_lea_group_by_member_address(&mut self, addr: RawAddress)3160 fn connect_lea_group_by_member_address(&mut self, addr: RawAddress) {
3161 // Note that at this point the scanning of profiles may be incomplete,
3162 // TODO(b/335780769): connect to available profiles and ensure
3163 // this function is invoked whenever there is an incremental
3164 // discovery of LE audio profiles.
3165 for profile in MEDIA_LE_AUDIO_PROFILES {
3166 match profile {
3167 Profile::LeAudio => {
3168 self.connect_lea(addr);
3169 }
3170 Profile::VolumeControl => {
3171 self.connect_vc(addr);
3172 }
3173 Profile::CoordinatedSet => {
3174 self.connect_csis(addr);
3175 }
3176 _ => {}
3177 }
3178 }
3179 }
3180
disconnect_lea_group_by_member_address(&mut self, addr: RawAddress)3181 fn disconnect_lea_group_by_member_address(&mut self, addr: RawAddress) {
3182 let group_id = self.get_group_id(addr);
3183 if group_id == LEA_UNKNOWN_GROUP_ID {
3184 warn!(
3185 "disconnect_lea_group_by_member_address: [{}]: address belongs to no group",
3186 DisplayAddress(&addr)
3187 );
3188 return;
3189 }
3190
3191 let group = self.le_audio_groups.entry(group_id).or_default().clone();
3192
3193 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3194
3195 info!(
3196 "disconnect_lea_group_by_member_address: [{}]: available profiles: {:?}.",
3197 DisplayAddress(&addr),
3198 available_profiles
3199 );
3200
3201 for &member_addr in group.devices.iter() {
3202 for profile in self.adapter_get_le_audio_profiles(addr) {
3203 match profile {
3204 Profile::LeAudio => {
3205 self.disconnect_lea(member_addr);
3206 }
3207 Profile::VolumeControl => {
3208 self.disconnect_vc(member_addr);
3209 }
3210 Profile::CoordinatedSet => {
3211 self.disconnect_csis(member_addr);
3212 }
3213 _ => {}
3214 }
3215 }
3216 }
3217 }
3218
connect_lea(&mut self, addr: RawAddress)3219 fn connect_lea(&mut self, addr: RawAddress) {
3220 if !self.is_le_audio_only_enabled {
3221 warn!("connect_lea: LeAudioEnableLeAudioOnly is not set");
3222 return;
3223 }
3224
3225 if *self.le_audio_states.get(&addr).unwrap_or(&BtLeAudioConnectionState::Disconnected)
3226 == BtLeAudioConnectionState::Connected
3227 {
3228 info!("connect_lea: already connected.");
3229 return;
3230 }
3231
3232 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3233
3234 info!(
3235 "connect_lea: [{}]: connecting, available profiles: {:?}.",
3236 DisplayAddress(&addr),
3237 available_profiles
3238 );
3239
3240 match self.le_audio.as_mut() {
3241 Some(le_audio) => {
3242 le_audio.set_enable_state(addr, true);
3243 le_audio.connect(addr);
3244 }
3245 None => {
3246 warn!("connect_lea: [{}]: uninitialized LeAudio to connect", DisplayAddress(&addr));
3247 }
3248 };
3249 }
3250
disconnect_lea(&mut self, addr: RawAddress)3251 fn disconnect_lea(&mut self, addr: RawAddress) {
3252 if *self.le_audio_states.get(&addr).unwrap_or(&BtLeAudioConnectionState::Disconnected)
3253 == BtLeAudioConnectionState::Disconnected
3254 {
3255 info!("disconnect_lea: [{}]: already disconnected", DisplayAddress(&addr));
3256 return;
3257 }
3258
3259 info!("disconnect_lea: [{}]: disconnecting", DisplayAddress(&addr));
3260
3261 match self.le_audio.as_mut() {
3262 Some(le_audio) => {
3263 le_audio.set_enable_state(addr, false);
3264 le_audio.disconnect(addr);
3265 }
3266 None => {
3267 warn!(
3268 "disconnect_lea: [{}]: uninitialized LeAudio to disconnect",
3269 DisplayAddress(&addr)
3270 );
3271 }
3272 };
3273 }
3274
connect_vc(&mut self, addr: RawAddress)3275 fn connect_vc(&mut self, addr: RawAddress) {
3276 if !self.is_le_audio_only_enabled {
3277 warn!("connect_vc: LeAudioEnableLeAudioOnly is not set");
3278 return;
3279 }
3280
3281 if *self.vc_states.get(&addr).unwrap_or(&BtVcConnectionState::Disconnected)
3282 == BtVcConnectionState::Connected
3283 {
3284 info!("connect_vc: already connected");
3285 return;
3286 }
3287
3288 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3289
3290 info!(
3291 "connect_vc: [{}]: connecting, available profiles: {:?}.",
3292 DisplayAddress(&addr),
3293 available_profiles
3294 );
3295
3296 match self.vc.as_mut() {
3297 Some(vc) => {
3298 vc.connect(addr);
3299 }
3300 None => {
3301 warn!("connect_vc: [{}]: uninitialized VC to connect", DisplayAddress(&addr));
3302 }
3303 };
3304 }
3305
disconnect_vc(&mut self, addr: RawAddress)3306 fn disconnect_vc(&mut self, addr: RawAddress) {
3307 if *self.vc_states.get(&addr).unwrap_or(&BtVcConnectionState::Disconnected)
3308 == BtVcConnectionState::Disconnected
3309 {
3310 info!("disconnect_vc: already disconnected");
3311 return;
3312 }
3313
3314 info!("disconnect_vc: [{}]: disconnecting", DisplayAddress(&addr));
3315
3316 match self.vc.as_mut() {
3317 Some(vc) => {
3318 vc.disconnect(addr);
3319 }
3320 None => {
3321 warn!("disconnect_vc: [{}]: uninitialized VC to disconnect", DisplayAddress(&addr));
3322 }
3323 };
3324 }
3325
connect_csis(&mut self, addr: RawAddress)3326 fn connect_csis(&mut self, addr: RawAddress) {
3327 if !self.is_le_audio_only_enabled {
3328 warn!("connect_csis: LeAudioEnableLeAudioOnly is not set");
3329 return;
3330 }
3331
3332 if *self.csis_states.get(&addr).unwrap_or(&BtCsisConnectionState::Disconnected)
3333 == BtCsisConnectionState::Connected
3334 {
3335 info!("connect_csis: already connected");
3336 return;
3337 }
3338
3339 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3340
3341 info!(
3342 "connect_csis: [{}]: connecting, available profiles: {:?}.",
3343 DisplayAddress(&addr),
3344 available_profiles
3345 );
3346
3347 match self.csis.as_mut() {
3348 Some(csis) => {
3349 csis.connect(addr);
3350 }
3351 None => {
3352 warn!("connect_csis: [{}]: uninitialized Csis to connect", DisplayAddress(&addr));
3353 }
3354 };
3355 }
3356
disconnect_csis(&mut self, addr: RawAddress)3357 fn disconnect_csis(&mut self, addr: RawAddress) {
3358 if *self.csis_states.get(&addr).unwrap_or(&BtCsisConnectionState::Disconnected)
3359 == BtCsisConnectionState::Disconnected
3360 {
3361 info!("disconnect_csis: already disconnected");
3362 return;
3363 }
3364
3365 info!("disconnect_csis: [{}]: disconnecting", DisplayAddress(&addr));
3366
3367 match self.csis.as_mut() {
3368 Some(csis) => {
3369 csis.disconnect(addr);
3370 }
3371 None => {
3372 warn!(
3373 "disconnect_csis: [{}]: uninitialized CSIS to disconnect",
3374 DisplayAddress(&addr)
3375 );
3376 }
3377 };
3378 }
3379
connect(&mut self, addr: RawAddress)3380 fn connect(&mut self, addr: RawAddress) {
3381 if self.is_le_audio_only_enabled {
3382 warn!("connect: LeAudioEnableLeAudioOnly is set");
3383 return;
3384 }
3385
3386 let available_profiles = self.adapter_get_classic_audio_profiles(addr);
3387
3388 info!(
3389 "[{}]: Connecting to device, available profiles: {:?}.",
3390 DisplayAddress(&addr),
3391 available_profiles
3392 );
3393
3394 let connected_profiles = self.connected_profiles.entry(addr).or_insert_with(HashSet::new);
3395
3396 // Sort here so the order of connection is always consistent
3397 let missing_profiles =
3398 available_profiles.difference(&connected_profiles).sorted().collect::<Vec<_>>();
3399
3400 // Connect the profiles one-by-one so it won't stuck at the lower layer.
3401 // Therefore, just connect to one profile for now.
3402 // connect() will be called again after the first profile is successfully connected.
3403 let mut is_connect = false;
3404 for profile in missing_profiles {
3405 match profile {
3406 Profile::A2dpSink => {
3407 metrics::profile_connection_state_changed(
3408 addr,
3409 Profile::A2dpSink as u32,
3410 BtStatus::Success,
3411 BtavConnectionState::Connecting as u32,
3412 );
3413 match self.a2dp.as_mut() {
3414 Some(a2dp) => {
3415 let status: BtStatus = a2dp.connect(addr);
3416 if BtStatus::Success != status {
3417 metrics::profile_connection_state_changed(
3418 addr,
3419 Profile::A2dpSink as u32,
3420 status,
3421 BtavConnectionState::Disconnected as u32,
3422 );
3423 } else {
3424 is_connect = true;
3425 break;
3426 }
3427 }
3428 None => {
3429 warn!("Uninitialized A2DP to connect {}", DisplayAddress(&addr));
3430 metrics::profile_connection_state_changed(
3431 addr,
3432 Profile::A2dpSink as u32,
3433 BtStatus::NotReady,
3434 BtavConnectionState::Disconnected as u32,
3435 );
3436 }
3437 };
3438 }
3439 Profile::Hfp => {
3440 metrics::profile_connection_state_changed(
3441 addr,
3442 Profile::Hfp as u32,
3443 BtStatus::Success,
3444 BtavConnectionState::Connecting as u32,
3445 );
3446 match self.hfp.as_mut() {
3447 Some(hfp) => {
3448 let status: BtStatus = hfp.connect(addr);
3449 if BtStatus::Success != status {
3450 metrics::profile_connection_state_changed(
3451 addr,
3452 Profile::Hfp as u32,
3453 status,
3454 BthfConnectionState::Disconnected as u32,
3455 );
3456 } else {
3457 is_connect = true;
3458 break;
3459 }
3460 }
3461 None => {
3462 warn!("Uninitialized HFP to connect {}", DisplayAddress(&addr));
3463 metrics::profile_connection_state_changed(
3464 addr,
3465 Profile::Hfp as u32,
3466 BtStatus::NotReady,
3467 BthfConnectionState::Disconnected as u32,
3468 );
3469 }
3470 };
3471 }
3472 Profile::AvrcpController => {
3473 // Fluoride will resolve AVRCP as a part of A2DP connection request.
3474 // Explicitly connect to it only when it is considered missing, and don't
3475 // bother about it when A2DP is not connected.
3476 if !connected_profiles.contains(&Profile::A2dpSink) {
3477 continue;
3478 }
3479
3480 metrics::profile_connection_state_changed(
3481 addr,
3482 Profile::AvrcpController as u32,
3483 BtStatus::Success,
3484 BtavConnectionState::Connecting as u32,
3485 );
3486 match self.avrcp.as_mut() {
3487 Some(avrcp) => {
3488 self.avrcp_direction = BtConnectionDirection::Outgoing;
3489 let status: BtStatus = avrcp.connect(addr);
3490 if BtStatus::Success != status {
3491 // Reset direction to unknown.
3492 self.avrcp_direction = BtConnectionDirection::Unknown;
3493 metrics::profile_connection_state_changed(
3494 addr,
3495 Profile::AvrcpController as u32,
3496 status,
3497 BtavConnectionState::Disconnected as u32,
3498 );
3499 } else {
3500 is_connect = true;
3501 break;
3502 }
3503 }
3504
3505 None => {
3506 warn!("Uninitialized AVRCP to connect {}", DisplayAddress(&addr));
3507 metrics::profile_connection_state_changed(
3508 addr,
3509 Profile::AvrcpController as u32,
3510 BtStatus::NotReady,
3511 BtavConnectionState::Disconnected as u32,
3512 );
3513 }
3514 };
3515 }
3516 _ => warn!("Unknown profile: {:?}", profile),
3517 }
3518 }
3519
3520 if is_connect {
3521 let mut tasks = self.fallback_tasks.lock().unwrap();
3522 let mut states = self.device_states.lock().unwrap();
3523 if !tasks.contains_key(&addr) {
3524 states.insert(addr, DeviceConnectionStates::Initiating);
3525
3526 let fallback_tasks = self.fallback_tasks.clone();
3527 let device_states = self.device_states.clone();
3528 let now_ts = Instant::now();
3529 let task = topstack::get_runtime().spawn(async move {
3530 sleep(Duration::from_secs(CONNECT_AS_INITIATOR_TIMEOUT_SEC)).await;
3531
3532 // If here the task is not yet aborted, probably connection is failed,
3533 // therefore here we release the states. Even if later the connection is
3534 // actually successful, we will just treat this as if the connection is
3535 // initiated by the peer and will reconnect the missing profiles after
3536 // some time, so it's safe.
3537 {
3538 device_states.lock().unwrap().remove(&addr);
3539 fallback_tasks.lock().unwrap().remove(&addr);
3540 }
3541 });
3542 tasks.insert(addr, Some((task, now_ts)));
3543 }
3544 }
3545 }
3546
cleanup(&mut self) -> bool3547 fn cleanup(&mut self) -> bool {
3548 true
3549 }
3550
3551 // This may not disconnect all media profiles at once, but once the stack
3552 // is notified of the disconnection callback, `disconnect_device` will be
3553 // invoked as necessary to ensure the device is removed.
disconnect(&mut self, addr: RawAddress)3554 fn disconnect(&mut self, addr: RawAddress) {
3555 if self.is_le_audio_only_enabled {
3556 warn!("LeAudioEnableLeAudioOnly is set");
3557 return;
3558 }
3559
3560 let connected_profiles = match self.connected_profiles.get(&addr) {
3561 Some(profiles) => profiles,
3562 None => {
3563 warn!(
3564 "[{}]: Ignoring disconnection request since there is no connected profile.",
3565 DisplayAddress(&addr)
3566 );
3567 return;
3568 }
3569 };
3570
3571 for profile in connected_profiles {
3572 match profile {
3573 Profile::A2dpSink => {
3574 // Some headsets (b/278963515) will try reconnecting to A2DP
3575 // when HFP is running but (requested to be) disconnected.
3576 // TODO: Remove this workaround once proper fix lands.
3577 if connected_profiles.contains(&Profile::Hfp) {
3578 continue;
3579 }
3580 metrics::profile_connection_state_changed(
3581 addr,
3582 Profile::A2dpSink as u32,
3583 BtStatus::Success,
3584 BtavConnectionState::Disconnecting as u32,
3585 );
3586 match self.a2dp.as_mut() {
3587 Some(a2dp) => {
3588 let status: BtStatus = a2dp.disconnect(addr);
3589 if BtStatus::Success != status {
3590 metrics::profile_connection_state_changed(
3591 addr,
3592 Profile::A2dpSource as u32,
3593 status,
3594 BtavConnectionState::Disconnected as u32,
3595 );
3596 }
3597 }
3598 None => {
3599 warn!("Uninitialized A2DP to disconnect {}", DisplayAddress(&addr));
3600 metrics::profile_connection_state_changed(
3601 addr,
3602 Profile::A2dpSource as u32,
3603 BtStatus::NotReady,
3604 BtavConnectionState::Disconnected as u32,
3605 );
3606 }
3607 };
3608 }
3609 Profile::Hfp => {
3610 metrics::profile_connection_state_changed(
3611 addr,
3612 Profile::Hfp as u32,
3613 BtStatus::Success,
3614 BthfConnectionState::Disconnecting as u32,
3615 );
3616 match self.hfp.as_mut() {
3617 Some(hfp) => {
3618 let status: BtStatus = hfp.disconnect(addr);
3619 if BtStatus::Success != status {
3620 metrics::profile_connection_state_changed(
3621 addr,
3622 Profile::Hfp as u32,
3623 status,
3624 BthfConnectionState::Disconnected as u32,
3625 );
3626 }
3627 }
3628 None => {
3629 warn!("Uninitialized HFP to disconnect {}", DisplayAddress(&addr));
3630 metrics::profile_connection_state_changed(
3631 addr,
3632 Profile::Hfp as u32,
3633 BtStatus::NotReady,
3634 BthfConnectionState::Disconnected as u32,
3635 );
3636 }
3637 };
3638 }
3639 Profile::AvrcpController => {
3640 if connected_profiles.contains(&Profile::A2dpSink) {
3641 continue;
3642 }
3643 metrics::profile_connection_state_changed(
3644 addr,
3645 Profile::AvrcpController as u32,
3646 BtStatus::Success,
3647 BtavConnectionState::Disconnecting as u32,
3648 );
3649 match self.avrcp.as_mut() {
3650 Some(avrcp) => {
3651 self.avrcp_direction = BtConnectionDirection::Outgoing;
3652 let status: BtStatus = avrcp.disconnect(addr);
3653 if BtStatus::Success != status {
3654 // Reset direction to unknown.
3655 self.avrcp_direction = BtConnectionDirection::Unknown;
3656 metrics::profile_connection_state_changed(
3657 addr,
3658 Profile::AvrcpController as u32,
3659 status,
3660 BtavConnectionState::Disconnected as u32,
3661 );
3662 }
3663 }
3664
3665 None => {
3666 warn!("Uninitialized AVRCP to disconnect {}", DisplayAddress(&addr));
3667 metrics::profile_connection_state_changed(
3668 addr,
3669 Profile::AvrcpController as u32,
3670 BtStatus::NotReady,
3671 BtavConnectionState::Disconnected as u32,
3672 );
3673 }
3674 };
3675 }
3676 _ => warn!("Unknown profile: {:?}", profile),
3677 }
3678 }
3679 }
3680
set_active_device(&mut self, addr: RawAddress)3681 fn set_active_device(&mut self, addr: RawAddress) {
3682 match self.a2dp_states.get(&addr) {
3683 Some(BtavConnectionState::Connected) => {
3684 if let Some(a2dp) = self.a2dp.as_mut() {
3685 a2dp.set_active_device(addr);
3686 self.uinput.set_active_device(addr.to_string());
3687 } else {
3688 warn!("Uninitialized A2DP to set active device");
3689 }
3690 }
3691 _ => warn!("[{}] Not connected or disconnected A2DP address", DisplayAddress(&addr)),
3692 };
3693 }
3694
reset_active_device(&mut self)3695 fn reset_active_device(&mut self) {
3696 // During MPS tests, there might be some A2DP stream manipulation unexpected to CRAS.
3697 // CRAS would then attempt to reset the active device. Ignore it during test.
3698 if !self.is_complete_profiles_required() {
3699 return;
3700 }
3701
3702 if let Some(a2dp) = self.a2dp.as_mut() {
3703 a2dp.set_active_device(RawAddress::empty());
3704 } else {
3705 warn!("Uninitialized A2DP to set active device");
3706 }
3707 self.uinput.set_active_device(RawAddress::empty().to_string());
3708 }
3709
set_hfp_active_device(&mut self, addr: RawAddress)3710 fn set_hfp_active_device(&mut self, addr: RawAddress) {
3711 match self.hfp_states.get(&addr) {
3712 Some(BthfConnectionState::SlcConnected) => {
3713 if let Some(hfp) = self.hfp.as_mut() {
3714 hfp.set_active_device(addr);
3715 } else {
3716 warn!("Uninitialized HFP to set active device");
3717 }
3718 }
3719 _ => warn!("[{}] Not connected or disconnected HFP address", DisplayAddress(&addr)),
3720 }
3721 }
3722
set_audio_config( &mut self, addr: RawAddress, codec_type: A2dpCodecIndex, sample_rate: A2dpCodecSampleRate, bits_per_sample: A2dpCodecBitsPerSample, channel_mode: A2dpCodecChannelMode, ) -> bool3723 fn set_audio_config(
3724 &mut self,
3725 addr: RawAddress,
3726 codec_type: A2dpCodecIndex,
3727 sample_rate: A2dpCodecSampleRate,
3728 bits_per_sample: A2dpCodecBitsPerSample,
3729 channel_mode: A2dpCodecChannelMode,
3730 ) -> bool {
3731 if self.a2dp_states.get(&addr).is_none() {
3732 warn!(
3733 "[{}]: Ignore set config event for unconnected or disconnected A2DP device",
3734 DisplayAddress(&addr)
3735 );
3736 return false;
3737 }
3738
3739 match self.a2dp.as_mut() {
3740 Some(a2dp) => {
3741 let caps = self.a2dp_caps.get(&addr).unwrap_or(&Vec::new()).to_vec();
3742
3743 for cap in &caps {
3744 if A2dpCodecIndex::from(cap.codec_type) == codec_type {
3745 if (A2dpCodecSampleRate::from_bits(cap.sample_rate).unwrap() & sample_rate)
3746 != sample_rate
3747 {
3748 warn!("Unsupported sample rate {:?}", sample_rate);
3749 return false;
3750 }
3751 if (A2dpCodecBitsPerSample::from_bits(cap.bits_per_sample).unwrap()
3752 & bits_per_sample)
3753 != bits_per_sample
3754 {
3755 warn!("Unsupported bit depth {:?}", bits_per_sample);
3756 return false;
3757 }
3758 if (A2dpCodecChannelMode::from_bits(cap.channel_mode).unwrap()
3759 & channel_mode)
3760 != channel_mode
3761 {
3762 warn!("Unsupported channel mode {:?}", channel_mode);
3763 return false;
3764 }
3765
3766 let config = vec![A2dpCodecConfig {
3767 codec_type: codec_type as i32,
3768 codec_priority: A2dpCodecPriority::Highest as i32,
3769 sample_rate: sample_rate.bits() as i32,
3770 bits_per_sample: bits_per_sample.bits() as i32,
3771 channel_mode: channel_mode.bits() as i32,
3772 ..Default::default()
3773 }];
3774
3775 a2dp.config_codec(addr, config);
3776 return true;
3777 }
3778 }
3779
3780 warn!("Unsupported codec type {:?}", codec_type);
3781 false
3782 }
3783 None => {
3784 warn!("Uninitialized A2DP to set audio config");
3785 false
3786 }
3787 }
3788 }
3789
set_volume(&mut self, volume: u8)3790 fn set_volume(&mut self, volume: u8) {
3791 // Guard the range 0-127 by the try_from cast from u8 to i8.
3792 let vol = match i8::try_from(volume) {
3793 Ok(val) => val,
3794 _ => {
3795 warn!("Ignore invalid volume {}", volume);
3796 return;
3797 }
3798 };
3799
3800 match self.avrcp.as_mut() {
3801 Some(avrcp) => avrcp.set_volume(vol),
3802 None => warn!("Uninitialized AVRCP to set volume"),
3803 };
3804 }
3805
set_hfp_volume(&mut self, volume: u8, addr: RawAddress)3806 fn set_hfp_volume(&mut self, volume: u8, addr: RawAddress) {
3807 let vol = match i8::try_from(volume) {
3808 Ok(val) if val <= 15 => val,
3809 _ => {
3810 warn!("[{}]: Ignore invalid volume {}", DisplayAddress(&addr), volume);
3811 return;
3812 }
3813 };
3814
3815 if self.hfp_states.get(&addr).is_none() {
3816 warn!(
3817 "[{}]: Ignore volume event for unconnected or disconnected HFP device",
3818 DisplayAddress(&addr)
3819 );
3820 return;
3821 }
3822
3823 match self.hfp.as_mut() {
3824 Some(hfp) => {
3825 hfp.set_volume(vol, addr);
3826 }
3827 None => warn!("Uninitialized HFP to set volume"),
3828 };
3829 }
3830
start_audio_request(&mut self) -> bool3831 fn start_audio_request(&mut self) -> bool {
3832 self.start_audio_request_impl()
3833 }
3834
stop_audio_request(&mut self)3835 fn stop_audio_request(&mut self) {
3836 debug!("Stop audio request");
3837
3838 match self.a2dp.as_mut() {
3839 Some(a2dp) => a2dp.stop_audio_request(),
3840 None => warn!("Uninitialized A2DP to stop audio request"),
3841 };
3842 }
3843
start_sco_call( &mut self, address: RawAddress, sco_offload: bool, disabled_codecs: HfpCodecBitId, ) -> bool3844 fn start_sco_call(
3845 &mut self,
3846 address: RawAddress,
3847 sco_offload: bool,
3848 disabled_codecs: HfpCodecBitId,
3849 ) -> bool {
3850 self.start_sco_call_impl(address, sco_offload, disabled_codecs)
3851 }
3852
stop_sco_call(&mut self, address: RawAddress)3853 fn stop_sco_call(&mut self, address: RawAddress) {
3854 self.stop_sco_call_impl(address)
3855 }
3856
get_a2dp_audio_started(&mut self, addr: RawAddress) -> bool3857 fn get_a2dp_audio_started(&mut self, addr: RawAddress) -> bool {
3858 match self.a2dp_audio_state.get(&addr) {
3859 Some(BtavAudioState::Started) => true,
3860 _ => false,
3861 }
3862 }
3863
get_hfp_audio_final_codecs(&mut self, addr: RawAddress) -> u83864 fn get_hfp_audio_final_codecs(&mut self, addr: RawAddress) -> u8 {
3865 match self.hfp_audio_state.get(&addr) {
3866 Some(BthfAudioState::Connected) => match self.hfp_cap.get(&addr) {
3867 Some(caps)
3868 if (*caps & HfpCodecFormat::LC3_TRANSPARENT)
3869 == HfpCodecFormat::LC3_TRANSPARENT =>
3870 {
3871 HfpCodecBitId::LC3
3872 }
3873 Some(caps) if (*caps & HfpCodecFormat::MSBC) == HfpCodecFormat::MSBC => {
3874 HfpCodecBitId::MSBC
3875 }
3876 Some(caps)
3877 if (*caps & HfpCodecFormat::MSBC_TRANSPARENT)
3878 == HfpCodecFormat::MSBC_TRANSPARENT =>
3879 {
3880 HfpCodecBitId::MSBC
3881 }
3882 Some(caps) if (*caps & HfpCodecFormat::CVSD) == HfpCodecFormat::CVSD => {
3883 HfpCodecBitId::CVSD
3884 }
3885 _ => {
3886 warn!("hfp_cap not found, fallback to CVSD.");
3887 HfpCodecBitId::CVSD
3888 }
3889 },
3890 _ => HfpCodecBitId::NONE,
3891 }
3892 .try_into()
3893 .unwrap()
3894 }
3895
get_presentation_position(&mut self) -> PresentationPosition3896 fn get_presentation_position(&mut self) -> PresentationPosition {
3897 let position = match self.a2dp.as_mut() {
3898 Some(a2dp) => a2dp.get_presentation_position(),
3899 None => {
3900 warn!("Uninitialized A2DP to get presentation position");
3901 Default::default()
3902 }
3903 };
3904 PresentationPosition {
3905 remote_delay_report_ns: position.remote_delay_report_ns,
3906 total_bytes_read: position.total_bytes_read,
3907 data_position_sec: position.data_position_sec,
3908 data_position_nsec: position.data_position_nsec,
3909 }
3910 }
3911
set_player_playback_status(&mut self, status: String)3912 fn set_player_playback_status(&mut self, status: String) {
3913 debug!("AVRCP received player playback status: {}", status);
3914 match self.avrcp.as_mut() {
3915 Some(avrcp) => avrcp.set_playback_status(&status),
3916 None => warn!("Uninitialized AVRCP to set player playback status"),
3917 };
3918 }
set_player_position(&mut self, position_us: i64)3919 fn set_player_position(&mut self, position_us: i64) {
3920 debug!("AVRCP received player position: {}", position_us);
3921 match self.avrcp.as_mut() {
3922 Some(avrcp) => avrcp.set_position(position_us),
3923 None => warn!("Uninitialized AVRCP to set player position"),
3924 };
3925 }
set_player_metadata(&mut self, metadata: PlayerMetadata)3926 fn set_player_metadata(&mut self, metadata: PlayerMetadata) {
3927 debug!("AVRCP received player metadata: {:?}", metadata);
3928 match self.avrcp.as_mut() {
3929 Some(avrcp) => avrcp.set_metadata(&metadata),
3930 None => warn!("Uninitialized AVRCP to set player playback status"),
3931 };
3932 }
3933
trigger_debug_dump(&mut self)3934 fn trigger_debug_dump(&mut self) {
3935 match self.hfp.as_mut() {
3936 Some(hfp) => hfp.debug_dump(),
3937 None => warn!("Uninitialized HFP to dump debug log"),
3938 };
3939 }
3940
group_set_active(&mut self, group_id: i32)3941 fn group_set_active(&mut self, group_id: i32) {
3942 match self.le_audio.as_mut() {
3943 Some(le_audio) => le_audio.group_set_active(group_id),
3944 None => {
3945 warn!("Uninitialized LEA to group set active");
3946 }
3947 }
3948 }
3949
source_metadata_changed( &mut self, usage: BtLeAudioUsage, content_type: BtLeAudioContentType, gain: f64, ) -> bool3950 fn source_metadata_changed(
3951 &mut self,
3952 usage: BtLeAudioUsage,
3953 content_type: BtLeAudioContentType,
3954 gain: f64,
3955 ) -> bool {
3956 match self.le_audio.as_mut() {
3957 Some(le_audio) => {
3958 let data = vec![SourceMetadata { usage, content_type, gain }];
3959 le_audio.source_metadata_changed(data);
3960 true
3961 }
3962 None => {
3963 warn!("Uninitialized LEA to update source metadata");
3964 false
3965 }
3966 }
3967 }
3968
sink_metadata_changed(&mut self, source: BtLeAudioSource, gain: f64) -> bool3969 fn sink_metadata_changed(&mut self, source: BtLeAudioSource, gain: f64) -> bool {
3970 match self.le_audio.as_mut() {
3971 Some(le_audio) => {
3972 let data = vec![SinkMetadata { source, gain }];
3973 le_audio.sink_metadata_changed(data);
3974 true
3975 }
3976 None => {
3977 warn!("Uninitialized LEA to update sink metadata");
3978 false
3979 }
3980 }
3981 }
3982
host_start_audio_request(&mut self) -> bool3983 fn host_start_audio_request(&mut self) -> bool {
3984 match self.le_audio.as_mut() {
3985 Some(le_audio) => le_audio.host_start_audio_request(),
3986 None => {
3987 warn!("Uninitialized LEA to start audio request");
3988 false
3989 }
3990 }
3991 }
3992
host_stop_audio_request(&mut self)3993 fn host_stop_audio_request(&mut self) {
3994 match self.le_audio.as_mut() {
3995 Some(le_audio) => le_audio.host_stop_audio_request(),
3996 None => {
3997 warn!("Uninitialized LEA to stop audio request");
3998 }
3999 }
4000 }
4001
peer_start_audio_request(&mut self) -> bool4002 fn peer_start_audio_request(&mut self) -> bool {
4003 match self.le_audio.as_mut() {
4004 Some(le_audio) => le_audio.peer_start_audio_request(),
4005 None => {
4006 warn!("Uninitialized LEA for peer to start audio request");
4007 false
4008 }
4009 }
4010 }
4011
peer_stop_audio_request(&mut self)4012 fn peer_stop_audio_request(&mut self) {
4013 match self.le_audio.as_mut() {
4014 Some(le_audio) => le_audio.peer_stop_audio_request(),
4015 None => {
4016 warn!("Uninitialized LEA for peer to stop audio request");
4017 }
4018 }
4019 }
4020
get_host_pcm_config(&mut self) -> BtLePcmConfig4021 fn get_host_pcm_config(&mut self) -> BtLePcmConfig {
4022 match self.le_audio.as_mut() {
4023 Some(le_audio) => le_audio.get_host_pcm_config(),
4024 None => {
4025 warn!("Uninitialized LEA to get active pcm config from host");
4026 Default::default()
4027 }
4028 }
4029 }
4030
get_peer_pcm_config(&mut self) -> BtLePcmConfig4031 fn get_peer_pcm_config(&mut self) -> BtLePcmConfig {
4032 match self.le_audio.as_mut() {
4033 Some(le_audio) => le_audio.get_peer_pcm_config(),
4034 None => {
4035 warn!("Uninitialized LEA to get active pcm config from peer");
4036 Default::default()
4037 }
4038 }
4039 }
4040
get_host_stream_started(&mut self) -> BtLeStreamStartedStatus4041 fn get_host_stream_started(&mut self) -> BtLeStreamStartedStatus {
4042 match self.le_audio.as_mut() {
4043 Some(le_audio) => le_audio.get_host_stream_started(),
4044 None => {
4045 warn!("Uninitialized LEA to get_host_stream_started");
4046 BtLeStreamStartedStatus::Idle
4047 }
4048 }
4049 }
4050
get_peer_stream_started(&mut self) -> BtLeStreamStartedStatus4051 fn get_peer_stream_started(&mut self) -> BtLeStreamStartedStatus {
4052 match self.le_audio.as_mut() {
4053 Some(le_audio) => le_audio.get_peer_stream_started(),
4054 None => {
4055 warn!("Uninitialized LEA to get_peer_stream_started");
4056 BtLeStreamStartedStatus::Idle
4057 }
4058 }
4059 }
4060
get_unicast_monitor_mode_status( &mut self, direction: BtLeAudioDirection, ) -> BtLeAudioUnicastMonitorModeStatus4061 fn get_unicast_monitor_mode_status(
4062 &mut self,
4063 direction: BtLeAudioDirection,
4064 ) -> BtLeAudioUnicastMonitorModeStatus {
4065 *self
4066 .le_audio_unicast_monitor_mode_status
4067 .get(&direction.into())
4068 .unwrap_or(&BtLeAudioUnicastMonitorModeStatus::StreamingSuspended)
4069 }
4070
get_group_stream_status(&mut self, group_id: i32) -> BtLeAudioGroupStreamStatus4071 fn get_group_stream_status(&mut self, group_id: i32) -> BtLeAudioGroupStreamStatus {
4072 if self.le_audio_groups.get(&group_id).is_none() {
4073 return BtLeAudioGroupStreamStatus::Idle;
4074 }
4075
4076 self.le_audio_groups.get(&group_id).unwrap().stream_status
4077 }
4078
get_group_status(&mut self, group_id: i32) -> BtLeAudioGroupStatus4079 fn get_group_status(&mut self, group_id: i32) -> BtLeAudioGroupStatus {
4080 if self.le_audio_groups.get(&group_id).is_none() {
4081 return BtLeAudioGroupStatus::Inactive;
4082 }
4083
4084 self.le_audio_groups.get(&group_id).unwrap().status
4085 }
4086
set_group_volume(&mut self, group_id: i32, volume: u8)4087 fn set_group_volume(&mut self, group_id: i32, volume: u8) {
4088 match self.vc.as_mut() {
4089 Some(vc) => {
4090 vc.set_volume(group_id, volume);
4091 }
4092 None => warn!("Uninitialized VC to set volume"),
4093 };
4094 }
4095 }
4096
4097 impl IBluetoothTelephony for BluetoothMedia {
register_telephony_callback( &mut self, callback: Box<dyn IBluetoothTelephonyCallback + Send>, ) -> bool4098 fn register_telephony_callback(
4099 &mut self,
4100 callback: Box<dyn IBluetoothTelephonyCallback + Send>,
4101 ) -> bool {
4102 let _id = self.telephony_callbacks.lock().unwrap().add_callback(callback);
4103 true
4104 }
4105
set_network_available(&mut self, network_available: bool)4106 fn set_network_available(&mut self, network_available: bool) {
4107 if self.telephony_device_status.network_available == network_available {
4108 return;
4109 }
4110 self.telephony_device_status.network_available = network_available;
4111 self.device_status_notification();
4112 }
4113
set_roaming(&mut self, roaming: bool)4114 fn set_roaming(&mut self, roaming: bool) {
4115 if self.telephony_device_status.roaming == roaming {
4116 return;
4117 }
4118 self.telephony_device_status.roaming = roaming;
4119 self.device_status_notification();
4120 }
4121
set_signal_strength(&mut self, signal_strength: i32) -> bool4122 fn set_signal_strength(&mut self, signal_strength: i32) -> bool {
4123 if signal_strength < 0 || signal_strength > 5 {
4124 warn!("Invalid signal strength, got {}, want 0 to 5", signal_strength);
4125 return false;
4126 }
4127 if self.telephony_device_status.signal_strength == signal_strength {
4128 return true;
4129 }
4130
4131 self.telephony_device_status.signal_strength = signal_strength;
4132 self.device_status_notification();
4133
4134 true
4135 }
4136
set_battery_level(&mut self, battery_level: i32) -> bool4137 fn set_battery_level(&mut self, battery_level: i32) -> bool {
4138 if battery_level < 0 || battery_level > 5 {
4139 warn!("Invalid battery level, got {}, want 0 to 5", battery_level);
4140 return false;
4141 }
4142 if self.telephony_device_status.battery_level == battery_level {
4143 return true;
4144 }
4145
4146 self.telephony_device_status.battery_level = battery_level;
4147 self.device_status_notification();
4148
4149 true
4150 }
4151
set_phone_ops_enabled(&mut self, enable: bool)4152 fn set_phone_ops_enabled(&mut self, enable: bool) {
4153 info!("Bluetooth HID telephony mode enabled");
4154 if self.phone_ops_enabled == enable {
4155 return;
4156 }
4157
4158 self.call_list = vec![];
4159 self.phone_state.num_active = 0;
4160 self.phone_state.num_held = 0;
4161 self.phone_state.state = CallState::Idle;
4162 self.memory_dialing_number = None;
4163 self.last_dialing_number = None;
4164 self.a2dp_has_interrupted_stream = false;
4165
4166 self.phone_ops_enabled = enable;
4167 if self.hfp_audio_state.keys().any(|addr| self.should_insert_call_when_sco_start(*addr))
4168 && self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected)
4169 {
4170 self.place_active_call();
4171 return;
4172 }
4173
4174 self.phone_state_change("".into());
4175 }
4176
set_mps_qualification_enabled(&mut self, enable: bool)4177 fn set_mps_qualification_enabled(&mut self, enable: bool) {
4178 info!("MPS qualification mode enabled");
4179 if self.mps_qualification_enabled == enable {
4180 return;
4181 }
4182
4183 self.call_list = vec![];
4184 self.phone_state.num_active = 0;
4185 self.phone_state.num_held = 0;
4186 self.phone_state.state = CallState::Idle;
4187 self.memory_dialing_number = None;
4188 self.last_dialing_number = None;
4189 self.a2dp_has_interrupted_stream = false;
4190 self.mps_qualification_enabled = enable;
4191
4192 if self.hfp_audio_state.keys().any(|addr| self.should_insert_call_when_sco_start(*addr))
4193 && self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected)
4194 {
4195 self.place_active_call();
4196 return;
4197 }
4198
4199 self.phone_state_change("".into());
4200 }
4201
incoming_call(&mut self, number: String) -> bool4202 fn incoming_call(&mut self, number: String) -> bool {
4203 if !self.mps_qualification_enabled {
4204 warn!("Unexpected incoming_call dbus command. mps_qualification_enabled does not enabled.");
4205 return false;
4206 }
4207 return self.incoming_call_impl(number);
4208 }
4209
dialing_call(&mut self, number: String) -> bool4210 fn dialing_call(&mut self, number: String) -> bool {
4211 if !self.mps_qualification_enabled {
4212 warn!("Unexpected incoming_call dbus command. mps_qualification_enabled does not enabled.");
4213 return false;
4214 }
4215 return self.dialing_call_impl(number, None);
4216 }
4217
answer_call(&mut self) -> bool4218 fn answer_call(&mut self) -> bool {
4219 if !self.mps_qualification_enabled {
4220 warn!(
4221 "Unexpected answer_call dbus command. mps_qualification_enabled does not enabled."
4222 );
4223 return false;
4224 }
4225 return self.answer_call_impl();
4226 }
4227
hangup_call(&mut self) -> bool4228 fn hangup_call(&mut self) -> bool {
4229 if !self.mps_qualification_enabled {
4230 warn!(
4231 "Unexpected hangup_call dbus command. mps_qualification_enabled does not enabled."
4232 );
4233 return false;
4234 }
4235 return self.hangup_call_impl();
4236 }
4237
set_memory_call(&mut self, number: Option<String>) -> bool4238 fn set_memory_call(&mut self, number: Option<String>) -> bool {
4239 if !self.mps_qualification_enabled {
4240 warn!("Unexpected set_memory_call dbus command. mps_qualification_enabled does not enabled.");
4241 return false;
4242 }
4243 self.memory_dialing_number = number;
4244 true
4245 }
4246
set_last_call(&mut self, number: Option<String>) -> bool4247 fn set_last_call(&mut self, number: Option<String>) -> bool {
4248 if !self.mps_qualification_enabled {
4249 warn!("Unexpected set_last_call dbus command. mps_qualification_enabled does not enabled.");
4250 return false;
4251 }
4252 self.last_dialing_number = number;
4253 true
4254 }
4255
release_held(&mut self) -> bool4256 fn release_held(&mut self) -> bool {
4257 if !self.mps_qualification_enabled {
4258 warn!(
4259 "Unexpected release_held dbus command. mps_qualification_enabled does not enabled."
4260 );
4261 return false;
4262 }
4263 return self.release_held_impl(None);
4264 }
4265
release_active_accept_held(&mut self) -> bool4266 fn release_active_accept_held(&mut self) -> bool {
4267 if !self.mps_qualification_enabled {
4268 warn!("Unexpected release_active_accept_held dbus command. mps_qualification_enabled does not enabled.");
4269 return false;
4270 }
4271 return self.release_active_accept_held_impl(None);
4272 }
4273
hold_active_accept_held(&mut self) -> bool4274 fn hold_active_accept_held(&mut self) -> bool {
4275 if !self.mps_qualification_enabled {
4276 warn!("Unexpected hold_active_accept_held dbus command. mps_qualification_enabled does not enabled.");
4277 return false;
4278 }
4279 return self.hold_active_accept_held_impl(None);
4280 }
4281
audio_connect(&mut self, address: RawAddress) -> bool4282 fn audio_connect(&mut self, address: RawAddress) -> bool {
4283 self.start_sco_call_impl(address, false, HfpCodecBitId::NONE)
4284 }
4285
audio_disconnect(&mut self, address: RawAddress)4286 fn audio_disconnect(&mut self, address: RawAddress) {
4287 self.stop_sco_call_impl(address)
4288 }
4289 }
4290
4291 struct BatteryProviderCallback {}
4292
4293 impl BatteryProviderCallback {
new() -> Self4294 fn new() -> Self {
4295 Self {}
4296 }
4297 }
4298
4299 impl IBatteryProviderCallback for BatteryProviderCallback {
4300 // We do not support refreshing HFP battery information.
refresh_battery_info(&mut self)4301 fn refresh_battery_info(&mut self) {}
4302 }
4303
4304 impl RPCProxy for BatteryProviderCallback {
get_object_id(&self) -> String4305 fn get_object_id(&self) -> String {
4306 "HFP BatteryProvider Callback".to_string()
4307 }
4308 }
4309