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

Commit 97c8e304 authored by Jeremy Wu's avatar Jeremy Wu Committed by Gerrit Code Review
Browse files

Merge "Floss: wait when audio profile connection received but SDP is empty" into main

parents c8b3151e 8cc7ee12
Loading
Loading
Loading
Loading
+58 −18
Original line number Diff line number Diff line
@@ -43,8 +43,9 @@ use crate::uuid::Profile;
use crate::{Message, RPCProxy};

// The timeout we have to wait for all supported profiles to connect after we
// receive the first profile connected event. The host shall disconnect the
// device after this many seconds of timeout.
// receive the first profile connected event. The host shall disconnect or
// force connect the potentially partially connected device after this many
// seconds of timeout.
const PROFILE_DISCOVERY_TIMEOUT_SEC: u64 = 10;
// The timeout we have to wait for the initiator peer device to complete the
// initial profile connection. After this many seconds, we will begin to
@@ -256,6 +257,7 @@ enum DeviceConnectionStates {
    ConnectingAfterRetry,  // Host initiated requests to missing profiles after timeout
    FullyConnected,        // All profiles (excluding AVRCP) are connected
    Disconnecting,         // Working towards disconnection of each connected profile
    WaitingConnection,     // Waiting for new connections initiated by peer
}

pub struct BluetoothMedia {
@@ -605,7 +607,8 @@ impl BluetoothMedia {
                    info!("[{}]: state {:?}", DisplayAddress(&addr), state);
                    match state {
                        DeviceConnectionStates::ConnectingBeforeRetry
                        | DeviceConnectionStates::ConnectingAfterRetry => {
                        | DeviceConnectionStates::ConnectingAfterRetry
                        | DeviceConnectionStates::WaitingConnection => {
                            self.delay_volume_update.insert(Profile::AvrcpController, volume);
                        }
                        DeviceConnectionStates::FullyConnected => {
@@ -779,7 +782,8 @@ impl BluetoothMedia {
                );
                match states.get(&addr).unwrap() {
                    DeviceConnectionStates::ConnectingBeforeRetry
                    | DeviceConnectionStates::ConnectingAfterRetry => {
                    | DeviceConnectionStates::ConnectingAfterRetry
                    | DeviceConnectionStates::WaitingConnection => {
                        self.delay_volume_update.insert(Profile::Hfp, volume);
                    }
                    DeviceConnectionStates::FullyConnected => {
@@ -1122,7 +1126,7 @@ impl BluetoothMedia {
        first_conn_ts: Instant,
    ) {
        let now_ts = Instant::now();
        let total_duration = Duration::from_secs(CONNECT_MISSING_PROFILES_TIMEOUT_SEC);
        let total_duration = Duration::from_secs(PROFILE_DISCOVERY_TIMEOUT_SEC);
        let sleep_duration = (first_conn_ts + total_duration).saturating_duration_since(now_ts);
        sleep(sleep_duration).await;
        let _ = txl.send(Message::Media(MediaActions::ForceEnterConnected(addr.to_string()))).await;
@@ -1193,6 +1197,33 @@ impl BluetoothMedia {
        if states.get(&addr).is_none() {
            states.insert(addr, DeviceConnectionStates::ConnectingBeforeRetry);
        }

        if states.get(&addr).unwrap() != &DeviceConnectionStates::FullyConnected {
            if available_profiles.is_empty() {
                // Some headsets may start initiating connections to audio profiles before they are
                // exposed to the stack. In this case, wait for either all critical profiles have been
                // connected or some timeout to enter the |FullyConnected| state.
                if connected_profiles.contains(&Profile::Hfp)
                    && connected_profiles.contains(&Profile::A2dpSink)
                {
                    info!(
                        "[{}]: Fully connected, available profiles: {:?}, connected profiles: {:?}.",
                        DisplayAddress(&addr),
                        available_profiles,
                        connected_profiles
                    );

                    states.insert(addr, DeviceConnectionStates::FullyConnected);
                } else {
                    warn!(
                        "[{}]: Connected profiles: {:?}, waiting for peer to initiate remaining connections.",
                        DisplayAddress(&addr),
                        connected_profiles
                    );

                    states.insert(addr, DeviceConnectionStates::WaitingConnection);
                }
            } else {
                if missing_profiles.is_empty()
                    || missing_profiles == HashSet::from([Profile::AvrcpController])
                {
@@ -1205,6 +1236,8 @@ impl BluetoothMedia {

                    states.insert(addr, DeviceConnectionStates::FullyConnected);
                }
            }
        }

        info!(
            "[{}]: Device connection state: {:?}.",
@@ -1300,6 +1333,13 @@ impl BluetoothMedia {
                guard.insert(addr, None);
            }
            DeviceConnectionStates::Disconnecting => {}
            DeviceConnectionStates::WaitingConnection => {
                let task = topstack::get_runtime().spawn(async move {
                    BluetoothMedia::wait_retry(&tasks, &device_states, &txl, &addr, ts).await;
                    BluetoothMedia::wait_force_enter_connected(&txl, &addr, ts).await;
                });
                guard.insert(addr, Some((task, ts)));
            }
        }
    }

@@ -1716,9 +1756,9 @@ impl BluetoothMedia {
    }

    // Force the media enters the FullyConnected state and then triggers a retry.
    // This function is only used for qualification as a replacement of normal retry.
    // Usually PTS initiates the connection of the necessary profiles, and Floss should notify
    // CRAS of the new audio device regardless of the unconnected profiles.
    // When this function is used for qualification as a replacement of normal retry,
    // PTS could initiate the connection of the necessary profiles, and Floss should
    // notify CRAS of the new audio device regardless of the unconnected profiles.
    // Still retry in the end because some test cases require that.
    fn force_enter_connected(&mut self, address: String) {
        let addr = match RawAddress::from_string(address.clone()) {