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