Loading system/gd/rust/linux/client/src/command_handler.rs +4 −0 Original line number Diff line number Diff line Loading @@ -880,6 +880,7 @@ impl CommandHandler { connection_state, uuids, wake_allowed, dual_mode_audio, ) = { let ctx = self.lock_context(); let adapter = ctx.adapter_dbus.as_ref().unwrap(); Loading @@ -898,6 +899,7 @@ impl CommandHandler { }; let uuids = adapter.get_remote_uuids(device.clone()); let wake_allowed = adapter.get_remote_wake_allowed(device.clone()); let dual_mode_audio = adapter.is_dual_mode_audio_sink_device(device.clone()); ( name, Loading @@ -910,6 +912,7 @@ impl CommandHandler { connection_state, uuids, wake_allowed, dual_mode_audio, ) }; Loading @@ -923,6 +926,7 @@ impl CommandHandler { print_info!("Wake Allowed: {}", wake_allowed); print_info!("Bond State: {:?}", bonded); print_info!("Connection State: {}", connection_state); print_info!("Dual Mode Audio Device: {}", dual_mode_audio); print_info!( "Uuids: {}", DisplayList( Loading system/gd/rust/linux/client/src/dbus_iface.rs +5 −0 Original line number Diff line number Diff line Loading @@ -1030,6 +1030,11 @@ impl IBluetooth for BluetoothDBus { fn is_le_audio_supported(&self) -> bool { dbus_generated!() } #[dbus_method("IsDualModeAudioSinkDevice")] fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool { dbus_generated!() } } pub(crate) struct BluetoothQALegacyDBus { Loading system/gd/rust/linux/service/src/iface_bluetooth.rs +5 −0 Original line number Diff line number Diff line Loading @@ -765,6 +765,11 @@ impl IBluetooth for IBluetoothDBus { fn is_le_audio_supported(&self) -> bool { dbus_generated!() } #[dbus_method("IsDualModeAudioSinkDevice", DBusLog::Disable)] fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool { dbus_generated!() } } impl_dbus_arg_enum!(SocketType); Loading system/gd/rust/linux/stack/src/bluetooth.rs +28 −1 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin}; use crate::bluetooth_gatt::{ BluetoothGatt, GattActions, IBluetoothGatt, IScannerCallback, ScanResult, }; use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions}; use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions, LEA_UNKNOWN_GROUP_ID}; use crate::callbacks::Callbacks; use crate::socket_manager::SocketActions; use crate::uuid::{Profile, UuidHelper}; Loading Loading @@ -258,6 +258,10 @@ pub trait IBluetooth { /// Returns whether LE Audio is supported. fn is_le_audio_supported(&self) -> bool; /// Returns whether the remote device is a dual mode audio sink device (supports both classic and /// LE Audio sink roles). fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool; } /// Adapter API for Bluetooth qualification and verification. Loading Loading @@ -2971,6 +2975,29 @@ impl IBluetooth for Bluetooth { // See Core 5.3, Vol 6, 4.6 FEATURE SUPPORT self.le_local_supported_features >> 28 & 1 == 1u64 } fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool { fn is_dual_mode(uuids: Vec<Uuid>) -> bool { fn get_unwrapped_uuid(profile: Profile) -> Uuid { *UuidHelper::get_profile_uuid(&profile).unwrap_or(&Uuid::empty()) } uuids.contains(&get_unwrapped_uuid(Profile::LeAudio)) && (uuids.contains(&get_unwrapped_uuid(Profile::A2dpSink)) || uuids.contains(&get_unwrapped_uuid(Profile::Hfp))) } let media = self.bluetooth_media.lock().unwrap(); let group_id = media.get_group_id(device.address); if group_id == LEA_UNKNOWN_GROUP_ID { return is_dual_mode(self.get_remote_uuids(device)); } // Check if any device in the CSIP group is a dual mode audio sink device media.get_group_devices(group_id).iter().any(|addr| { is_dual_mode(self.get_remote_uuids(BluetoothDevice::new(*addr, "".to_string()))) }) } } impl BtifSdpCallbacks for Bluetooth { Loading system/gd/rust/linux/stack/src/bluetooth_media.rs +15 −9 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ const MEDIA_LE_AUDIO_PROFILES: &[Profile] = &[Profile::LeAudio, Profile::VolumeControl, Profile::CoordinatedSet]; /// Group ID used to identify unknown/non-existent groups. const LEA_UNKNOWN_GROUP_ID: i32 = -1; pub const LEA_UNKNOWN_GROUP_ID: i32 = -1; /// Refer to |pairDeviceByCsip| in |CachedBluetoothDeviceManager.java|. /// Number of attempts for CSIS to bond set members of a connected group. Loading Loading @@ -852,11 +852,7 @@ impl BluetoothMedia { BtVcConnectionState::Connected => { self.vc_states.insert(addr, state); let group_id = *self .le_audio_node_to_group .get(&addr) .unwrap_or(&LEA_UNKNOWN_GROUP_ID); let group_id = self.get_group_id(addr); match self.le_audio_groups.get(&group_id) { Some(group) if self.is_group_connected(group) => { self.callbacks.lock().unwrap().for_all_callbacks(|callback| { Loading Loading @@ -953,8 +949,7 @@ impl BluetoothMedia { return; } let group_id = *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID); let group_id = self.get_group_id(addr); if group_id == LEA_UNKNOWN_GROUP_ID { warn!( "LeAudioClientCallbacks::ConnectionState: [{}] Ignored dispatching of LeAudio callback on a device with no group", Loading Loading @@ -3020,6 +3015,17 @@ impl BluetoothMedia { self.phone_state.num_active = 1; self.phone_state_change("".into()); } pub fn get_group_devices(&self, group_id: i32) -> HashSet<RawAddress> { match self.le_audio_groups.get(&group_id) { Some(g) => g.devices.clone(), _ => HashSet::new(), } } pub fn get_group_id(&self, addr: RawAddress) -> i32 { *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID) } } fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher { Loading Loading @@ -3173,7 +3179,7 @@ impl IBluetoothMedia for BluetoothMedia { } fn disconnect_lea_group_by_member_address(&mut self, addr: RawAddress) { let group_id = *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID); let group_id = self.get_group_id(addr); if group_id == LEA_UNKNOWN_GROUP_ID { warn!( "disconnect_lea_group_by_member_address: [{}]: address belongs to no group", Loading Loading
system/gd/rust/linux/client/src/command_handler.rs +4 −0 Original line number Diff line number Diff line Loading @@ -880,6 +880,7 @@ impl CommandHandler { connection_state, uuids, wake_allowed, dual_mode_audio, ) = { let ctx = self.lock_context(); let adapter = ctx.adapter_dbus.as_ref().unwrap(); Loading @@ -898,6 +899,7 @@ impl CommandHandler { }; let uuids = adapter.get_remote_uuids(device.clone()); let wake_allowed = adapter.get_remote_wake_allowed(device.clone()); let dual_mode_audio = adapter.is_dual_mode_audio_sink_device(device.clone()); ( name, Loading @@ -910,6 +912,7 @@ impl CommandHandler { connection_state, uuids, wake_allowed, dual_mode_audio, ) }; Loading @@ -923,6 +926,7 @@ impl CommandHandler { print_info!("Wake Allowed: {}", wake_allowed); print_info!("Bond State: {:?}", bonded); print_info!("Connection State: {}", connection_state); print_info!("Dual Mode Audio Device: {}", dual_mode_audio); print_info!( "Uuids: {}", DisplayList( Loading
system/gd/rust/linux/client/src/dbus_iface.rs +5 −0 Original line number Diff line number Diff line Loading @@ -1030,6 +1030,11 @@ impl IBluetooth for BluetoothDBus { fn is_le_audio_supported(&self) -> bool { dbus_generated!() } #[dbus_method("IsDualModeAudioSinkDevice")] fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool { dbus_generated!() } } pub(crate) struct BluetoothQALegacyDBus { Loading
system/gd/rust/linux/service/src/iface_bluetooth.rs +5 −0 Original line number Diff line number Diff line Loading @@ -765,6 +765,11 @@ impl IBluetooth for IBluetoothDBus { fn is_le_audio_supported(&self) -> bool { dbus_generated!() } #[dbus_method("IsDualModeAudioSinkDevice", DBusLog::Disable)] fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool { dbus_generated!() } } impl_dbus_arg_enum!(SocketType); Loading
system/gd/rust/linux/stack/src/bluetooth.rs +28 −1 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ use crate::bluetooth_admin::{BluetoothAdmin, IBluetoothAdmin}; use crate::bluetooth_gatt::{ BluetoothGatt, GattActions, IBluetoothGatt, IScannerCallback, ScanResult, }; use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions}; use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions, LEA_UNKNOWN_GROUP_ID}; use crate::callbacks::Callbacks; use crate::socket_manager::SocketActions; use crate::uuid::{Profile, UuidHelper}; Loading Loading @@ -258,6 +258,10 @@ pub trait IBluetooth { /// Returns whether LE Audio is supported. fn is_le_audio_supported(&self) -> bool; /// Returns whether the remote device is a dual mode audio sink device (supports both classic and /// LE Audio sink roles). fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool; } /// Adapter API for Bluetooth qualification and verification. Loading Loading @@ -2971,6 +2975,29 @@ impl IBluetooth for Bluetooth { // See Core 5.3, Vol 6, 4.6 FEATURE SUPPORT self.le_local_supported_features >> 28 & 1 == 1u64 } fn is_dual_mode_audio_sink_device(&self, device: BluetoothDevice) -> bool { fn is_dual_mode(uuids: Vec<Uuid>) -> bool { fn get_unwrapped_uuid(profile: Profile) -> Uuid { *UuidHelper::get_profile_uuid(&profile).unwrap_or(&Uuid::empty()) } uuids.contains(&get_unwrapped_uuid(Profile::LeAudio)) && (uuids.contains(&get_unwrapped_uuid(Profile::A2dpSink)) || uuids.contains(&get_unwrapped_uuid(Profile::Hfp))) } let media = self.bluetooth_media.lock().unwrap(); let group_id = media.get_group_id(device.address); if group_id == LEA_UNKNOWN_GROUP_ID { return is_dual_mode(self.get_remote_uuids(device)); } // Check if any device in the CSIP group is a dual mode audio sink device media.get_group_devices(group_id).iter().any(|addr| { is_dual_mode(self.get_remote_uuids(BluetoothDevice::new(*addr, "".to_string()))) }) } } impl BtifSdpCallbacks for Bluetooth { Loading
system/gd/rust/linux/stack/src/bluetooth_media.rs +15 −9 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ const MEDIA_LE_AUDIO_PROFILES: &[Profile] = &[Profile::LeAudio, Profile::VolumeControl, Profile::CoordinatedSet]; /// Group ID used to identify unknown/non-existent groups. const LEA_UNKNOWN_GROUP_ID: i32 = -1; pub const LEA_UNKNOWN_GROUP_ID: i32 = -1; /// Refer to |pairDeviceByCsip| in |CachedBluetoothDeviceManager.java|. /// Number of attempts for CSIS to bond set members of a connected group. Loading Loading @@ -852,11 +852,7 @@ impl BluetoothMedia { BtVcConnectionState::Connected => { self.vc_states.insert(addr, state); let group_id = *self .le_audio_node_to_group .get(&addr) .unwrap_or(&LEA_UNKNOWN_GROUP_ID); let group_id = self.get_group_id(addr); match self.le_audio_groups.get(&group_id) { Some(group) if self.is_group_connected(group) => { self.callbacks.lock().unwrap().for_all_callbacks(|callback| { Loading Loading @@ -953,8 +949,7 @@ impl BluetoothMedia { return; } let group_id = *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID); let group_id = self.get_group_id(addr); if group_id == LEA_UNKNOWN_GROUP_ID { warn!( "LeAudioClientCallbacks::ConnectionState: [{}] Ignored dispatching of LeAudio callback on a device with no group", Loading Loading @@ -3020,6 +3015,17 @@ impl BluetoothMedia { self.phone_state.num_active = 1; self.phone_state_change("".into()); } pub fn get_group_devices(&self, group_id: i32) -> HashSet<RawAddress> { match self.le_audio_groups.get(&group_id) { Some(g) => g.devices.clone(), _ => HashSet::new(), } } pub fn get_group_id(&self, addr: RawAddress) -> i32 { *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID) } } fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher { Loading Loading @@ -3173,7 +3179,7 @@ impl IBluetoothMedia for BluetoothMedia { } fn disconnect_lea_group_by_member_address(&mut self, addr: RawAddress) { let group_id = *self.le_audio_node_to_group.get(&addr).unwrap_or(&LEA_UNKNOWN_GROUP_ID); let group_id = self.get_group_id(addr); if group_id == LEA_UNKNOWN_GROUP_ID { warn!( "disconnect_lea_group_by_member_address: [{}]: address belongs to no group", Loading