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

Commit 193edabe authored by Jeremy Wu's avatar Jeremy Wu
Browse files

floss: consolidate group related members in BluetoothMedia

This CL moves several group related information into a struct for
maintainability.

Bug: 317682584
Test: m Bluetooth

Change-Id: Ia7b7b1d93861cfceba4a490f738b0b257617ea36
parent a2720bc2
Loading
Loading
Loading
Loading
+129 −114
Original line number Diff line number Diff line
@@ -409,6 +409,14 @@ struct LEAAudioConf {
    pub avail_cont: u16,
}

#[derive(Default, Clone)]
struct LeAudioGroup {
    pub devices: HashSet<RawAddress>,
    pub status: BtLeAudioGroupStatus,
    pub stream_status: BtLeAudioGroupStreamStatus,
    pub volume: Option<u8>,
}

#[derive(Debug, Copy, Clone, FromPrimitive)]
#[repr(u8)]
enum TelephonyEvent {
@@ -473,13 +481,10 @@ pub struct BluetoothMedia {
    last_dialing_number: Option<String>,
    uhid: HashMap<RawAddress, UHid>,
    le_audio: Option<LeAudioClient>,
    le_audio_group_status: HashMap<i32, BtLeAudioGroupStatus>,
    le_audio_group_volume: HashMap<i32, u8>,
    le_audio_groups: HashMap<i32, HashSet<RawAddress>>,
    le_audio_groups: HashMap<i32, LeAudioGroup>,
    le_audio_node_to_group: HashMap<RawAddress, i32>,
    le_audio_states: HashMap<RawAddress, BtLeAudioConnectionState>,
    le_audio_unicast_monitor_mode_status: HashMap<i32, BtLeAudioUnicastMonitorModeStatus>,
    le_audio_group_stream_status: HashMap<i32, BtLeAudioGroupStreamStatus>,
    le_audio_delayed_audio_conf_updates: HashMap<i32, LEAAudioConf>,
    le_audio_delayed_vc_connection_updates: HashSet<RawAddress>,
    vc: Option<VolumeControl>,
@@ -541,13 +546,10 @@ impl BluetoothMedia {
            last_dialing_number: None,
            uhid: HashMap::new(),
            le_audio: None,
            le_audio_group_status: HashMap::new(),
            le_audio_group_volume: HashMap::new(),
            le_audio_groups: HashMap::new(),
            le_audio_node_to_group: HashMap::new(),
            le_audio_states: HashMap::new(),
            le_audio_unicast_monitor_mode_status: HashMap::new(),
            le_audio_group_stream_status: HashMap::new(),
            le_audio_delayed_audio_conf_updates: HashMap::new(),
            le_audio_delayed_vc_connection_updates: HashSet::new(),
            vc: None,
@@ -603,13 +605,40 @@ impl BluetoothMedia {
        self.notify_media_capability_updated(addr);
    }

    fn is_group_connected(&self, group: HashSet<RawAddress>) -> bool {
        group.iter().any(|&addr| {
    fn is_group_connected(&self, group: &LeAudioGroup) -> bool {
        group.devices.iter().any(|&addr| {
            *self.le_audio_states.get(&addr).unwrap_or(&BtLeAudioConnectionState::Disconnected)
                == BtLeAudioConnectionState::Connected
        })
    }

    fn remove_device_from_group(&mut self, addr: RawAddress) {
        let group_id = match self.le_audio_node_to_group.get(&addr) {
            Some(group_id) => group_id,
            None => {
                warn!("Cannot remove device {} that belongs to no group", DisplayAddress(&addr));
                return;
            }
        };

        match self.le_audio_groups.get_mut(&group_id) {
            Some(group) => {
                group.devices.remove(&addr);
                if group.devices.is_empty() {
                    self.le_audio_groups.remove(&group_id);
                }
            }
            None => {
                warn!(
                    "{} claims to be in group {} which does not exist",
                    DisplayAddress(&addr),
                    group_id
                );
                return;
            }
        }
    }

    pub fn set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>) {
        self.adapter = Some(adapter);
    }
@@ -828,20 +857,20 @@ impl BluetoothMedia {
                            .get(&addr)
                            .unwrap_or(&LEA_UNKNOWN_GROUP_ID);

                        let group =
                            self.le_audio_groups.get(&group_id).unwrap_or(&HashSet::new()).clone();

                        if self.is_group_connected(group) {
                        match self.le_audio_groups.get(&group_id) {
                            Some(group) if self.is_group_connected(group) => {
                                self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
                                    callback.on_lea_vc_connected(addr, group_id);
                                });
                        } else {
                            self.le_audio_delayed_vc_connection_updates.insert(addr);
                        }

                                // Sync group volume in case this new member has not been adjusted.
                        if let Some(volume) = self.le_audio_group_volume.get(&group_id) {
                            self.set_group_volume(group_id, *volume);
                                if let Some(volume) = group.volume {
                                    self.set_group_volume(group_id, volume);
                                }
                            }
                            _ => {
                                self.le_audio_delayed_vc_connection_updates.insert(addr);
                            }
                        }
                    }
                    BtVcConnectionState::Disconnected => {
@@ -867,12 +896,6 @@ impl BluetoothMedia {
                    group_id, volume, mute, is_autonomous
                );

                if let Some(old_volume) = self.le_audio_group_volume.insert(group_id, volume) {
                    if old_volume == volume {
                        return;
                    }
                }

                // This can come with ~300ms delay, thus notify only when
                // triggered by the headset. Otherwise expect the audio server
                // to know the expected volume.
@@ -881,6 +904,8 @@ impl BluetoothMedia {
                        callback.on_lea_group_volume_changed(group_id, volume);
                    });
                }

                self.le_audio_groups.entry(group_id).or_default().volume = Some(volume);
            }
            VolumeControlCallbacks::DeviceAvailable(addr, num_offset) => {
                info!(
@@ -938,16 +963,17 @@ impl BluetoothMedia {
                    return;
                }

                let group = self.le_audio_groups.get(&group_id).unwrap_or(&HashSet::new()).clone();

                let is_only_connected_member = group.iter().all(|&member_addr| {
                let is_only_connected_member = match self.le_audio_groups.get(&group_id) {
                    Some(group) => group.devices.iter().all(|&member_addr| {
                        member_addr == addr
                            || *self
                                .le_audio_states
                                .get(&member_addr)
                                .unwrap_or(&BtLeAudioConnectionState::Disconnected)
                                != BtLeAudioConnectionState::Connected
                });
                    }),
                    _ => true,
                };

                info!(
                    "LeAudioClientCallbacks::ConnectionState: [{}]: state={:?}, group_id={}, is_only_connected_member={}",
@@ -999,6 +1025,9 @@ impl BluetoothMedia {
                                });
                            }
                        }

                        // In anticipation that it could possibly never be connected.
                        self.le_audio_delayed_vc_connection_updates.remove(&addr);
                    }
                    _ => {
                        self.le_audio_states.insert(addr, state);
@@ -1006,8 +1035,8 @@ impl BluetoothMedia {
                }
            }
            LeAudioClientCallbacks::GroupStatus(group_id, status) => {
                if !self.le_audio_group_status.get(&group_id).is_none()
                    && status == *self.le_audio_group_status.get(&group_id).unwrap()
                if !self.le_audio_groups.get(&group_id).is_none()
                    && status == self.le_audio_groups.get(&group_id).unwrap().status
                {
                    return;
                }
@@ -1017,15 +1046,11 @@ impl BluetoothMedia {
                    group_id, status
                );

                if self.le_audio_groups.get(&group_id).is_none() {
                    warn!("LeAudioClientCallbacks::GroupStatus: Updating status of a non-existent group.")
                }

                self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
                    callback.on_lea_group_status(group_id, status);
                });

                self.le_audio_group_status.insert(group_id, status);
                self.le_audio_groups.entry(group_id).or_default().status = status;
            }
            LeAudioClientCallbacks::GroupNodeStatus(addr, group_id, status) => {
                info!(
@@ -1037,64 +1062,48 @@ impl BluetoothMedia {

                match status {
                    BtLeAudioGroupNodeStatus::Added => {
                        if let Some(old_group_id) =
                            self.le_audio_node_to_group.insert(addr, group_id)
                        {
                            if old_group_id != group_id {
                        match self.le_audio_node_to_group.get(&addr) {
                            Some(old_group_id) if *old_group_id != group_id => {
                                warn!(
                                    "LeAudioClientCallbacks::GroupNodeStatus: [{}]: node already belongs to another group {}",
                                    DisplayAddress(&addr),
                                    old_group_id,
                                );

                                if let Some(old_group) = self.le_audio_groups.get_mut(&old_group_id)
                                {
                                    old_group.remove(&addr);
                                    if old_group.is_empty() {
                                        self.le_audio_groups.remove(&old_group_id);
                                        self.le_audio_group_status.remove(&old_group_id);
                                        self.le_audio_group_volume.remove(&old_group_id);
                                        self.le_audio_group_stream_status.remove(&old_group_id);
                                        self.le_audio_delayed_audio_conf_updates
                                            .remove(&old_group_id);
                                    }
                                }
                                self.remove_device_from_group(addr);
                            }
                            _ => {}
                        }

                        self.le_audio_groups.entry(group_id).or_insert(HashSet::new()).insert(addr);
                        self.le_audio_node_to_group.insert(addr, group_id);

                        let group = self.le_audio_groups.entry(group_id).or_default();

                        group.devices.insert(addr);

                        if let Some(volume) = self.le_audio_group_volume.get(&group_id) {
                            self.set_group_volume(group_id, *volume);
                        if let Some(volume) = group.volume {
                            self.set_group_volume(group_id, volume);
                        }
                    }
                    BtLeAudioGroupNodeStatus::Removed => {
                        if let Some(old_group_id) = self.le_audio_node_to_group.remove(&addr) {
                            if old_group_id != group_id {
                        match self.le_audio_node_to_group.get(&addr) {
                            Some(old_group_id) if *old_group_id == group_id => {
                                self.remove_device_from_group(addr);
                            }
                            Some(old_group_id) if *old_group_id != group_id => {
                                warn!(
                                    "LeAudioClientCallbacks::GroupNodeStatus: [{}]: removed node from its group {} which is not the specified group {}",
                                    "LeAudioClientCallbacks::GroupNodeStatus: [{}]: cannot remove node from group {} because it is in group {}",
                                    DisplayAddress(&addr),
                                    old_group_id,
                                    group_id,
                                    old_group_id,
                                );
                            }

                            if let Some(old_group) = self.le_audio_groups.get_mut(&old_group_id) {
                                old_group.remove(&addr);
                                if old_group.is_empty() {
                                    self.le_audio_groups.remove(&old_group_id);
                                    self.le_audio_group_status.remove(&old_group_id);
                                    self.le_audio_group_volume.remove(&old_group_id);
                                    self.le_audio_group_stream_status.remove(&old_group_id);
                                    self.le_audio_delayed_audio_conf_updates.remove(&old_group_id);
                                }
                                return;
                            }
                        } else {
                            warn!(
                                "LeAudioClientCallbacks::GroupNodeStatus: [{}]: node does not belong to any group",
                                DisplayAddress(&addr)
                            );
                            _ => {}
                        }

                        self.le_audio_node_to_group.remove(&addr);
                    }
                    _ => {
                        warn!("LeAudioClientCallbacks::GroupNodeStatus: Unknown status for GroupNodeStatus {:?}", status);
@@ -1117,9 +1126,8 @@ impl BluetoothMedia {
                    direction, group_id, snk_audio_location, src_audio_location, avail_cont,
                );

                let group = self.le_audio_groups.get(&group_id).unwrap_or(&HashSet::new()).clone();

                if self.is_group_connected(group) {
                match self.le_audio_groups.get(&group_id) {
                    Some(group) if self.is_group_connected(group) => {
                        self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
                            callback.on_lea_audio_conf(
                                direction,
@@ -1129,7 +1137,8 @@ impl BluetoothMedia {
                                avail_cont,
                            );
                        });
                } else {
                    }
                    _ => {
                        self.le_audio_delayed_audio_conf_updates.insert(
                            group_id,
                            LEAAudioConf {
@@ -1142,6 +1151,7 @@ impl BluetoothMedia {
                        );
                    }
                }
            }
            LeAudioClientCallbacks::SinkAudioLocationAvailable(addr, snk_audio_locations) => {
                info!("LeAudioClientCallbacks::SinkAudioLocationAvailable: [{}]: snk_audio_locations={:?}", DisplayAddress(&addr), snk_audio_locations);
            }
@@ -1187,8 +1197,8 @@ impl BluetoothMedia {
                self.le_audio_unicast_monitor_mode_status.insert(direction.into(), status);
            }
            LeAudioClientCallbacks::GroupStreamStatus(group_id, status) => {
                if !self.le_audio_group_stream_status.get(&group_id).is_none()
                    && status == *self.le_audio_group_stream_status.get(&group_id).unwrap()
                if !self.le_audio_groups.get(&group_id).is_none()
                    && status == self.le_audio_groups.get(&group_id).unwrap().stream_status
                {
                    return;
                }
@@ -1202,7 +1212,7 @@ impl BluetoothMedia {
                    callback.on_lea_group_stream_status(group_id, status);
                });

                self.le_audio_group_stream_status.insert(group_id, status);
                self.le_audio_groups.entry(group_id).or_default().stream_status = status;
            }
        }
    }
@@ -3179,7 +3189,7 @@ impl IBluetoothMedia for BluetoothMedia {
            return;
        }

        let group = self.le_audio_groups.get(&group_id).unwrap_or(&HashSet::new()).clone();
        let group = self.le_audio_groups.entry(group_id).or_default().clone();

        let available_profiles = self.adapter_get_le_audio_profiles(addr);

@@ -3189,7 +3199,7 @@ impl IBluetoothMedia for BluetoothMedia {
            available_profiles
        );

        for &member_addr in group.iter() {
        for &member_addr in group.devices.iter() {
            for profile in self.adapter_get_le_audio_profiles(addr) {
                match profile {
                    uuid::Profile::LeAudio => {
@@ -4060,14 +4070,19 @@ impl IBluetoothMedia for BluetoothMedia {
    }

    fn get_group_stream_status(&mut self, group_id: i32) -> BtLeAudioGroupStreamStatus {
        *self
            .le_audio_group_stream_status
            .get(&group_id)
            .unwrap_or(&BtLeAudioGroupStreamStatus::Idle)
        if self.le_audio_groups.get(&group_id).is_none() {
            return BtLeAudioGroupStreamStatus::Idle;
        }

        self.le_audio_groups.get(&group_id).unwrap().stream_status
    }

    fn get_group_status(&mut self, group_id: i32) -> BtLeAudioGroupStatus {
        *self.le_audio_group_status.get(&group_id).unwrap_or(&BtLeAudioGroupStatus::Inactive)
        if self.le_audio_groups.get(&group_id).is_none() {
            return BtLeAudioGroupStatus::Inactive;
        }

        self.le_audio_groups.get(&group_id).unwrap().status
    }

    fn set_group_volume(&mut self, group_id: i32, volume: u8) {
+12 −0
Original line number Diff line number Diff line
@@ -257,6 +257,12 @@ impl From<i32> for BtLeAudioGroupStatus {
    }
}

impl Default for BtLeAudioGroupStatus {
    fn default() -> Self {
        BtLeAudioGroupStatus::Inactive
    }
}

impl From<BtLeAudioGroupNodeStatus> for i32 {
    fn from(value: BtLeAudioGroupNodeStatus) -> Self {
        match value {
@@ -432,6 +438,12 @@ impl From<i32> for BtLeAudioGroupStreamStatus {
    }
}

impl Default for BtLeAudioGroupStreamStatus {
    fn default() -> Self {
        BtLeAudioGroupStreamStatus::Idle
    }
}

impl From<BtLeAudioDirection> for i32 {
    fn from(value: BtLeAudioDirection) -> Self {
        match value {