Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions deps/cloudxr/webxr_client/helpers/react/CloudXRComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ const WARMUP_COMPLETE_LOG_PATTERN =
// override via the streamAttachTimeoutMs prop, not by lowering this default.
const STREAM_ATTACH_BASE_TIMEOUT_MS = 120000; // 2 minutes

// Defaults for the warmupBeginTimeoutMs/warmupEndTimeoutMs props below. Both shorter than
// STREAM_ATTACH_BASE_TIMEOUT_MS and, unlike it, neither grows per reconnect attempt (see
// armWarmupBeginTimer/armWarmupEndTimer): once the stream has attached at all, decoder warm-up
// is a fast, bounded startup step (server encoder priming), not something that legitimately
// takes longer on a slow network the way the initial attach can. Split into two deadlines
// because "no warm-up signal at all since attaching" and "warm-up started but never finishes"
// are different failure modes worth distinguishing in the synthetic error message.
const WARMUP_BEGIN_BASE_TIMEOUT_MS = 10000; // 10 seconds - first warm-up log since onStreamStarted
const WARMUP_END_BASE_TIMEOUT_MS = 30000; // 30 seconds - completion since warm-up began
// Defaults for the warmupBeginTimeoutMs/warmupEndTimeoutMs props below. 0 disables warm-up
// detection: a CloudXR runtime with no OpenXR app streams idle frames that count as warm-up
// frames, so a fixed deadline can tear down a healthy session that is only waiting for an app.
// Callers that want detection (e.g. tests) set the props. Neither deadline grows per reconnect
// attempt (see armWarmupBeginTimer/armWarmupEndTimer). Split into two because "no warm-up signal
// at all since attaching" and "warm-up started but never finishes" are different failure modes
// worth distinguishing in the synthetic error message.
const WARMUP_BEGIN_BASE_TIMEOUT_MS = 0; // disabled; first warm-up log since onStreamStarted
const WARMUP_END_BASE_TIMEOUT_MS = 0; // disabled; completion since warm-up began

