revert: drop the portal response timeout
Hyprland's portal shows its picker during SelectSources, so a timeout before the picker step cut users off while choosing. A wedged portal backend looks the same; recording stays in Waiting for capture and the app must prompt.
This commit is contained in:
@@ -176,14 +176,6 @@ fn pipewire_state(message: &str) -> Option<PipeWireState> {
|
||||
PipeWireState::Stopped
|
||||
});
|
||||
}
|
||||
// Requested from the portal, then the picker is shown (or a restore
|
||||
// token is used): only the first step can stall without the user.
|
||||
if message == "PipeWire initialized" {
|
||||
return Some(PipeWireState::Requesting);
|
||||
}
|
||||
if message.starts_with("[pipewire] Asking for ") {
|
||||
return Some(PipeWireState::Selecting);
|
||||
}
|
||||
// The user denied or cancelled the portal request, or it failed.
|
||||
let refused = message.starts_with("[pipewire] Error ")
|
||||
|| (message.starts_with("[pipewire] Failed to ")
|
||||
@@ -193,8 +185,6 @@ fn pipewire_state(message: &str) -> Option<PipeWireState> {
|
||||
|
||||
fn load_pipewire_state() -> Option<PipeWireState> {
|
||||
match PIPEWIRE_STATE.load(Ordering::Relaxed) {
|
||||
state if state == PipeWireState::Requesting as u8 => Some(PipeWireState::Requesting),
|
||||
state if state == PipeWireState::Selecting as u8 => Some(PipeWireState::Selecting),
|
||||
state if state == PipeWireState::Streaming as u8 => Some(PipeWireState::Streaming),
|
||||
state if state == PipeWireState::Stopped as u8 => Some(PipeWireState::Stopped),
|
||||
state if state == PipeWireState::Refused as u8 => Some(PipeWireState::Refused),
|
||||
@@ -887,14 +877,6 @@ mod tests {
|
||||
state("[pipewire] Error selecting screencast source: Timeout"),
|
||||
Some(PipeWireState::Refused)
|
||||
);
|
||||
assert_eq!(
|
||||
state("PipeWire initialized"),
|
||||
Some(PipeWireState::Requesting)
|
||||
);
|
||||
assert_eq!(
|
||||
state("[pipewire] Asking for monitor and window"),
|
||||
Some(PipeWireState::Selecting)
|
||||
);
|
||||
assert_eq!(state("[pipewire] Screencast session created"), None);
|
||||
// OBS cancelling its own pending request at teardown is not a refusal.
|
||||
assert_eq!(state("[portals] Request cancelled"), None);
|
||||
|
||||
@@ -286,15 +286,11 @@ pub struct Health {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PipeWireState {
|
||||
/// A screen-share session was requested from the portal.
|
||||
Requesting = 1,
|
||||
/// The portal is showing its picker or restoring an earlier selection.
|
||||
Selecting = 2,
|
||||
Streaming = 3,
|
||||
Streaming = 1,
|
||||
/// The stream exists but is not delivering frames.
|
||||
Stopped = 4,
|
||||
Stopped = 2,
|
||||
/// The portal request was denied, cancelled by the user, or failed.
|
||||
Refused = 5,
|
||||
Refused = 3,
|
||||
}
|
||||
|
||||
/// Derives the status shown to the user from health samples and output events.
|
||||
@@ -309,7 +305,6 @@ pub struct StatusTracker {
|
||||
stall_limit: Duration,
|
||||
last_written: u64,
|
||||
last_progress: Instant,
|
||||
requesting_since: Option<Instant>,
|
||||
}
|
||||
|
||||
impl StatusTracker {
|
||||
@@ -317,9 +312,6 @@ impl StatusTracker {
|
||||
/// be finalised rather than failing mid-write.
|
||||
pub const DEFAULT_MIN_FREE_BYTES: u64 = 1 << 30;
|
||||
|
||||
/// How long the portal may take to reach its picker or restore a selection.
|
||||
pub const PORTAL_RESPONSE_LIMIT: Duration = Duration::from_secs(10);
|
||||
|
||||
/// Matroska output can stay buffered until its segment closes, so footage
|
||||
/// may appear on disk only once per segment. A stall is declared after two
|
||||
/// segment lengths without growth.
|
||||
@@ -330,7 +322,6 @@ impl StatusTracker {
|
||||
stall_limit: (segment_length * 2 + Duration::from_secs(1)).max(Duration::from_secs(3)),
|
||||
last_written: 0,
|
||||
last_progress: now,
|
||||
requesting_since: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,21 +343,6 @@ impl StatusTracker {
|
||||
self.last_written = health.written_bytes;
|
||||
self.last_progress = now;
|
||||
}
|
||||
// Before the picker appears the portal needs no user input, so a
|
||||
// request stuck there has stalled (seen with Hyprland's portal).
|
||||
if health.pipewire == Some(PipeWireState::Requesting) {
|
||||
let since = *self.requesting_since.get_or_insert(now);
|
||||
if now.duration_since(since) >= Self::PORTAL_RESPONSE_LIMIT {
|
||||
self.status = RecordingStatus::Failed {
|
||||
reason:
|
||||
"the screen-share portal did not respond; select a capture source again"
|
||||
.into(),
|
||||
};
|
||||
return &self.status;
|
||||
}
|
||||
} else {
|
||||
self.requesting_since = None;
|
||||
}
|
||||
if health.pipewire == Some(PipeWireState::Refused) {
|
||||
self.status = RecordingStatus::Failed {
|
||||
reason: "screen capture was not allowed: the source selection was denied, cancelled or failed"
|
||||
@@ -642,38 +618,6 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_portal_that_never_reaches_its_picker_fails() {
|
||||
let start = Instant::now();
|
||||
let mut tracker = StatusTracker::new(start, 0, SEGMENT);
|
||||
let requesting = Health {
|
||||
source_width: 0,
|
||||
source_height: 0,
|
||||
pipewire: Some(PipeWireState::Requesting),
|
||||
..healthy(5000)
|
||||
};
|
||||
assert_eq!(
|
||||
tracker.sample(&requesting, start),
|
||||
&RecordingStatus::WaitingForCapture
|
||||
);
|
||||
// The user may take as long as they like in the picker.
|
||||
let selecting = Health {
|
||||
pipewire: Some(PipeWireState::Selecting),
|
||||
..requesting.clone()
|
||||
};
|
||||
let much_later = start + StatusTracker::PORTAL_RESPONSE_LIMIT * 3;
|
||||
assert_eq!(
|
||||
tracker.sample(&selecting, much_later),
|
||||
&RecordingStatus::WaitingForCapture
|
||||
);
|
||||
let mut tracker = StatusTracker::new(start, 0, SEGMENT);
|
||||
tracker.sample(&requesting, start);
|
||||
assert!(matches!(
|
||||
tracker.sample(&requesting, start + StatusTracker::PORTAL_RESPONSE_LIMIT),
|
||||
RecordingStatus::Failed { reason } if reason.contains("did not respond")
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_errors_fail_and_clean_stops_go_idle() {
|
||||
let mut tracker = StatusTracker::new(Instant::now(), 0, SEGMENT);
|
||||
|
||||
Reference in New Issue
Block a user