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
30 changes: 30 additions & 0 deletions docs/source/references/cloudxr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,36 @@ control how the headset connects and how the web client is delivered.
prints a banner as it comes up, so ``run`` is often the more useful command
while setting those modes up for the first time.

USB-local startup checks
------------------------

On a clean ``--usb-local`` start, the service records the selected headset's
negotiated USB speed, hub and controller path, and evidence of faster USB
root hubs on the same controller. After its existing adb reverse rules are
ready, it measures three seconds of host-to-headset transfer using the
already served ``/client/bundle.js`` over HTTPS. This finishes before the
browser is opened. The selected headset must first report
``mWakefulness=Awake``; if that cannot be confirmed, no transfer or browser
launch occurs and the JSON report records the incomplete check. If the headset
lacks a usable curl or timer, the service uses a three-second ADB-only transfer
and labels the narrower coverage in the result.

One JSON report is saved under ``<CloudXR install dir>/logs/usb-health/`` for
each USB-local start. It begins before ADB selection, records partial results
when device preparation or a check fails, and refreshes link topology after
a preserved browser reconnect without repeating the active transfer. It
uses a hashed device serial, and keeps at most 20 reports or 14 days of
history. A link below 5000 Mb/s or an incomplete transfer is logged as a
warning and startup continues. ``hostToHeadsetMbps`` is the completed bytes
divided by the full three-second wall-clock interval. Each curl request opens
a new connection, so this includes request and TLS setup. The optional
``hostToHeadsetResponseBodyMbps`` instead divides those same completed bytes
by the sum of curl's ``time_total - time_starttransfer`` intervals. It excludes
setup and gaps between requests; it is a response-body estimate, not sustained
goodput or USB line rate. Neither metric measures headset-to-host traffic or
CloudXR stream throughput. A faster root hub is a topology clue, not proof
that an accessible physical port is free.

Re-open the client on the headset
---------------------------------

Expand Down
26 changes: 13 additions & 13 deletions src/python/isaaccapture/cloudxr/oob_teleop_adb.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,18 +340,15 @@ def headset_wakefulness() -> str:
return m.group(1) if m else ""


def assert_headset_awake(*, timeout: float = 15.0) -> None:
"""Warn-and-wait when the headset is asleep before launching OOB automation.

Quest / PICO devices sleep when the proximity sensor is uncovered
(e.g. the headset is sitting on a desk). In that state, ``am start``
may still register but the screen can return to sleep before the
CONNECT click lands, and WebXR session entry will fail.

Sends ``KEYCODE_WAKEUP`` once and then polls ``mWakefulness`` for up to
``timeout`` seconds. Returns silently once the device is ``Awake``.
Otherwise logs a warning and returns — downstream automation may still
succeed if ``am start`` wakes the device.
def assert_headset_awake(*, timeout: float = 15.0, require_awake: bool = False) -> None:
Comment thread
AndreusNvidius marked this conversation as resolved.
"""Check wakefulness before OOB automation, sending one wake key if asleep.

A sleeping Quest/PICO may accept ``am start`` yet sleep before CONNECT,
preventing WebXR session entry.

Args:
timeout: Seconds to poll after ``KEYCODE_WAKEUP``; zero skips retry polling.
require_awake: Raise ``OobAdbError`` if still not Awake; otherwise warn and return.
"""
wake = headset_wakefulness()
if wake == "Awake":
Expand Down Expand Up @@ -384,10 +381,13 @@ def assert_headset_awake(*, timeout: float = 15.0) -> None:
return

log.warning(
"Headset still appears asleep after %.0fs (wakefulness=%s); continuing anyway.",
"Headset still appears asleep after %.0fs (wakefulness=%s); %s.",
timeout,
wake or "?",
"aborting USB transfer" if require_awake else "continuing anyway",
)
if require_awake:
raise OobAdbError("Headset wakefulness was not confirmed as Awake")


def adb_device_state() -> str:
Expand Down
Loading
Loading