// setTimeout's delay is stored as a 32-bit signed int internally; a value above this overflows
// and fires (almost) immediately instead of waiting - the opposite of what a long configured
Expand Down Expand Up @@ -151,7 +151,8 @@ interface CloudXRComponentProps {
* only whether the resulting synthetic error gets retried depends on `reconnect`. Doubles on
* every reconnect attempt (this value, then x2, then x4, ...) so a connection that's genuinely
* just slow, not stuck, gets more time on each retry instead of being cut off at the same fixed
* threshold every attempt. Defaults to STREAM_ATTACH_BASE_TIMEOUT_MS (2 minutes).
* threshold every attempt. Defaults to STREAM_ATTACH_BASE_TIMEOUT_MS (2 minutes). A value <= 0
* disables this detection.
*/
streamAttachTimeoutMs?: number;

Expand All @@ -166,7 +167,8 @@ interface CloudXRComponentProps {
* message. Like warmupEndTimeoutMs, does NOT grow per reconnect attempt - warm-up is a fast,
* bounded server-side priming step once the stream has attached at all, not something that
* legitimately takes longer under retry the way the initial attach can. Defaults to
* WARMUP_BEGIN_BASE_TIMEOUT_MS (10 seconds).
* WARMUP_BEGIN_BASE_TIMEOUT_MS (0, disabled). A value <= 0 disables this detection, as does
* warmupEndTimeoutMs <= 0.
*/
warmupBeginTimeoutMs?: number;

Expand All @@ -176,7 +178,8 @@ interface CloudXRComponentProps {
* the first warm-up log arrives and cleared by WARMUP_COMPLETE_LOG_PATTERN). See
* warmupBeginTimeoutMs's doc comment for why this is a separate deadline. Does NOT grow per
* reconnect attempt, for the same reason warmupBeginTimeoutMs doesn't. Defaults to
* WARMUP_END_BASE_TIMEOUT_MS (30 seconds).
* WARMUP_END_BASE_TIMEOUT_MS (0, disabled). A value <= 0 disables this detection and
* warmupBeginTimeoutMs too (all warm-up detection); stream-attach detection is unaffected.
*/
warmupEndTimeoutMs?: number;

Expand Down Expand Up @@ -357,6 +360,8 @@ export default function CloudXRComponent({
*/
const armStreamAttachTimer = useCallback(
(cxrSession: CloudXR.Session) => {
// <= 0 disables detection; setTimeout(fn, 0) would fire immediately instead.
if (streamAttachBaseTimeoutMs <= 0) return;
const attemptForThisTimer = reconnectAttemptRef.current;
const attachTimeoutMs = Math.min(
streamAttachBaseTimeoutMs * 2 ** attemptForThisTimer,
Expand Down Expand Up @@ -397,6 +402,8 @@ export default function CloudXRComponent({
*/
const armWarmupBeginTimer = useCallback(
(cxrSession: CloudXR.Session) => {
// warmupEndTimeoutMs <= 0 turns off all warm-up detection; the begin timer only hands off to the end timer.
if (warmupBeginBaseTimeoutMs <= 0 || warmupEndBaseTimeoutMs <= 0) return;
// Same overflow guard as armStreamAttachTimer: an uncapped delay above setTimeout's
// ~24.8-day int32 limit wraps and fires near-immediately instead of waiting.
const timeoutMs = Math.min(warmupBeginBaseTimeoutMs, MAX_SET_TIMEOUT_MS);
Expand All @@ -416,7 +423,7 @@ export default function CloudXRComponent({
} as CloudXR.StreamingError);
}, timeoutMs);
},
[warmupBeginBaseTimeoutMs]
[warmupBeginBaseTimeoutMs, warmupEndBaseTimeoutMs]
);

/**
Expand All @@ -429,6 +436,7 @@ export default function CloudXRComponent({
*/
const armWarmupEndTimer = useCallback(
(cxrSession: CloudXR.Session) => {
if (warmupEndBaseTimeoutMs <= 0) return; // disabled, see armStreamAttachTimer
const timeoutMs = Math.min(warmupEndBaseTimeoutMs, MAX_SET_TIMEOUT_MS);
warmupEndTimerRef.current = setTimeout(() => {
warmupEndTimerRef.current = null;
Expand Down
4 changes: 2 additions & 2 deletions deps/cloudxr/webxr_client/src/CloudXR2DUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,8 @@ export class CloudXR2DUI {
reconnectMaxAttempts: 3,
reconnectDelayMs: 3000,
streamAttachTimeoutMs: 120000,
warmupBeginTimeoutMs: 10000,
warmupEndTimeoutMs: 30000,
warmupBeginTimeoutMs: 0,
warmupEndTimeoutMs: 0,
teleopPath: DEFAULT_TELEOP_PATH,
};
}
Expand Down
6 changes: 3 additions & 3 deletions deps/cloudxr/webxr_client/src/config/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,21 +265,21 @@ export const URL_PARAMS: UrlParam[] = [
elementId: 'cloudxrStreamAttachTimeoutMs',
isValid: isNumber,
description:
'Base timeout for detecting a stream that never attaches ("passthrough-only"), in milliseconds. Independent of retry.',
'Base timeout for detecting a stream that never attaches ("passthrough-only"), in milliseconds. Independent of retry. 0 disables.',
},
{
key: 'warmupBeginTimeoutMs',
elementId: 'cloudxrWarmupBeginTimeoutMs',
isValid: isNumber,
description:
'Timeout for detecting a stream that attached but produced no decoder warm-up signal at all, in milliseconds. Does not grow on retry.',
'Timeout for detecting a stream that attached but produced no decoder warm-up signal at all, in milliseconds. Does not grow on retry. 0 disables.',
},
{
key: 'warmupEndTimeoutMs',
elementId: 'cloudxrWarmupEndTimeoutMs',
isValid: isNumber,
description:
'Timeout for detecting decoder warm-up that began but never finished, in milliseconds. Does not grow on retry.',
'Timeout for detecting decoder warm-up that began but never finished, in milliseconds. Does not grow on retry. 0 disables all warm-up detection, including the begin timeout.',
},
{
key: 'proxyUrl',
Expand Down
18 changes: 10 additions & 8 deletions deps/cloudxr/webxr_client/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1563,14 +1563,14 @@ <h4 class="advanced-divider">Advanced settings</h4>
<div class="config-text">
How long to wait for the video stream to attach before treating the session as
stuck ("passthrough-only" - entered XR with nothing rendering). Independent of
Retry on Error above: this detection always runs; doubles on each retry attempt
when retry is also on.
Retry on Error above: this detection runs even with retry off; doubles on each
retry attempt when retry is also on. Set to 0 to disable.
</div>
</div>

<div class="config-section">
<label for="cloudxrWarmupBeginTimeoutMs" class="input-label"
>Warm-up Begin Timeout (ms, default: 10000 / 10 seconds)</label
>Warm-up Begin Timeout (ms, default: 0 / disabled)</label
>
<input
id="cloudxrWarmupBeginTimeoutMs"
Expand All @@ -1580,18 +1580,19 @@ <h4 class="advanced-divider">Advanced settings</h4>
step="1000"
placeholder="Warm-up begin timeout in ms"
spellcheck="false"
value="10000"
value="0"
/>
<div class="config-text">
How long to wait, after the stream attaches, for the first sign that decoder
warm-up has started before treating the session as stuck. Independent of Stream
Attach Timeout above (a separate, later window); does not grow on retry.
Attach Timeout above (a separate, later window); does not grow on retry. Set to 0
to disable.
</div>
</div>

<div class="config-section">
<label for="cloudxrWarmupEndTimeoutMs" class="input-label"
>Warm-up End Timeout (ms, default: 30000 / 30 seconds)</label
>Warm-up End Timeout (ms, default: 0 / disabled)</label
>
<input
id="cloudxrWarmupEndTimeoutMs"
Expand All @@ -1601,11 +1602,12 @@ <h4 class="advanced-divider">Advanced settings</h4>
step="1000"
placeholder="Warm-up end timeout in ms"
spellcheck="false"
value="30000"
value="0"
/>
<div class="config-text">
How long to wait for decoder warm-up to finish once it has begun before treating
the session as stuck. Does not grow on retry.
the session as stuck. Does not grow on retry. Set to 0 to disable all warm-up
detection, including the Warm-up Begin Timeout above.
</div>
</div>

Expand Down
Loading