Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e094fe6 authored by Jeremy Wu's avatar Jeremy Wu
Browse files

Floss: add csis to profile policy

This is only enabled when the chrome flag
|CrOSLateBootBluetoothAudioLEAudioOnly| is enabled.

Bug: 317682584
Test: m Bluetooth
Change-Id: Id98fd212e23895bff6579de0a7eae64c62f48406
parent 1784097d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -2660,6 +2660,16 @@ impl IBluetoothMedia for BluetoothMediaDBus {
        dbus_generated!()
    }

    #[dbus_method("ConnectCsis")]
    fn connect_csis(&mut self, address: String) {
        dbus_generated!()
    }

    #[dbus_method("DisconnectCsis")]
    fn disconnect_csis(&mut self, address: String) {
        dbus_generated!()
    }

    #[dbus_method("SetActiveDevice")]
    fn set_active_device(&mut self, address: String) {
        dbus_generated!()
+10 −0
Original line number Diff line number Diff line
@@ -300,6 +300,16 @@ impl IBluetoothMedia for IBluetoothMediaDBus {
        dbus_generated!()
    }

    #[dbus_method("ConnectCsis")]
    fn connect_csis(&mut self, address: String) {
        dbus_generated!()
    }

    #[dbus_method("DisconnectCsis")]
    fn disconnect_csis(&mut self, address: String) {
        dbus_generated!()
    }

    #[dbus_method("SetActiveDevice")]
    fn set_active_device(&mut self, address: String) {
        dbus_generated!()
+12 −5
Original line number Diff line number Diff line
@@ -664,7 +664,8 @@ impl Bluetooth {
            | Profile::Hfp
            | Profile::AvrcpTarget
            | Profile::LeAudio
            | Profile::VolumeControl => {
            | Profile::VolumeControl
            | Profile::CoordinatedSet => {
                self.bluetooth_media.lock().unwrap().disable_profile(profile);
            }
            // Ignore profiles that we don't connect.
@@ -690,7 +691,8 @@ impl Bluetooth {
            | Profile::Hfp
            | Profile::AvrcpTarget
            | Profile::LeAudio
            | Profile::VolumeControl => {
            | Profile::VolumeControl
            | Profile::CoordinatedSet => {
                self.bluetooth_media.lock().unwrap().enable_profile(profile);
            }
            // Ignore profiles that we don't connect.
@@ -712,7 +714,8 @@ impl Bluetooth {
            | Profile::Hfp
            | Profile::AvrcpTarget
            | Profile::LeAudio
            | Profile::VolumeControl => {
            | Profile::VolumeControl
            | Profile::CoordinatedSet => {
                self.bluetooth_media.lock().unwrap().is_profile_enabled(profile)
            }
            // Ignore profiles that we don't connect.
@@ -2772,7 +2775,9 @@ impl IBluetooth for Bluetooth {
                            }

                            // TODO(b/317682584): implement policy to connect to LEA, VC, and CSIS
                            Profile::LeAudio | Profile::VolumeControl if !has_le_media_profile => {
                            Profile::LeAudio | Profile::VolumeControl | Profile::CoordinatedSet
                                if !has_le_media_profile =>
                            {
                                has_le_media_profile = true;
                                let txl = self.tx.clone();
                                let address = device.address.clone();
@@ -2896,7 +2901,9 @@ impl IBluetooth for Bluetooth {
                            }

                            // TODO(b/317682584): implement policy to disconnect from LEA, VC, and CSIS
                            Profile::LeAudio | Profile::VolumeControl if !has_le_media_profile => {
                            Profile::LeAudio | Profile::VolumeControl | Profile::CoordinatedSet
                                if !has_le_media_profile =>
                            {
                                has_le_media_profile = true;
                                let txl = self.tx.clone();
                                let address = device.address.clone();
+192 −2
Original line number Diff line number Diff line
@@ -12,6 +12,9 @@ use bt_topshim::profiles::a2dp::{
use bt_topshim::profiles::avrcp::{
    Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher, PlayerMetadata,
};
use bt_topshim::profiles::csis::{
    BtCsisConnectionState, CsisClient, CsisClientCallbacks, CsisClientCallbacksDispatcher,
};
use bt_topshim::profiles::hfp::interop_insert_call_when_sco_start;
use bt_topshim::profiles::hfp::{
    BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallState, EscoCodingFormat,
@@ -82,11 +85,17 @@ const MEDIA_CLASSIC_AUDIO_PROFILES: &[uuid::Profile] =

/// The list of profiles we consider as LE audio profiles for media.
const MEDIA_LE_AUDIO_PROFILES: &[uuid::Profile] =
    &[uuid::Profile::LeAudio, uuid::Profile::VolumeControl];
    &[uuid::Profile::LeAudio, uuid::Profile::VolumeControl, uuid::Profile::CoordinatedSet];

/// Group ID used to identify unknown/non-existent groups.
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.
const CSIS_BONDING_NUM_ATTEMPTS: u32 = 30;
/// The delay for bonding retries when pairing is busy, in milliseconds.
const CSIS_BONDING_RETRY_DELAY_MS: u64 = 500;

pub trait IBluetoothMedia {
    ///
    fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool;
@@ -111,6 +120,8 @@ pub trait IBluetoothMedia {
    fn disconnect_lea(&mut self, address: String);
    fn connect_vc(&mut self, address: String);
    fn disconnect_vc(&mut self, address: String);
    fn connect_csis(&mut self, address: String);
    fn disconnect_csis(&mut self, address: String);

    // Set the device as the active A2DP device
    fn set_active_device(&mut self, address: String);
@@ -361,6 +372,8 @@ pub enum MediaActions {
    DisconnectLea(String),
    ConnectVc(String),
    DisconnectVc(String),
    ConnectCsis(String),
    DisconnectCsis(String),
}

#[derive(Debug, Clone, PartialEq)]
@@ -433,6 +446,8 @@ pub struct BluetoothMedia {
    le_audio_delayed_audio_conf_updates: HashMap<i32, LEAAudioConf>,
    vc: Option<VolumeControl>,
    vc_states: HashMap<RawAddress, BtVcConnectionState>,
    csis: Option<CsisClient>,
    csis_states: HashMap<RawAddress, BtCsisConnectionState>,
    is_le_audio_only_enabled: bool, // TODO: remove this once there is dual mode.
}

@@ -497,6 +512,8 @@ impl BluetoothMedia {
            le_audio_delayed_audio_conf_updates: HashMap::new(),
            vc: None,
            vc_states: HashMap::new(),
            csis: None,
            csis_states: HashMap::new(),
            is_le_audio_only_enabled: false,
        }
    }
@@ -558,7 +575,7 @@ impl BluetoothMedia {
                    return;
                }
            }
            Profile::LeAudio | Profile::VolumeControl => {
            Profile::LeAudio | Profile::VolumeControl | Profile::CoordinatedSet => {
                if !self.is_le_audio_only_enabled {
                    info!("LeAudioEnableLeAudioOnly is not set, skip enabling {:?}", profile);
                    return;
@@ -593,6 +610,11 @@ impl BluetoothMedia {
                    vc.enable();
                }
            }
            &Profile::CoordinatedSet => {
                if let Some(csis) = &mut self.csis {
                    csis.enable();
                }
            }
            _ => {
                warn!("Tried to enable {} in bluetooth_media", profile);
                return;
@@ -633,6 +655,11 @@ impl BluetoothMedia {
                    vc.disable();
                }
            }
            &Profile::CoordinatedSet => {
                if let Some(csis) = &mut self.csis {
                    csis.disable();
                }
            }
            _ => {
                warn!("Tried to disable {} in bluetooth_media", profile);
                return;
@@ -655,6 +682,9 @@ impl BluetoothMedia {
                Some(self.le_audio.as_ref().map_or(false, |le_audio| le_audio.is_enabled()))
            }
            &Profile::VolumeControl => Some(self.vc.as_ref().map_or(false, |vc| vc.is_enabled())),
            &Profile::CoordinatedSet => {
                Some(self.csis.as_ref().map_or(false, |csis| csis.is_enabled()))
            }
            _ => {
                warn!("Tried to query enablement status of {} in bluetooth_media", profile);
                None
@@ -662,6 +692,71 @@ impl BluetoothMedia {
        }
    }

    pub fn dispatch_csis_callbacks(&mut self, cb: CsisClientCallbacks) {
        match cb {
            CsisClientCallbacks::ConnectionState(addr, state) => {
                if !self.csis_states.get(&addr).is_none()
                    && state == *self.csis_states.get(&addr).unwrap()
                {
                    return;
                }

                info!(
                    "CsisClientCallbacks::ConnectionState: [{}]: state={:?}",
                    DisplayAddress(&addr),
                    state
                );

                match state {
                    BtCsisConnectionState::Connected => {
                        self.csis_states.insert(addr, state);
                    }
                    BtCsisConnectionState::Disconnected => {
                        self.csis_states.remove(&addr);
                    }
                    _ => {
                        self.csis_states.insert(addr, state);
                    }
                }
            }
            CsisClientCallbacks::DeviceAvailable(addr, group_id, group_size, rank, uuid) => {
                info!(
                    "CsisClientCallbacks::DeviceAvailable: [{}]: group_id={}, group_size={}, rank={}, uuid={:?}",
                    DisplayAddress(&addr),
                    group_id,
                    group_size,
                    rank,
                    uuid,
                );
            }
            CsisClientCallbacks::SetMemberAvailable(addr, group_id) => {
                info!(
                    "CsisClientCallbacks::SetMemberAvailable: [{}]: group_id={}",
                    DisplayAddress(&addr),
                    group_id
                );
                let device = BluetoothDevice::new(addr.to_string(), "".to_string());
                let txl = self.tx.clone();
                topstack::get_runtime().spawn(async move {
                    let _ = txl
                        .send(Message::CreateBondWithRetry(
                            device,
                            BtTransport::Le,
                            CSIS_BONDING_NUM_ATTEMPTS,
                            Duration::from_millis(CSIS_BONDING_RETRY_DELAY_MS),
                        ))
                        .await;
                });
            }
            CsisClientCallbacks::GroupLockChanged(group_id, locked, status) => {
                info!(
                    "CsisClientCallbacks::GroupLockChanged: group_id={}, locked={}, status={:?}",
                    group_id, locked, status
                );
            }
        }
    }

    pub fn dispatch_vc_callbacks(&mut self, cb: VolumeControlCallbacks) {
        match cb {
            VolumeControlCallbacks::ConnectionState(state, addr) => {
@@ -1212,6 +1307,8 @@ impl BluetoothMedia {
            MediaActions::DisconnectLea(address) => self.disconnect_lea(address),
            MediaActions::ConnectVc(address) => self.connect_vc(address),
            MediaActions::DisconnectVc(address) => self.disconnect_vc(address),
            MediaActions::ConnectCsis(address) => self.connect_csis(address),
            MediaActions::DisconnectCsis(address) => self.disconnect_csis(address),

            MediaActions::ConnectLeaGroupByMemberAddress(address) => {
                self.connect_lea_group_by_member_address(address)
@@ -2896,6 +2993,17 @@ fn get_vc_dispatcher(tx: Sender<Message>) -> VolumeControlCallbacksDispatcher {
    }
}

fn get_csis_dispatcher(tx: Sender<Message>) -> CsisClientCallbacksDispatcher {
    CsisClientCallbacksDispatcher {
        dispatch: Box::new(move |cb| {
            let txl = tx.clone();
            topstack::get_runtime().spawn(async move {
                let _ = txl.send(Message::CsisClient(cb)).await;
            });
        }),
    }
}

impl IBluetoothMedia for BluetoothMedia {
    fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool {
        let _id = self.callbacks.lock().unwrap().add_callback(callback);
@@ -2936,6 +3044,11 @@ impl IBluetoothMedia for BluetoothMedia {
        self.vc = Some(VolumeControl::new(&self.intf.lock().unwrap()));
        self.vc.as_mut().unwrap().initialize(vc_dispatcher);

        // CSIS
        let csis_dispatcher = get_csis_dispatcher(self.tx.clone());
        self.csis = Some(CsisClient::new(&self.intf.lock().unwrap()));
        self.csis.as_mut().unwrap().initialize(csis_dispatcher);

        // TODO(b/284811956) A2DP needs to be enabled before AVRCP otherwise AVRCP gets memset'd.
        // Iterate the delay_enable_profiles hashmap directly when this is fixed.
        let profile_order = vec![
@@ -2944,6 +3057,7 @@ impl IBluetoothMedia for BluetoothMedia {
            Profile::Hfp,
            Profile::LeAudio,
            Profile::VolumeControl,
            Profile::CoordinatedSet,
        ];
        for profile in profile_order {
            if self.delay_enable_profiles.contains(&profile) {
@@ -2974,6 +3088,9 @@ impl IBluetoothMedia for BluetoothMedia {
                uuid::Profile::VolumeControl => {
                    self.connect_vc(addr.to_string());
                }
                uuid::Profile::CoordinatedSet => {
                    self.connect_csis(addr.to_string());
                }
                _ => {}
            }
        }
@@ -3016,6 +3133,9 @@ impl IBluetoothMedia for BluetoothMedia {
                    uuid::Profile::VolumeControl => {
                        self.disconnect_vc(member_addr.to_string());
                    }
                    uuid::Profile::CoordinatedSet => {
                        self.disconnect_csis(member_addr.to_string());
                    }
                    _ => {}
                }
            }
@@ -3161,6 +3281,76 @@ impl IBluetoothMedia for BluetoothMedia {
        };
    }

    fn connect_csis(&mut self, address: String) {
        if !self.is_le_audio_only_enabled {
            warn!("connect_csis: LeAudioEnableLeAudioOnly is not set");
            return;
        }

        let addr = match RawAddress::from_string(address.clone()) {
            None => {
                warn!("connecting_csis: invalid device address");
                return;
            }
            Some(addr) => addr,
        };

        if *self.csis_states.get(&addr).unwrap_or(&BtCsisConnectionState::Disconnected)
            == BtCsisConnectionState::Connected
        {
            info!("connect_csis: already connected");
            return;
        }

        let available_profiles = self.adapter_get_le_audio_profiles(addr);

        info!(
            "connect_csis: [{}]: connecting, available profiles: {:?}.",
            DisplayAddress(&addr),
            available_profiles
        );

        match self.csis.as_mut() {
            Some(csis) => {
                csis.connect(addr);
            }
            None => {
                warn!("connect_csis: [{}]: uninitialized Csis to connect", DisplayAddress(&addr));
            }
        };
    }

    fn disconnect_csis(&mut self, address: String) {
        let addr = match RawAddress::from_string(address.clone()) {
            None => {
                warn!("disconnect_csis: invalid device address");
                return;
            }
            Some(addr) => addr,
        };

        if *self.csis_states.get(&addr).unwrap_or(&BtCsisConnectionState::Disconnected)
            == BtCsisConnectionState::Disconnected
        {
            info!("disconnect_csis: already disconnected");
            return;
        }

        info!("disconnect_csis: [{}]: disconnecting", DisplayAddress(&addr),);

        match self.csis.as_mut() {
            Some(csis) => {
                csis.disconnect(addr);
            }
            None => {
                warn!(
                    "disconnect_csis: [{}]: uninitialized CSIS to disconnect",
                    DisplayAddress(&addr)
                );
            }
        };
    }

    fn connect(&mut self, address: String) {
        if self.is_le_audio_only_enabled {
            warn!("connect: LeAudioEnableLeAudioOnly is set");
+6 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ use bt_topshim::{
    profiles::{
        a2dp::A2dpCallbacks,
        avrcp::AvrcpCallbacks,
        csis::CsisClientCallbacks,
        gatt::GattAdvCallbacks,
        gatt::GattAdvInbandCallbacks,
        gatt::GattClientCallbacks,
@@ -91,6 +92,7 @@ pub enum Message {
    Hfp(HfpCallbacks),
    Sdp(SdpCallbacks),
    VolumeControl(VolumeControlCallbacks),
    CsisClient(CsisClientCallbacks),
    CreateBondWithRetry(BluetoothDevice, BtTransport, u32, Duration),

    // Actions within the stack
@@ -309,6 +311,10 @@ impl Stack {
                    bluetooth_media.lock().unwrap().dispatch_vc_callbacks(a);
                }

                Message::CsisClient(a) => {
                    bluetooth_media.lock().unwrap().dispatch_csis_callbacks(a);
                }

                Message::LeScanner(m) => {
                    dispatch_le_scanner_callbacks(bluetooth_gatt.lock().unwrap().as_mut(), m);
                }
Loading