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_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: u32, src_audio_location: u32, avail_cont: u16, )295 fn on_lea_audio_conf(
296 &mut self,
297 direction: u8,
298 group_id: i32,
299 snk_audio_location: u32,
300 src_audio_location: u32,
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: u32,
424 pub src_audio_location: u32,
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 device = BluetoothDevice::new(addr, "".to_string());
2557 self.adapter
2558 .lock()
2559 .unwrap()
2560 .get_remote_uuids(device)
2561 .into_iter()
2562 .filter_map(|u| UuidHelper::is_known_profile(&u))
2563 .filter(|u| MEDIA_CLASSIC_AUDIO_PROFILES.contains(u))
2564 .collect()
2565 }
2566
get_hfp_connection_state(&self) -> ProfileConnectionState2567 pub fn get_hfp_connection_state(&self) -> ProfileConnectionState {
2568 if self.hfp_audio_state.values().any(|state| *state == BthfAudioState::Connected) {
2569 ProfileConnectionState::Active
2570 } else {
2571 let mut winning_state = ProfileConnectionState::Disconnected;
2572 for state in self.hfp_states.values() {
2573 // Grab any state higher than the current state.
2574 match state {
2575 // Any SLC completed state means the profile is connected.
2576 BthfConnectionState::SlcConnected => {
2577 winning_state = ProfileConnectionState::Connected;
2578 }
2579
2580 // Connecting or Connected are both counted as connecting for profile state
2581 // since it's not a complete connection.
2582 BthfConnectionState::Connecting | BthfConnectionState::Connected
2583 if winning_state != ProfileConnectionState::Connected =>
2584 {
2585 winning_state = ProfileConnectionState::Connecting;
2586 }
2587
2588 BthfConnectionState::Disconnecting
2589 if winning_state == ProfileConnectionState::Disconnected =>
2590 {
2591 winning_state = ProfileConnectionState::Disconnecting;
2592 }
2593
2594 _ => (),
2595 }
2596 }
2597
2598 winning_state
2599 }
2600 }
2601
get_a2dp_connection_state(&self) -> ProfileConnectionState2602 pub fn get_a2dp_connection_state(&self) -> ProfileConnectionState {
2603 if self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
2604 ProfileConnectionState::Active
2605 } else {
2606 let mut winning_state = ProfileConnectionState::Disconnected;
2607 for state in self.a2dp_states.values() {
2608 // Grab any state higher than the current state.
2609 match state {
2610 BtavConnectionState::Connected => {
2611 winning_state = ProfileConnectionState::Connected;
2612 }
2613
2614 BtavConnectionState::Connecting
2615 if winning_state != ProfileConnectionState::Connected =>
2616 {
2617 winning_state = ProfileConnectionState::Connecting;
2618 }
2619
2620 BtavConnectionState::Disconnecting
2621 if winning_state == ProfileConnectionState::Disconnected =>
2622 {
2623 winning_state = ProfileConnectionState::Disconnecting;
2624 }
2625
2626 _ => (),
2627 }
2628 }
2629
2630 winning_state
2631 }
2632 }
2633
filter_to_connected_audio_devices_from( &self, devices: &Vec<BluetoothDevice>, ) -> Vec<BluetoothDevice>2634 pub fn filter_to_connected_audio_devices_from(
2635 &self,
2636 devices: &Vec<BluetoothDevice>,
2637 ) -> Vec<BluetoothDevice> {
2638 devices
2639 .iter()
2640 .filter(|d| {
2641 self.is_any_profile_connected(&d.address, MEDIA_CLASSIC_AUDIO_PROFILES)
2642 || self.is_any_profile_connected(&d.address, MEDIA_LE_AUDIO_PROFILES)
2643 })
2644 .cloned()
2645 .collect()
2646 }
2647
start_audio_request_impl(&mut self) -> bool2648 fn start_audio_request_impl(&mut self) -> bool {
2649 debug!("Start audio request");
2650 self.a2dp.start_audio_request()
2651 }
2652
suspend_audio_request_impl(&mut self)2653 fn suspend_audio_request_impl(&mut self) {
2654 self.a2dp.suspend_audio_request();
2655 }
2656
try_a2dp_resume(&mut self)2657 fn try_a2dp_resume(&mut self) {
2658 // Try resume the A2DP stream (per MPS v1.0) on rejecting an incoming call or an
2659 // outgoing call is rejected.
2660 // It may fail if a SCO connection is still active (terminate call case), in that
2661 // case we will retry on SCO disconnected.
2662 if !self.mps_qualification_enabled {
2663 return;
2664 }
2665 // Make sure there is no any SCO connection and then resume the A2DP stream.
2666 if self.a2dp_has_interrupted_stream
2667 && !self.hfp_audio_state.values().any(|state| *state == BthfAudioState::Connected)
2668 {
2669 self.a2dp_has_interrupted_stream = false;
2670 self.start_audio_request_impl();
2671 }
2672 }
2673
try_a2dp_suspend(&mut self)2674 fn try_a2dp_suspend(&mut self) {
2675 // Try suspend the A2DP stream (per MPS v1.0) when receiving an incoming call
2676 if !self.mps_qualification_enabled {
2677 return;
2678 }
2679 // Suspend the A2DP stream if there is any.
2680 if self.a2dp_audio_state.values().any(|state| *state == BtavAudioState::Started) {
2681 self.a2dp_has_interrupted_stream = true;
2682 self.suspend_audio_request_impl();
2683 }
2684 }
2685
start_sco_call_impl( &mut self, addr: RawAddress, sco_offload: bool, disabled_codecs: HfpCodecBitId, ) -> bool2686 fn start_sco_call_impl(
2687 &mut self,
2688 addr: RawAddress,
2689 sco_offload: bool,
2690 disabled_codecs: HfpCodecBitId,
2691 ) -> bool {
2692 info!("Start sco call for {}", DisplayAddress(&addr));
2693
2694 let Ok(disabled_codecs) = disabled_codecs.try_into() else {
2695 warn!("Can't parse disabled_codecs");
2696 return false;
2697 };
2698 if self.hfp.connect_audio(addr, sco_offload, disabled_codecs) != 0 {
2699 warn!("SCO connect_audio status failed");
2700 return false;
2701 }
2702 info!("SCO connect_audio status success");
2703 true
2704 }
2705
stop_sco_call_impl(&mut self, addr: RawAddress)2706 fn stop_sco_call_impl(&mut self, addr: RawAddress) {
2707 info!("Stop sco call for {}", DisplayAddress(&addr));
2708 self.hfp.disconnect_audio(addr);
2709 }
2710
device_status_notification(&mut self)2711 fn device_status_notification(&mut self) {
2712 for (addr, state) in self.hfp_states.iter() {
2713 if *state != BthfConnectionState::SlcConnected {
2714 continue;
2715 }
2716 debug!(
2717 "[{}]: Device status notification {:?}",
2718 DisplayAddress(addr),
2719 self.telephony_device_status
2720 );
2721 let status = self.hfp.device_status_notification(self.telephony_device_status, *addr);
2722 if status != BtStatus::Success {
2723 warn!(
2724 "[{}]: Device status notification failed, status={:?}",
2725 DisplayAddress(addr),
2726 status
2727 );
2728 }
2729 }
2730 }
2731
phone_state_change(&mut self, number: String)2732 fn phone_state_change(&mut self, number: String) {
2733 for (addr, state) in self.hfp_states.iter() {
2734 if *state != BthfConnectionState::SlcConnected {
2735 continue;
2736 }
2737 debug!(
2738 "[{}]: Phone state change state={:?} number={}",
2739 DisplayAddress(addr),
2740 self.phone_state,
2741 number
2742 );
2743 let status = self.hfp.phone_state_change(self.phone_state, &number, *addr);
2744 if status != BtStatus::Success {
2745 warn!(
2746 "[{}]: Device status notification failed, status={:?}",
2747 DisplayAddress(addr),
2748 status
2749 );
2750 }
2751 }
2752 }
2753
2754 // Returns the minimum unoccupied index starting from 1.
new_call_index(&self) -> i322755 fn new_call_index(&self) -> i32 {
2756 (1..)
2757 .find(|&index| self.call_list.iter().all(|x| x.index != index))
2758 .expect("There must be an unoccupied index")
2759 }
2760
simple_at_response(&mut self, ok: bool, addr: RawAddress)2761 fn simple_at_response(&mut self, ok: bool, addr: RawAddress) {
2762 let status = self.hfp.simple_at_response(ok, addr);
2763 if status != BtStatus::Success {
2764 warn!("[{}]: AT response failed, status={:?}", DisplayAddress(&addr), status);
2765 }
2766 }
2767
incoming_call_impl(&mut self, number: String) -> bool2768 fn incoming_call_impl(&mut self, number: String) -> bool {
2769 if self.phone_state.state != CallState::Idle {
2770 return false;
2771 }
2772
2773 if self.phone_state.num_active > 0 {
2774 return false;
2775 }
2776
2777 self.call_list.push(CallInfo {
2778 index: self.new_call_index(),
2779 dir_incoming: true,
2780 state: CallState::Incoming,
2781 number: number.clone(),
2782 });
2783 self.phone_state.state = CallState::Incoming;
2784 self.phone_state_change(number);
2785 self.try_a2dp_suspend();
2786 true
2787 }
2788
answer_call_impl(&mut self) -> bool2789 fn answer_call_impl(&mut self) -> bool {
2790 if self.phone_state.state == CallState::Idle {
2791 return false;
2792 }
2793 // There must be exactly one incoming/dialing call in the list.
2794 for c in self.call_list.iter_mut() {
2795 match c.state {
2796 CallState::Incoming | CallState::Dialing | CallState::Alerting => {
2797 c.state = CallState::Active;
2798 break;
2799 }
2800 _ => {}
2801 }
2802 }
2803 self.phone_state.state = CallState::Idle;
2804 self.phone_state.num_active += 1;
2805
2806 self.phone_state_change("".into());
2807
2808 if self.mps_qualification_enabled {
2809 // Find a connected HFP and try to establish an SCO.
2810 if let Some(addr) = self.hfp_states.iter().find_map(|(addr, state)| {
2811 if *state == BthfConnectionState::SlcConnected {
2812 Some(addr)
2813 } else {
2814 None
2815 }
2816 }) {
2817 info!("Start SCO call due to call answered");
2818 self.start_sco_call_impl(*addr, false, HfpCodecBitId::NONE);
2819 }
2820 }
2821
2822 true
2823 }
2824
hangup_call_impl(&mut self) -> bool2825 fn hangup_call_impl(&mut self) -> bool {
2826 if !self.phone_ops_enabled && !self.mps_qualification_enabled {
2827 return false;
2828 }
2829
2830 match self.phone_state.state {
2831 CallState::Idle if self.phone_state.num_active > 0 => {
2832 self.phone_state.num_active -= 1;
2833 }
2834 CallState::Incoming | CallState::Dialing | CallState::Alerting => {
2835 self.phone_state.state = CallState::Idle;
2836 }
2837 _ => return false,
2838 }
2839 // At this point, there must be exactly one incoming/dialing/alerting/active call to be
2840 // removed.
2841 self.call_list.retain(|x| match x.state {
2842 CallState::Active | CallState::Incoming | CallState::Dialing | CallState::Alerting => {
2843 false
2844 }
2845 _ => true,
2846 });
2847
2848 self.phone_state_change("".into());
2849 self.try_a2dp_resume();
2850
2851 true
2852 }
2853
dialing_call_impl(&mut self, number: String, addr: Option<RawAddress>) -> bool2854 fn dialing_call_impl(&mut self, number: String, addr: Option<RawAddress>) -> bool {
2855 if self.phone_state.num_active > 0 || self.phone_state.state != CallState::Idle {
2856 if let Some(addr) = addr {
2857 self.simple_at_response(false, addr);
2858 warn!("[{}]: Unexpected dialing command from HF", DisplayAddress(&addr));
2859 }
2860 return false;
2861 }
2862
2863 self.call_list.push(CallInfo {
2864 index: self.new_call_index(),
2865 dir_incoming: false,
2866 state: CallState::Dialing,
2867 number: number.clone(),
2868 });
2869 self.phone_state.state = CallState::Dialing;
2870
2871 if let Some(addr) = addr {
2872 self.simple_at_response(true, addr);
2873 warn!("[{}]: Unexpected dialing command from HF", DisplayAddress(&addr));
2874 }
2875
2876 // Inform libbluetooth that the state has changed to dialing.
2877 self.phone_state_change("".into());
2878 self.try_a2dp_suspend();
2879 // Change to alerting state and inform libbluetooth.
2880 self.dialing_to_alerting();
2881 true
2882 }
2883
dialing_to_alerting(&mut self) -> bool2884 fn dialing_to_alerting(&mut self) -> bool {
2885 if !(self.phone_ops_enabled || self.mps_qualification_enabled)
2886 || self.phone_state.state != CallState::Dialing
2887 {
2888 return false;
2889 }
2890 for c in self.call_list.iter_mut() {
2891 if c.state == CallState::Dialing {
2892 c.state = CallState::Alerting;
2893 break;
2894 }
2895 }
2896 self.phone_state.state = CallState::Alerting;
2897 self.phone_state_change("".into());
2898 true
2899 }
2900
release_held_impl(&mut self, addr: Option<RawAddress>) -> bool2901 fn release_held_impl(&mut self, addr: Option<RawAddress>) -> bool {
2902 if self.phone_state.state != CallState::Idle {
2903 if let Some(addr) = addr {
2904 // Respond ERROR to the HF which sent the command.
2905 self.simple_at_response(false, addr);
2906 }
2907 return false;
2908 }
2909 self.call_list.retain(|x| x.state != CallState::Held);
2910 self.phone_state.num_held = 0;
2911
2912 if let Some(addr) = addr {
2913 // This should be called before calling phone_state_change.
2914 self.simple_at_response(true, addr);
2915 }
2916 // Success means the call state has changed. Inform libbluetooth.
2917 self.phone_state_change("".into());
2918 true
2919 }
2920
release_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool2921 fn release_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool {
2922 self.call_list.retain(|x| x.state != CallState::Active);
2923 self.phone_state.num_active = 0;
2924 // Activate the first held call
2925 if self.phone_state.state != CallState::Idle {
2926 if let Some(addr) = addr {
2927 // Respond ERROR to the HF which sent the command.
2928 self.simple_at_response(false, addr);
2929 }
2930 return false;
2931 }
2932 for c in self.call_list.iter_mut() {
2933 if c.state == CallState::Held {
2934 c.state = CallState::Active;
2935 self.phone_state.num_held -= 1;
2936 self.phone_state.num_active += 1;
2937 break;
2938 }
2939 }
2940 if let Some(addr) = addr {
2941 // This should be called before calling phone_state_change.
2942 self.simple_at_response(true, addr);
2943 }
2944 // Success means the call state has changed. Inform libbluetooth.
2945 self.phone_state_change("".into());
2946 true
2947 }
2948
hold_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool2949 fn hold_active_accept_held_impl(&mut self, addr: Option<RawAddress>) -> bool {
2950 if self.phone_state.state != CallState::Idle {
2951 if let Some(addr) = addr {
2952 // Respond ERROR to the HF which sent the command.
2953 self.simple_at_response(false, addr);
2954 }
2955 return false;
2956 }
2957 self.phone_state.num_held += self.phone_state.num_active;
2958 self.phone_state.num_active = 0;
2959
2960 for c in self.call_list.iter_mut() {
2961 match c.state {
2962 // Activate at most one held call
2963 CallState::Held if self.phone_state.num_active == 0 => {
2964 c.state = CallState::Active;
2965 self.phone_state.num_held -= 1;
2966 self.phone_state.num_active = 1;
2967 }
2968 CallState::Active => {
2969 c.state = CallState::Held;
2970 }
2971 _ => {}
2972 }
2973 }
2974 if let Some(addr) = addr {
2975 // This should be called before calling phone_state_change.
2976 self.simple_at_response(true, addr);
2977 }
2978 // Success means the call state has changed. Inform libbluetooth.
2979 self.phone_state_change("".into());
2980 true
2981 }
2982
2983 // Per MPS v1.0 (Multi-Profile Specification), disconnecting or failing to connect
2984 // a profile should not affect the others.
2985 // Allow partial profiles connection during qualification (MPS qualification mode is enabled).
is_complete_profiles_required(&self) -> bool2986 fn is_complete_profiles_required(&self) -> bool {
2987 !self.mps_qualification_enabled
2988 }
2989
2990 // Force the media enters the FullyConnected state and then triggers a retry.
2991 // When this function is used for qualification as a replacement of normal retry,
2992 // PTS could initiate the connection of the necessary profiles, and Floss should
2993 // notify CRAS of the new audio device regardless of the unconnected profiles.
2994 // Still retry in the end because some test cases require that.
force_enter_connected(&mut self, addr: RawAddress)2995 fn force_enter_connected(&mut self, addr: RawAddress) {
2996 self.device_states.lock().unwrap().insert(addr, DeviceConnectionStates::FullyConnected);
2997 self.notify_media_capability_updated(addr);
2998 self.connect(addr);
2999 }
add_player(&mut self, name: String, browsing_supported: bool)3000 pub fn add_player(&mut self, name: String, browsing_supported: bool) {
3001 self.avrcp.add_player(&name, browsing_supported);
3002 }
3003
3004 // This function determines if it's safe to send a +CIEV command to an HFP device when SCO starts.
3005
3006 // The +CIEV command should NOT be sent if:
3007 // - MPS qualification mode is enabled, as it may cause qualification failures.
3008 // - Uhid device is open, as it may conflict with ongoing telephony operations.
3009
3010 // The +CIEV command is safe to send if:
3011 // - Both MPS qualification and Bluetooth telephony are disabled.
3012 // - Uhid device is closed, preventing any telephony conflicts.
3013 // - The headset is listed in interop_database.conf, indicating it requires +CIEV for audio.
should_insert_call_when_sco_start(&self, address: RawAddress) -> bool3014 fn should_insert_call_when_sco_start(&self, address: RawAddress) -> bool {
3015 if self.mps_qualification_enabled {
3016 return false;
3017 }
3018 if !self.phone_ops_enabled {
3019 return true;
3020 }
3021
3022 match self.uhid.get(&address) {
3023 Some(uhid) => {
3024 if !uhid.is_open {
3025 return true;
3026 }
3027 }
3028 None => {
3029 return true;
3030 }
3031 };
3032
3033 interop_insert_call_when_sco_start(address)
3034 }
3035 // Places an active call into the call list and triggers a headset update (+CIEV).
3036 // Preconditions:
3037 // - No active calls in progress (phone_state.num_active == 0)
3038 // - Phone state is idle (phone_state.state == CallState::Idle)
place_active_call(&mut self)3039 fn place_active_call(&mut self) {
3040 if self.phone_state.num_active != 0 {
3041 warn!("Unexpected usage. phone_state.num_active can only be 0 when calling place_active_call");
3042 return;
3043 }
3044
3045 if self.phone_state.state != CallState::Idle {
3046 warn!("Unexpected usage. phone_state.state can only be idle when calling place_active_call");
3047 return;
3048 }
3049
3050 self.dialing_call_impl("".into(), None);
3051 self.answer_call_impl();
3052 }
3053
get_group_devices(&self, group_id: i32) -> HashSet<RawAddress>3054 pub fn get_group_devices(&self, group_id: i32) -> HashSet<RawAddress> {
3055 match self.le_audio_groups.get(&group_id) {
3056 Some(g) => g.devices.clone(),
3057 _ => HashSet::new(),
3058 }
3059 }
3060
get_group_id(&self, addr: RawAddress) -> i323061 pub fn get_group_id(&self, addr: RawAddress) -> i32 {
3062 *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID)
3063 }
3064 }
3065
get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher3066 fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher {
3067 A2dpCallbacksDispatcher { dispatch: make_message_dispatcher(tx, Message::A2dp) }
3068 }
3069
get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher3070 fn get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher {
3071 AvrcpCallbacksDispatcher { dispatch: make_message_dispatcher(tx, Message::Avrcp) }
3072 }
3073
get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher3074 fn get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher {
3075 HfpCallbacksDispatcher { dispatch: make_message_dispatcher(tx, Message::Hfp) }
3076 }
3077
get_le_audio_dispatcher(tx: Sender<Message>) -> LeAudioClientCallbacksDispatcher3078 fn get_le_audio_dispatcher(tx: Sender<Message>) -> LeAudioClientCallbacksDispatcher {
3079 LeAudioClientCallbacksDispatcher {
3080 dispatch: make_message_dispatcher(tx, Message::LeAudioClient),
3081 }
3082 }
3083
get_vc_dispatcher(tx: Sender<Message>) -> VolumeControlCallbacksDispatcher3084 fn get_vc_dispatcher(tx: Sender<Message>) -> VolumeControlCallbacksDispatcher {
3085 VolumeControlCallbacksDispatcher {
3086 dispatch: make_message_dispatcher(tx, Message::VolumeControl),
3087 }
3088 }
3089
get_csis_dispatcher(tx: Sender<Message>) -> CsisClientCallbacksDispatcher3090 fn get_csis_dispatcher(tx: Sender<Message>) -> CsisClientCallbacksDispatcher {
3091 CsisClientCallbacksDispatcher { dispatch: make_message_dispatcher(tx, Message::CsisClient) }
3092 }
3093
3094 impl IBluetoothMedia for BluetoothMedia {
register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool3095 fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool {
3096 let _id = self.callbacks.lock().unwrap().add_callback(callback);
3097 true
3098 }
3099
initialize(&mut self) -> bool3100 fn initialize(&mut self) -> bool {
3101 if self.initialized {
3102 return false;
3103 }
3104 self.initialized = true;
3105
3106 self.is_le_audio_only_enabled =
3107 features::is_feature_enabled("CrOSLateBootBluetoothAudioLEAudioOnly").unwrap_or(false);
3108
3109 // A2DP
3110 let a2dp_dispatcher = get_a2dp_dispatcher(self.tx.clone());
3111 self.a2dp.initialize(a2dp_dispatcher);
3112
3113 // AVRCP
3114 let avrcp_dispatcher = get_avrcp_dispatcher(self.tx.clone());
3115 self.avrcp.initialize(avrcp_dispatcher);
3116
3117 // HFP
3118 let hfp_dispatcher = get_hfp_dispatcher(self.tx.clone());
3119 self.hfp.initialize(hfp_dispatcher);
3120
3121 // LEA
3122 let le_audio_dispatcher = get_le_audio_dispatcher(self.tx.clone());
3123 self.le_audio.initialize(le_audio_dispatcher);
3124
3125 // VC
3126 let vc_dispatcher = get_vc_dispatcher(self.tx.clone());
3127 self.vc.initialize(vc_dispatcher);
3128
3129 // CSIS
3130 let csis_dispatcher = get_csis_dispatcher(self.tx.clone());
3131 self.csis.initialize(csis_dispatcher);
3132
3133 // TODO(b/284811956) A2DP needs to be enabled before AVRCP otherwise AVRCP gets memset'd.
3134 // Iterate the delay_enable_profiles hashmap directly when this is fixed.
3135 for profile in MEDIA_PROFILE_ENABLE_ORDER {
3136 if self.delay_enable_profiles.contains(&profile) {
3137 self.enable_profile(&profile);
3138 }
3139 }
3140 let api_tx = self.api_tx.clone();
3141 tokio::spawn(async move {
3142 // TODO(b:300202052) make sure media interface is exposed after initialized
3143 let _ = api_tx.send(APIMessage::IsReady(BluetoothAPI::Media)).await;
3144 });
3145 true
3146 }
3147
connect_lea_group_by_member_address(&mut self, addr: RawAddress)3148 fn connect_lea_group_by_member_address(&mut self, addr: RawAddress) {
3149 // Note that at this point the scanning of profiles may be incomplete,
3150 // TODO(b/335780769): connect to available profiles and ensure
3151 // this function is invoked whenever there is an incremental
3152 // discovery of LE audio profiles.
3153 for profile in MEDIA_LE_AUDIO_PROFILES {
3154 match profile {
3155 Profile::LeAudio => {
3156 self.connect_lea(addr);
3157 }
3158 Profile::VolumeControl => {
3159 self.connect_vc(addr);
3160 }
3161 Profile::CoordinatedSet => {
3162 self.connect_csis(addr);
3163 }
3164 _ => {}
3165 }
3166 }
3167 }
3168
disconnect_lea_group_by_member_address(&mut self, addr: RawAddress)3169 fn disconnect_lea_group_by_member_address(&mut self, addr: RawAddress) {
3170 let group_id = self.get_group_id(addr);
3171 if group_id == LEA_UNKNOWN_GROUP_ID {
3172 warn!(
3173 "disconnect_lea_group_by_member_address: [{}]: address belongs to no group",
3174 DisplayAddress(&addr)
3175 );
3176 return;
3177 }
3178
3179 let group = self.le_audio_groups.entry(group_id).or_default().clone();
3180
3181 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3182
3183 info!(
3184 "disconnect_lea_group_by_member_address: [{}]: available profiles: {:?}.",
3185 DisplayAddress(&addr),
3186 available_profiles
3187 );
3188
3189 for &member_addr in group.devices.iter() {
3190 for profile in self.adapter_get_le_audio_profiles(addr) {
3191 match profile {
3192 Profile::LeAudio => {
3193 self.disconnect_lea(member_addr);
3194 }
3195 Profile::VolumeControl => {
3196 self.disconnect_vc(member_addr);
3197 }
3198 Profile::CoordinatedSet => {
3199 self.disconnect_csis(member_addr);
3200 }
3201 _ => {}
3202 }
3203 }
3204 }
3205 }
3206
connect_lea(&mut self, addr: RawAddress)3207 fn connect_lea(&mut self, addr: RawAddress) {
3208 if !self.is_le_audio_only_enabled {
3209 warn!("connect_lea: LeAudioEnableLeAudioOnly is not set");
3210 return;
3211 }
3212
3213 if *self.le_audio_states.get(&addr).unwrap_or(&BtLeAudioConnectionState::Disconnected)
3214 == BtLeAudioConnectionState::Connected
3215 {
3216 info!("connect_lea: already connected.");
3217 return;
3218 }
3219
3220 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3221
3222 info!(
3223 "connect_lea: [{}]: connecting, available profiles: {:?}.",
3224 DisplayAddress(&addr),
3225 available_profiles
3226 );
3227
3228 self.le_audio.set_enable_state(addr, true);
3229 self.le_audio.connect(addr);
3230 }
3231
disconnect_lea(&mut self, addr: RawAddress)3232 fn disconnect_lea(&mut self, addr: RawAddress) {
3233 if *self.le_audio_states.get(&addr).unwrap_or(&BtLeAudioConnectionState::Disconnected)
3234 == BtLeAudioConnectionState::Disconnected
3235 {
3236 info!("disconnect_lea: [{}]: already disconnected", DisplayAddress(&addr));
3237 return;
3238 }
3239
3240 info!("disconnect_lea: [{}]: disconnecting", DisplayAddress(&addr));
3241
3242 self.le_audio.set_enable_state(addr, false);
3243 self.le_audio.disconnect(addr);
3244 }
3245
connect_vc(&mut self, addr: RawAddress)3246 fn connect_vc(&mut self, addr: RawAddress) {
3247 if !self.is_le_audio_only_enabled {
3248 warn!("connect_vc: LeAudioEnableLeAudioOnly is not set");
3249 return;
3250 }
3251
3252 if *self.vc_states.get(&addr).unwrap_or(&BtVcConnectionState::Disconnected)
3253 == BtVcConnectionState::Connected
3254 {
3255 info!("connect_vc: already connected");
3256 return;
3257 }
3258
3259 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3260
3261 info!(
3262 "connect_vc: [{}]: connecting, available profiles: {:?}.",
3263 DisplayAddress(&addr),
3264 available_profiles
3265 );
3266
3267 self.vc.connect(addr);
3268 }
3269
disconnect_vc(&mut self, addr: RawAddress)3270 fn disconnect_vc(&mut self, addr: RawAddress) {
3271 if *self.vc_states.get(&addr).unwrap_or(&BtVcConnectionState::Disconnected)
3272 == BtVcConnectionState::Disconnected
3273 {
3274 info!("disconnect_vc: already disconnected");
3275 return;
3276 }
3277
3278 info!("disconnect_vc: [{}]: disconnecting", DisplayAddress(&addr));
3279
3280 self.vc.disconnect(addr);
3281 }
3282
connect_csis(&mut self, addr: RawAddress)3283 fn connect_csis(&mut self, addr: RawAddress) {
3284 if !self.is_le_audio_only_enabled {
3285 warn!("connect_csis: LeAudioEnableLeAudioOnly is not set");
3286 return;
3287 }
3288
3289 if *self.csis_states.get(&addr).unwrap_or(&BtCsisConnectionState::Disconnected)
3290 == BtCsisConnectionState::Connected
3291 {
3292 info!("connect_csis: already connected");
3293 return;
3294 }
3295
3296 let available_profiles = self.adapter_get_le_audio_profiles(addr);
3297
3298 info!(
3299 "connect_csis: [{}]: connecting, available profiles: {:?}.",
3300 DisplayAddress(&addr),
3301 available_profiles
3302 );
3303
3304 self.csis.connect(addr);
3305 }
3306
disconnect_csis(&mut self, addr: RawAddress)3307 fn disconnect_csis(&mut self, addr: RawAddress) {
3308 if *self.csis_states.get(&addr).unwrap_or(&BtCsisConnectionState::Disconnected)
3309 == BtCsisConnectionState::Disconnected
3310 {
3311 info!("disconnect_csis: already disconnected");
3312 return;
3313 }
3314
3315 info!("disconnect_csis: [{}]: disconnecting", DisplayAddress(&addr));
3316
3317 self.csis.disconnect(addr);
3318 }
3319
connect(&mut self, addr: RawAddress)3320 fn connect(&mut self, addr: RawAddress) {
3321 if self.is_le_audio_only_enabled {
3322 warn!("connect: LeAudioEnableLeAudioOnly is set");
3323 return;
3324 }
3325
3326 let available_profiles = self.adapter_get_classic_audio_profiles(addr);
3327
3328 info!(
3329 "[{}]: Connecting to device, available profiles: {:?}.",
3330 DisplayAddress(&addr),
3331 available_profiles
3332 );
3333
3334 let connected_profiles = self.connected_profiles.get(&addr).cloned().unwrap_or_default();
3335
3336 // Sort here so the order of connection is always consistent
3337 let missing_profiles =
3338 available_profiles.difference(&connected_profiles).sorted().collect::<Vec<_>>();
3339
3340 // Connect the profiles one-by-one so it won't stuck at the lower layer.
3341 // Therefore, just connect to one profile for now.
3342 // connect() will be called again after the first profile is successfully connected.
3343 let mut is_connect = false;
3344 for profile in missing_profiles {
3345 match profile {
3346 Profile::A2dpSink => {
3347 metrics::profile_connection_state_changed(
3348 addr,
3349 Profile::A2dpSink as u32,
3350 BtStatus::Success,
3351 BtavConnectionState::Connecting as u32,
3352 );
3353 let status = self.a2dp.connect(addr);
3354 if BtStatus::Success != status {
3355 metrics::profile_connection_state_changed(
3356 addr,
3357 Profile::A2dpSink as u32,
3358 status,
3359 BtavConnectionState::Disconnected as u32,
3360 );
3361 } else {
3362 is_connect = true;
3363 break;
3364 }
3365 }
3366 Profile::Hfp => {
3367 metrics::profile_connection_state_changed(
3368 addr,
3369 Profile::Hfp as u32,
3370 BtStatus::Success,
3371 BtavConnectionState::Connecting as u32,
3372 );
3373 let status = self.hfp.connect(addr);
3374 if BtStatus::Success != status {
3375 metrics::profile_connection_state_changed(
3376 addr,
3377 Profile::Hfp as u32,
3378 status,
3379 BthfConnectionState::Disconnected as u32,
3380 );
3381 } else {
3382 is_connect = true;
3383 break;
3384 }
3385 }
3386 Profile::AvrcpController => {
3387 // Fluoride will resolve AVRCP as a part of A2DP connection request.
3388 // Explicitly connect to it only when it is considered missing, and don't
3389 // bother about it when A2DP is not connected.
3390 if !connected_profiles.contains(&Profile::A2dpSink) {
3391 continue;
3392 }
3393
3394 metrics::profile_connection_state_changed(
3395 addr,
3396 Profile::AvrcpController as u32,
3397 BtStatus::Success,
3398 BtavConnectionState::Connecting as u32,
3399 );
3400 self.avrcp_states.insert(addr, BtavConnectionState::Connecting);
3401 let status = self.avrcp.connect(addr);
3402 if BtStatus::Success != status {
3403 // Reset direction to unknown.
3404 self.avrcp_states.remove(&addr);
3405 metrics::profile_connection_state_changed(
3406 addr,
3407 Profile::AvrcpController as u32,
3408 status,
3409 BtavConnectionState::Disconnected as u32,
3410 );
3411 } else {
3412 is_connect = true;
3413 break;
3414 }
3415 }
3416 _ => warn!("Unknown profile: {:?}", profile),
3417 }
3418 }
3419
3420 if is_connect {
3421 let mut tasks = self.fallback_tasks.lock().unwrap();
3422 let mut states = self.device_states.lock().unwrap();
3423 if let std::collections::hash_map::Entry::Vacant(e) = tasks.entry(addr) {
3424 states.insert(addr, DeviceConnectionStates::Initiating);
3425
3426 let fallback_tasks = self.fallback_tasks.clone();
3427 let device_states = self.device_states.clone();
3428 let now_ts = Instant::now();
3429 let task = topstack::get_runtime().spawn(async move {
3430 sleep(Duration::from_secs(CONNECT_AS_INITIATOR_TIMEOUT_SEC)).await;
3431
3432 // If here the task is not yet aborted, probably connection is failed,
3433 // therefore here we release the states. Even if later the connection is
3434 // actually successful, we will just treat this as if the connection is
3435 // initiated by the peer and will reconnect the missing profiles after
3436 // some time, so it's safe.
3437 {
3438 device_states.lock().unwrap().remove(&addr);
3439 fallback_tasks.lock().unwrap().remove(&addr);
3440 }
3441 });
3442 e.insert(Some((task, now_ts)));
3443 }
3444 }
3445 }
3446
is_initialized(&self) -> bool3447 fn is_initialized(&self) -> bool {
3448 self.initialized
3449 }
3450
cleanup(&mut self) -> bool3451 fn cleanup(&mut self) -> bool {
3452 self.cleanup()
3453 }
3454
3455 // This may not disconnect all media profiles at once, but once the stack
3456 // is notified of the disconnection callback, `disconnect_device` will be
3457 // invoked as necessary to ensure the device is removed.
disconnect(&mut self, addr: RawAddress)3458 fn disconnect(&mut self, addr: RawAddress) {
3459 if self.is_le_audio_only_enabled {
3460 warn!("LeAudioEnableLeAudioOnly is set");
3461 return;
3462 }
3463
3464 let connected_profiles = match self.connected_profiles.get(&addr) {
3465 Some(profiles) => profiles,
3466 None => {
3467 warn!(
3468 "[{}]: Ignoring disconnection request since there is no connected profile.",
3469 DisplayAddress(&addr)
3470 );
3471 return;
3472 }
3473 };
3474
3475 for profile in connected_profiles {
3476 match profile {
3477 Profile::A2dpSink => {
3478 // Some headsets (b/278963515) will try reconnecting to A2DP
3479 // when HFP is running but (requested to be) disconnected.
3480 // TODO: Remove this workaround once proper fix lands.
3481 if connected_profiles.contains(&Profile::Hfp) {
3482 continue;
3483 }
3484 metrics::profile_connection_state_changed(
3485 addr,
3486 Profile::A2dpSink as u32,
3487 BtStatus::Success,
3488 BtavConnectionState::Disconnecting as u32,
3489 );
3490 let status = self.a2dp.disconnect(addr);
3491 if BtStatus::Success != status {
3492 metrics::profile_connection_state_changed(
3493 addr,
3494 Profile::A2dpSource as u32,
3495 status,
3496 BtavConnectionState::Disconnected as u32,
3497 );
3498 }
3499 }
3500 Profile::Hfp => {
3501 metrics::profile_connection_state_changed(
3502 addr,
3503 Profile::Hfp as u32,
3504 BtStatus::Success,
3505 BthfConnectionState::Disconnecting as u32,
3506 );
3507 let status = self.hfp.disconnect(addr);
3508 if BtStatus::Success != status {
3509 metrics::profile_connection_state_changed(
3510 addr,
3511 Profile::Hfp as u32,
3512 status,
3513 BthfConnectionState::Disconnected as u32,
3514 );
3515 }
3516 }
3517 Profile::AvrcpController => {
3518 if connected_profiles.contains(&Profile::A2dpSink) {
3519 continue;
3520 }
3521 metrics::profile_connection_state_changed(
3522 addr,
3523 Profile::AvrcpController as u32,
3524 BtStatus::Success,
3525 BtavConnectionState::Disconnecting as u32,
3526 );
3527 self.avrcp_states.insert(addr, BtavConnectionState::Disconnecting);
3528 let status = self.avrcp.disconnect(addr);
3529 if BtStatus::Success != status {
3530 // Reset direction to unknown.
3531 self.avrcp_states.remove(&addr);
3532 metrics::profile_connection_state_changed(
3533 addr,
3534 Profile::AvrcpController as u32,
3535 status,
3536 BtavConnectionState::Disconnected as u32,
3537 );
3538 }
3539 }
3540 _ => warn!("Unknown profile: {:?}", profile),
3541 }
3542 }
3543 }
3544
set_active_device(&mut self, addr: RawAddress)3545 fn set_active_device(&mut self, addr: RawAddress) {
3546 match self.a2dp_states.get(&addr) {
3547 Some(BtavConnectionState::Connected) => {
3548 self.a2dp.set_active_device(addr);
3549 self.uinput.set_active_device(addr.to_string());
3550 }
3551 _ => warn!("[{}] Not connected or disconnected A2DP address", DisplayAddress(&addr)),
3552 };
3553 }
3554
reset_active_device(&mut self)3555 fn reset_active_device(&mut self) {
3556 // During MPS tests, there might be some A2DP stream manipulation unexpected to CRAS.
3557 // CRAS would then attempt to reset the active device. Ignore it during test.
3558 if !self.is_complete_profiles_required() {
3559 return;
3560 }
3561
3562 self.a2dp.set_active_device(RawAddress::empty());
3563 self.uinput.set_active_device(RawAddress::empty().to_string());
3564 }
3565
set_hfp_active_device(&mut self, addr: RawAddress)3566 fn set_hfp_active_device(&mut self, addr: RawAddress) {
3567 if self.hfp_states.get(&addr) == Some(&BthfConnectionState::SlcConnected) {
3568 self.hfp.set_active_device(addr);
3569 } else {
3570 warn!("[{}] Not connected or disconnected HFP address", DisplayAddress(&addr));
3571 }
3572 }
3573
set_audio_config( &mut self, addr: RawAddress, codec_type: A2dpCodecIndex, sample_rate: A2dpCodecSampleRate, bits_per_sample: A2dpCodecBitsPerSample, channel_mode: A2dpCodecChannelMode, ) -> bool3574 fn set_audio_config(
3575 &mut self,
3576 addr: RawAddress,
3577 codec_type: A2dpCodecIndex,
3578 sample_rate: A2dpCodecSampleRate,
3579 bits_per_sample: A2dpCodecBitsPerSample,
3580 channel_mode: A2dpCodecChannelMode,
3581 ) -> bool {
3582 if self.a2dp_states.get(&addr).is_none() {
3583 warn!(
3584 "[{}]: Ignore set config event for unconnected or disconnected A2DP device",
3585 DisplayAddress(&addr)
3586 );
3587 return false;
3588 }
3589
3590 let caps = self.a2dp_caps.get(&addr).unwrap_or(&Vec::new()).to_vec();
3591
3592 for cap in &caps {
3593 if A2dpCodecIndex::from(cap.codec_type) == codec_type {
3594 if (A2dpCodecSampleRate::from_bits(cap.sample_rate).unwrap() & sample_rate)
3595 != sample_rate
3596 {
3597 warn!("Unsupported sample rate {:?}", sample_rate);
3598 return false;
3599 }
3600 if (A2dpCodecBitsPerSample::from_bits(cap.bits_per_sample).unwrap()
3601 & bits_per_sample)
3602 != bits_per_sample
3603 {
3604 warn!("Unsupported bit depth {:?}", bits_per_sample);
3605 return false;
3606 }
3607 if (A2dpCodecChannelMode::from_bits(cap.channel_mode).unwrap() & channel_mode)
3608 != channel_mode
3609 {
3610 warn!("Unsupported channel mode {:?}", channel_mode);
3611 return false;
3612 }
3613
3614 let config = vec![A2dpCodecConfig {
3615 codec_type: codec_type as i32,
3616 codec_priority: A2dpCodecPriority::Highest as i32,
3617 sample_rate: sample_rate.bits(),
3618 bits_per_sample: bits_per_sample.bits(),
3619 channel_mode: channel_mode.bits(),
3620 ..Default::default()
3621 }];
3622
3623 self.a2dp.config_codec(addr, config);
3624 return true;
3625 }
3626 }
3627
3628 warn!("Unsupported codec type {:?}", codec_type);
3629 false
3630 }
3631
set_volume(&mut self, volume: u8)3632 fn set_volume(&mut self, volume: u8) {
3633 // Guard the range 0-127 by the try_from cast from u8 to i8.
3634 let vol = match i8::try_from(volume) {
3635 Ok(val) => val,
3636 _ => {
3637 warn!("Ignore invalid volume {}", volume);
3638 return;
3639 }
3640 };
3641
3642 // There is always no more than one active media connection, which
3643 // implies only one address is connected with AVRCP.
3644 for (addr, profiles) in &self.connected_profiles {
3645 if profiles.contains(&Profile::AvrcpController) {
3646 self.avrcp.set_volume(*addr, vol);
3647 }
3648 }
3649 }
3650
set_hfp_volume(&mut self, volume: u8, addr: RawAddress)3651 fn set_hfp_volume(&mut self, volume: u8, addr: RawAddress) {
3652 let vol = match i8::try_from(volume) {
3653 Ok(val) if val <= 15 => val,
3654 _ => {
3655 warn!("[{}]: Ignore invalid volume {}", DisplayAddress(&addr), volume);
3656 return;
3657 }
3658 };
3659
3660 if self.hfp_states.get(&addr).is_none() {
3661 warn!(
3662 "[{}]: Ignore volume event for unconnected or disconnected HFP device",
3663 DisplayAddress(&addr)
3664 );
3665 return;
3666 }
3667
3668 self.hfp.set_volume(vol, addr);
3669 }
3670
start_audio_request(&mut self, connection_listener: File) -> bool3671 fn start_audio_request(&mut self, connection_listener: File) -> bool {
3672 if self.a2dp_audio_connection_listener.is_some() {
3673 warn!("start_audio_request: replacing an unresolved listener");
3674 }
3675
3676 self.a2dp_audio_connection_listener = Some(connection_listener);
3677 self.start_audio_request_impl()
3678 }
3679
stop_audio_request(&mut self, connection_listener: File)3680 fn stop_audio_request(&mut self, connection_listener: File) {
3681 debug!("Stop audio request");
3682
3683 if self.a2dp_audio_connection_listener.is_some() {
3684 warn!("stop_audio_request: replacing an unresolved listener");
3685 }
3686
3687 self.a2dp_audio_connection_listener = Some(connection_listener);
3688
3689 self.a2dp.stop_audio_request();
3690 }
3691
start_sco_call( &mut self, address: RawAddress, sco_offload: bool, disabled_codecs: HfpCodecBitId, connection_listener: File, ) -> bool3692 fn start_sco_call(
3693 &mut self,
3694 address: RawAddress,
3695 sco_offload: bool,
3696 disabled_codecs: HfpCodecBitId,
3697 connection_listener: File,
3698 ) -> bool {
3699 if self.hfp_audio_connection_listener.is_some() {
3700 warn!("start_sco_call: replacing an unresolved listener");
3701 }
3702
3703 self.hfp_audio_connection_listener = Some(connection_listener);
3704 self.start_sco_call_impl(address, sco_offload, disabled_codecs)
3705 }
3706
stop_sco_call(&mut self, address: RawAddress, listener: File)3707 fn stop_sco_call(&mut self, address: RawAddress, listener: File) {
3708 if self.hfp_audio_connection_listener.is_some() {
3709 warn!("stop_sco_call: replacing an unresolved listener");
3710 }
3711
3712 self.hfp_audio_connection_listener = Some(listener);
3713 self.stop_sco_call_impl(address)
3714 }
3715
get_a2dp_audio_started(&mut self, addr: RawAddress) -> bool3716 fn get_a2dp_audio_started(&mut self, addr: RawAddress) -> bool {
3717 match self.a2dp_audio_state.get(&addr) {
3718 Some(BtavAudioState::Started) => true,
3719 _ => false,
3720 }
3721 }
3722
get_hfp_audio_final_codecs(&mut self, addr: RawAddress) -> u83723 fn get_hfp_audio_final_codecs(&mut self, addr: RawAddress) -> u8 {
3724 match self.hfp_audio_state.get(&addr) {
3725 Some(BthfAudioState::Connected) => match self.hfp_cap.get(&addr) {
3726 Some(caps)
3727 if (*caps & HfpCodecFormat::LC3_TRANSPARENT)
3728 == HfpCodecFormat::LC3_TRANSPARENT =>
3729 {
3730 HfpCodecBitId::LC3
3731 }
3732 Some(caps) if (*caps & HfpCodecFormat::MSBC) == HfpCodecFormat::MSBC => {
3733 HfpCodecBitId::MSBC
3734 }
3735 Some(caps)
3736 if (*caps & HfpCodecFormat::MSBC_TRANSPARENT)
3737 == HfpCodecFormat::MSBC_TRANSPARENT =>
3738 {
3739 HfpCodecBitId::MSBC
3740 }
3741 Some(caps) if (*caps & HfpCodecFormat::CVSD) == HfpCodecFormat::CVSD => {
3742 HfpCodecBitId::CVSD
3743 }
3744 _ => {
3745 warn!("hfp_cap not found, fallback to CVSD.");
3746 HfpCodecBitId::CVSD
3747 }
3748 },
3749 _ => HfpCodecBitId::NONE,
3750 }
3751 .try_into()
3752 .unwrap()
3753 }
3754
get_presentation_position(&mut self) -> PresentationPosition3755 fn get_presentation_position(&mut self) -> PresentationPosition {
3756 let position = self.a2dp.get_presentation_position();
3757 PresentationPosition {
3758 remote_delay_report_ns: position.remote_delay_report_ns,
3759 total_bytes_read: position.total_bytes_read,
3760 data_position_sec: position.data_position_sec,
3761 data_position_nsec: position.data_position_nsec,
3762 }
3763 }
3764
set_player_playback_status(&mut self, status: String)3765 fn set_player_playback_status(&mut self, status: String) {
3766 debug!("AVRCP received player playback status: {}", status);
3767 self.avrcp.set_playback_status(&status);
3768 }
set_player_position(&mut self, position_us: i64)3769 fn set_player_position(&mut self, position_us: i64) {
3770 debug!("AVRCP received player position: {}", position_us);
3771 self.avrcp.set_position(position_us);
3772 }
set_player_metadata(&mut self, metadata: PlayerMetadata)3773 fn set_player_metadata(&mut self, metadata: PlayerMetadata) {
3774 debug!("AVRCP received player metadata: {:?}", metadata);
3775 self.avrcp.set_metadata(&metadata);
3776 }
3777
trigger_debug_dump(&mut self)3778 fn trigger_debug_dump(&mut self) {
3779 self.hfp.debug_dump();
3780 }
3781
group_set_active(&mut self, group_id: i32)3782 fn group_set_active(&mut self, group_id: i32) {
3783 self.le_audio.group_set_active(group_id);
3784 }
3785
source_metadata_changed( &mut self, usage: BtLeAudioUsage, content_type: BtLeAudioContentType, gain: f64, ) -> bool3786 fn source_metadata_changed(
3787 &mut self,
3788 usage: BtLeAudioUsage,
3789 content_type: BtLeAudioContentType,
3790 gain: f64,
3791 ) -> bool {
3792 let data = vec![SourceMetadata { usage, content_type, gain }];
3793 self.le_audio.source_metadata_changed(data);
3794 true
3795 }
3796
sink_metadata_changed(&mut self, source: BtLeAudioSource, gain: f64) -> bool3797 fn sink_metadata_changed(&mut self, source: BtLeAudioSource, gain: f64) -> bool {
3798 let data = vec![SinkMetadata { source, gain }];
3799 self.le_audio.sink_metadata_changed(data);
3800 true
3801 }
3802
host_start_audio_request(&mut self) -> bool3803 fn host_start_audio_request(&mut self) -> bool {
3804 self.le_audio.host_start_audio_request()
3805 }
3806
host_stop_audio_request(&mut self)3807 fn host_stop_audio_request(&mut self) {
3808 self.le_audio.host_stop_audio_request();
3809 }
3810
peer_start_audio_request(&mut self) -> bool3811 fn peer_start_audio_request(&mut self) -> bool {
3812 self.le_audio.peer_start_audio_request()
3813 }
3814
peer_stop_audio_request(&mut self)3815 fn peer_stop_audio_request(&mut self) {
3816 self.le_audio.peer_stop_audio_request();
3817 }
3818
get_host_pcm_config(&mut self) -> BtLePcmConfig3819 fn get_host_pcm_config(&mut self) -> BtLePcmConfig {
3820 self.le_audio.get_host_pcm_config()
3821 }
3822
get_peer_pcm_config(&mut self) -> BtLePcmConfig3823 fn get_peer_pcm_config(&mut self) -> BtLePcmConfig {
3824 self.le_audio.get_peer_pcm_config()
3825 }
3826
get_host_stream_started(&mut self) -> BtLeStreamStartedStatus3827 fn get_host_stream_started(&mut self) -> BtLeStreamStartedStatus {
3828 self.le_audio.get_host_stream_started()
3829 }
3830
get_peer_stream_started(&mut self) -> BtLeStreamStartedStatus3831 fn get_peer_stream_started(&mut self) -> BtLeStreamStartedStatus {
3832 self.le_audio.get_peer_stream_started()
3833 }
3834
get_unicast_monitor_mode_status( &mut self, direction: BtLeAudioDirection, ) -> BtLeAudioUnicastMonitorModeStatus3835 fn get_unicast_monitor_mode_status(
3836 &mut self,
3837 direction: BtLeAudioDirection,
3838 ) -> BtLeAudioUnicastMonitorModeStatus {
3839 *self
3840 .le_audio_unicast_monitor_mode_status
3841 .get(&direction.into())
3842 .unwrap_or(&BtLeAudioUnicastMonitorModeStatus::StreamingSuspended)
3843 }
3844
get_group_stream_status(&mut self, group_id: i32) -> BtLeAudioGroupStreamStatus3845 fn get_group_stream_status(&mut self, group_id: i32) -> BtLeAudioGroupStreamStatus {
3846 if self.le_audio_groups.get(&group_id).is_none() {
3847 return BtLeAudioGroupStreamStatus::Idle;
3848 }
3849
3850 self.le_audio_groups.get(&group_id).unwrap().stream_status
3851 }
3852
get_group_status(&mut self, group_id: i32) -> BtLeAudioGroupStatus3853 fn get_group_status(&mut self, group_id: i32) -> BtLeAudioGroupStatus {
3854 if self.le_audio_groups.get(&group_id).is_none() {
3855 return BtLeAudioGroupStatus::Inactive;
3856 }
3857
3858 self.le_audio_groups.get(&group_id).unwrap().status
3859 }
3860
set_group_volume(&mut self, group_id: i32, volume: u8)3861 fn set_group_volume(&mut self, group_id: i32, volume: u8) {
3862 self.vc.set_volume(group_id, volume);
3863 }
3864 }
3865
3866 impl IBluetoothTelephony for BluetoothMedia {
register_telephony_callback( &mut self, callback: Box<dyn IBluetoothTelephonyCallback + Send>, ) -> bool3867 fn register_telephony_callback(
3868 &mut self,
3869 callback: Box<dyn IBluetoothTelephonyCallback + Send>,
3870 ) -> bool {
3871 let _id = self.telephony_callbacks.lock().unwrap().add_callback(callback);
3872 true
3873 }
3874
set_network_available(&mut self, network_available: bool)3875 fn set_network_available(&mut self, network_available: bool) {
3876 if self.telephony_device_status.network_available == network_available {
3877 return;
3878 }
3879 self.telephony_device_status.network_available = network_available;
3880 self.device_status_notification();
3881 }
3882
set_roaming(&mut self, roaming: bool)3883 fn set_roaming(&mut self, roaming: bool) {
3884 if self.telephony_device_status.roaming == roaming {
3885 return;
3886 }
3887 self.telephony_device_status.roaming = roaming;
3888 self.device_status_notification();
3889 }
3890
set_signal_strength(&mut self, signal_strength: i32) -> bool3891 fn set_signal_strength(&mut self, signal_strength: i32) -> bool {
3892 if !(0..=5).contains(&signal_strength) {
3893 warn!("Invalid signal strength, got {}, want 0 to 5", signal_strength);
3894 return false;
3895 }
3896 if self.telephony_device_status.signal_strength == signal_strength {
3897 return true;
3898 }
3899
3900 self.telephony_device_status.signal_strength = signal_strength;
3901 self.device_status_notification();
3902
3903 true
3904 }
3905
set_battery_level(&mut self, battery_level: i32) -> bool3906 fn set_battery_level(&mut self, battery_level: i32) -> bool {
3907 if !(0..=5).contains(&battery_level) {
3908 warn!("Invalid battery level, got {}, want 0 to 5", battery_level);
3909 return false;
3910 }
3911 if self.telephony_device_status.battery_level == battery_level {
3912 return true;
3913 }
3914
3915 self.telephony_device_status.battery_level = battery_level;
3916 self.device_status_notification();
3917
3918 true
3919 }
3920
set_phone_ops_enabled(&mut self, enable: bool)3921 fn set_phone_ops_enabled(&mut self, enable: bool) {
3922 info!("Bluetooth HID telephony mode enabled");
3923 if self.phone_ops_enabled == enable {
3924 return;
3925 }
3926
3927 self.call_list = vec![];
3928 self.phone_state.num_active = 0;
3929 self.phone_state.num_held = 0;
3930 self.phone_state.state = CallState::Idle;
3931 self.memory_dialing_number = None;
3932 self.last_dialing_number = None;
3933 self.a2dp_has_interrupted_stream = false;
3934
3935 self.phone_ops_enabled = enable;
3936 if self.hfp_audio_state.keys().any(|addr| self.should_insert_call_when_sco_start(*addr))
3937 && self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected)
3938 {
3939 self.place_active_call();
3940 return;
3941 }
3942
3943 self.phone_state_change("".into());
3944 }
3945
set_mps_qualification_enabled(&mut self, enable: bool)3946 fn set_mps_qualification_enabled(&mut self, enable: bool) {
3947 info!("MPS qualification mode enabled");
3948 if self.mps_qualification_enabled == enable {
3949 return;
3950 }
3951
3952 self.call_list = vec![];
3953 self.phone_state.num_active = 0;
3954 self.phone_state.num_held = 0;
3955 self.phone_state.state = CallState::Idle;
3956 self.memory_dialing_number = None;
3957 self.last_dialing_number = None;
3958 self.a2dp_has_interrupted_stream = false;
3959 self.mps_qualification_enabled = enable;
3960
3961 if self.hfp_audio_state.keys().any(|addr| self.should_insert_call_when_sco_start(*addr))
3962 && self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected)
3963 {
3964 self.place_active_call();
3965 return;
3966 }
3967
3968 self.phone_state_change("".into());
3969 }
3970
incoming_call(&mut self, number: String) -> bool3971 fn incoming_call(&mut self, number: String) -> bool {
3972 if !self.mps_qualification_enabled {
3973 warn!("Unexpected incoming_call dbus command. mps_qualification_enabled does not enabled.");
3974 return false;
3975 }
3976 self.incoming_call_impl(number)
3977 }
3978
dialing_call(&mut self, number: String) -> bool3979 fn dialing_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.dialing_call_impl(number, None)
3985 }
3986
answer_call(&mut self) -> bool3987 fn answer_call(&mut self) -> bool {
3988 if !self.mps_qualification_enabled {
3989 warn!(
3990 "Unexpected answer_call dbus command. mps_qualification_enabled does not enabled."
3991 );
3992 return false;
3993 }
3994 self.answer_call_impl()
3995 }
3996
hangup_call(&mut self) -> bool3997 fn hangup_call(&mut self) -> bool {
3998 if !self.mps_qualification_enabled {
3999 warn!(
4000 "Unexpected hangup_call dbus command. mps_qualification_enabled does not enabled."
4001 );
4002 return false;
4003 }
4004 self.hangup_call_impl()
4005 }
4006
set_memory_call(&mut self, number: Option<String>) -> bool4007 fn set_memory_call(&mut self, number: Option<String>) -> bool {
4008 if !self.mps_qualification_enabled {
4009 warn!("Unexpected set_memory_call dbus command. mps_qualification_enabled does not enabled.");
4010 return false;
4011 }
4012 self.memory_dialing_number = number;
4013 true
4014 }
4015
set_last_call(&mut self, number: Option<String>) -> bool4016 fn set_last_call(&mut self, number: Option<String>) -> bool {
4017 if !self.mps_qualification_enabled {
4018 warn!("Unexpected set_last_call dbus command. mps_qualification_enabled does not enabled.");
4019 return false;
4020 }
4021 self.last_dialing_number = number;
4022 true
4023 }
4024
release_held(&mut self) -> bool4025 fn release_held(&mut self) -> bool {
4026 if !self.mps_qualification_enabled {
4027 warn!(
4028 "Unexpected release_held dbus command. mps_qualification_enabled does not enabled."
4029 );
4030 return false;
4031 }
4032 self.release_held_impl(None)
4033 }
4034
release_active_accept_held(&mut self) -> bool4035 fn release_active_accept_held(&mut self) -> bool {
4036 if !self.mps_qualification_enabled {
4037 warn!("Unexpected release_active_accept_held dbus command. mps_qualification_enabled does not enabled.");
4038 return false;
4039 }
4040 self.release_active_accept_held_impl(None)
4041 }
4042
hold_active_accept_held(&mut self) -> bool4043 fn hold_active_accept_held(&mut self) -> bool {
4044 if !self.mps_qualification_enabled {
4045 warn!("Unexpected hold_active_accept_held dbus command. mps_qualification_enabled does not enabled.");
4046 return false;
4047 }
4048 self.hold_active_accept_held_impl(None)
4049 }
4050
audio_connect(&mut self, address: RawAddress) -> bool4051 fn audio_connect(&mut self, address: RawAddress) -> bool {
4052 self.start_sco_call_impl(address, false, HfpCodecBitId::NONE)
4053 }
4054
audio_disconnect(&mut self, address: RawAddress)4055 fn audio_disconnect(&mut self, address: RawAddress) {
4056 self.stop_sco_call_impl(address)
4057 }
4058 }
4059
4060 struct BatteryProviderCallback {}
4061
4062 impl BatteryProviderCallback {
new() -> Self4063 fn new() -> Self {
4064 Self {}
4065 }
4066 }
4067
4068 impl IBatteryProviderCallback for BatteryProviderCallback {
4069 // We do not support refreshing HFP battery information.
refresh_battery_info(&mut self)4070 fn refresh_battery_info(&mut self) {}
4071 }
4072
4073 impl RPCProxy for BatteryProviderCallback {
get_object_id(&self) -> String4074 fn get_object_id(&self) -> String {
4075 "HFP BatteryProvider Callback".to_string()
4076 }
4077 }
4078