Loading system/gd/rust/linux/stack/src/bluetooth_media.rs +58 −18 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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 => { Loading Loading @@ -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 => { Loading Loading @@ -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; Loading Loading @@ -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]) { Loading @@ -1205,6 +1236,8 @@ impl BluetoothMedia { states.insert(addr, DeviceConnectionStates::FullyConnected); } } } info!( "[{}]: Device connection state: {:?}.", Loading Loading @@ -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))); } } } Loading Loading @@ -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()) { Loading Loading
system/gd/rust/linux/stack/src/bluetooth_media.rs +58 −18 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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 => { Loading Loading @@ -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 => { Loading Loading @@ -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; Loading Loading @@ -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]) { Loading @@ -1205,6 +1236,8 @@ impl BluetoothMedia { states.insert(addr, DeviceConnectionStates::FullyConnected); } } } info!( "[{}]: Device connection state: {:?}.", Loading Loading @@ -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))); } } } Loading Loading @@ -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()) { Loading