15 KiB
v0.9.0 connection and support work
Status: project owner accepted the revised normal-use UI/support baseline for immediate v0.9.0 release. Extended network/storage/lifecycle validation remains explicitly deferred below. GitHub publication is pending; the agent did not install this update on a device.
Implemented scope
- Android v0.9.0, version code 6, signed with the existing release key. The approved screen-timeout fix remains included.
- Capture activity and receiver status are separate. Local encoding cannot turn the status green. A valid, recent PONG is required for Connected · receiver responding; this does not prove decoded/visible picture delivery.
- Connecting, awaiting confirmation, unreachable/address errors, reply timeout, disconnected/retry states have fixed actionable text and amber styling. Encoder counters no longer overwrite receiver status. RTT resets on each attempt/disconnect. A 10-second reply deadline closes stalled connections, including blocked initial writes through the reader deadline.
- Pairing rejection is currently connection closure, not a distinct wire error. The phone suggests checking pairing/relaunching but does not falsely assert a confirmed wrong-code diagnosis. Protocol-version errors receive update guidance.
- Phone Settings → About shows version, version code, build label and debug/release type. Headset Settings → About / Export logs shows receiver version and Git build identifier (including dirty/source fallback).
- Both About surfaces explicitly export bounded diagnostics to Downloads and report success/failure. Headset export requires a second deliberate activation, displays the saved filename, and runs file I/O on a worker rather than the render loop.
- Phone Find headset on LAN performs a bounded automatic network search rather than requiring the user to know an IP. Results show receiver name, IP and version; selection is explicit even for one result. The chosen address/name is remembered, but a name is not authenticated identity. Capture consent and pairing remain required.
Discovery decision and wire contract
Android NSD/DNS-SD was evaluated. It is a good standard option, but using it here would require a receiver-side mDNS implementation/library or additional Avahi service/runtime integration. This first bounded same-LAN implementation instead uses IPv4 UDP, without a new headset daemon or dependency. This is a PhoneCast-specific finder, not mDNS interoperability or cryptographic identity.
- Receiver listens on UDP 49322 only while the VR stream receiver runs; failure is non-fatal and manual TCP still works. TCP streaming defaults to 49321.
- Query: ASCII
PCVR_DISCOVER 1 <32 lowercase hexadecimal nonce>. - Unicast reply: ASCII
PCVR_RECEIVER 1 <same nonce> <TCP port> <version> <name>. - Reply version is digits/dots up to 16 characters; hostname-derived name is sanitized ASCII, at most 48 characters. No pairing code, user stream metadata or payload is advertised.
- Receiver accepts private/link-local IPv4 sources (and loopback for tests), validates exact query size/content, and caps replies globally at 20/second. Responses are under 160 bytes.
- Android broadcasts to discovered interface broadcast addresses and limited broadcast, sends at most once/second for four seconds, limits interfaces/results/received packets, validates nonce and fields, and cancels on activity stop. A temporary Wi-Fi multicast lock is released on every exit.
- Android's existing TCP endpoint is fixed at 49321, so the finder deliberately ignores custom-port responders. Manual address UI likewise retains its existing default-port behavior.
- Android adds normal ACCESS_WIFI_STATE and CHANGE_WIFI_MULTICAST_STATE permissions, not location, root or broad storage permission. INTERNET remains required. Future Android local-network permission changes need separate compatibility validation.
- Windows private-network firewall rules must also allow UDP 49322 for discovery. Never recommend router port forwarding or disabling security.
Guest/client isolation, VPNs, broadcast-blocked networks, cross-subnet and IPv6-only networks can prevent discovery. Manual IP entry remains available; discovery failure is not proof that TCP is unreachable. Existing v0.8 receivers do not implement this finder.
Changed-IP recovery: stop casting, run Find headset again, explicitly select the receiver, and start a new consented cast. Silent identity-based rediscovery/retargeting during an active reconnect is not implemented; it remains follow-up work with the trusted-device identity model. There is no continuous background scan or automatic capture start.
Diagnostic export privacy and limits
Android records its own fixed safe connection events plus periodic capture/receiver/frame-drop/RTT counters. The persistent ring is capped at 64 KiB and exported through MediaStore Downloads, using pending-file cleanup on failure. It does not read unrestricted system logcat, touch/notification contents, addresses, pairing credentials, or screen/audio samples. Android shared-storage APIs keep this independent of broad storage permission on API 29+.
Native export reads at most the trailing 256 KiB of the standard receiver log ($XDG_STATE_HOME/phonecast-vr/receiver.log, default ~/.local/state/phonecast-vr/receiver.log). Only explicitly allowed numeric diagnostic counters and fixed connection/pairing-result messages are retained; arbitrary text, notification/input/audio payloads, addresses and credentials are excluded. Filtered events are capped at 64 KiB plus a short header. Downloads honors XDG user-dirs configuration, with ~/Downloads fallback; exported Linux files are owner-only. Custom launch/log locations may yield a clearly marked log-unavailable report. The Windows fallback uses its standard user paths; this work primarily targets the native headset launcher.
Export is a safe support summary, not a full raw log dump. Review files before sharing privately. Native About reports the timestamped filename and saved Downloads location; phone export reports its exact saved path. Failed exports must not disrupt streaming.
Test and release checklist
- JVM tests for fixed safe errors and bounded/correlated discovery parsing.
- Real loopback TCP tests for TCP-without-PONG, invalid PONG, responsive PONG, disconnect/reconnect RTT reset, unreachable receiver and no-reply timeout.
- Native tests for discovery query validation, real UDP query/reply/start-stop, About navigation/confirmation, safe export filtering, bounds, localized Downloads and failed export.
- Local server candidate route/isolation tests; v0.8 aliases remain separate.
- Final Android debug/release JVM tests (49 per variant), both APK assemblies and both lint tasks pass after the timeout-reason race fix.
- Windows build and all 11 CTest tests pass.
- Final Linux ARM64 build and QEMU portable/audio/support/runtime tests pass after final UI/export changes.
- APK signature/version, ARM64 package contents/modes, checksum and live-download verification pass.
- Owner accepted the revised normal-use UI/support baseline for immediate release.
- Extended individual network/storage/lifecycle cases in the matrix below remain separately unvalidated.
The initial timeout test exposed a secondary reader-close error hiding the writer's actual reply timeout; reason preservation was corrected before final packaging. No new headset audio backend or render-path change is included. Existing decoder/Vulkan reliability follow-ups are not claimed fixed.
Release artifacts and local publication
Artifacts are ignored build output under out/packages:
phonecast-vr-v0.9.0-android.apk, SHA-256c16adb399f0c16c830873d65fa063a61161d342d4eee1cad4754bf7b1312382d.phonecast-vr-v0.9.0-steam-frame-arm64.tar.gz, SHA-25618b4a3643575920af86a0373877a2c60bfe73210fc1446a3fcc99a057e7ecc99.SHA256SUMS-v0.9.0contains both entries. The APK verifies with the same certificate as v0.8 and reports version 0.9.0/code 6. Receiver About uses build5195329-dirtyfor this uncommitted candidate.
The archive was created in Linux with stripped AArch64 binaries, 755 directories/executables/install scripts, 644 data/templates, and installer syntax checks. Only the local Node download server was restarted to expose a clearly labelled v0.9.0 test-candidate section. Both live downloads and served checksums match local artifacts. The old v0.8 aliases/bootstrap remain unchanged; the stable APK still matches the earlier code-4 timeout-fix artifact.
No phone/headset app, SteamVR, game or audio service was restarted or installed by this task. No GitHub release, commit or push was made. The owner subsequently accepted the revised release baseline; public GitHub publication remains a separate step. These artifacts were built from the working tree before the v0.9 source commit. The full implementation/documentation must be committed before tagging so the release's source includes these features. The tested receiver currently identifies its build as 5195329-dirty; rebuilding after a clean commit would change build metadata and artifact checksums and requires fresh verification.
Release documentation closure
The README now targets v0.9.0 filenames/install steps and explicitly explains the headset's two-selection export confirmation (not a thumbstick double-click). Copy-ready GitHub release notes are in docs/releases/v0.9.0.md. The local server is labelled release-ready/GitHub-publication-pending, and its revised export instructions and both live artifact hashes were checked. Three server/bootstrap tests, all 11 Windows CTest tests, README local-link checks and artifact checksums pass for the documentation closure; no native/Android source or binary changed in this closure. The full Android/ARM64 validation above remains the evidence for these exact artifacts.
The owner will create the GitHub release. Upload both versioned artifacts and SHA256SUMS-v0.9.0, and commit/tag all implementation/documentation changes first. GitHub release publication and tagging remain the owner's separate steps. Source commit/push is handled separately on the owner's request; it does not rebuild or change these tested artifacts.
Owner feedback and revision 6
The owner reported that the initial candidate works, receiver shutdown produces useful connection feedback, wrong pairing/IP produce relevant messages, and native log export works. Wrong-pairing retries rapidly alternated Connecting/Disconnected and changed page height; wrong-IP retries produced a slower variant. This is evidence for those exercised cases, not separate approval of discovery/multiple receivers, all About controls or storage failure paths.
Revision 6 addresses the feedback:
- Retain the actionable failure across retry attempts until a valid PONG arrives, rather than flashing through Connecting/Awaiting states on each retry. Duplicate connection notifications are suppressed. Exponential backoff resets after a receiver-confirmed attempt, not merely TCP establishment, avoiding rapid wrong-code retry loops.
- Use a stable short heading and fixed-line details/metrics areas so retry text and counters do not grow/shrink the status card. Tap the details text for the full message if it is ellipsized at large font sizes.
- Native export filename is now
phonecast-headset-<timestamp>.txt. The originalpc-vrwas only an abbreviation for PhoneCast VR, not another application or format. - Dashboard shortcut instructions now explicitly say CLOSE DASHBOARD FOR HOTKEYS. Shortcut behavior/input priority is unchanged.
- Loopback regression tests cover repeated rejected handshakes without renewed Connecting/Awaiting text; presentation tests cover stable headings. Export tests check the clearer filename prefix.
Android debug/release tests, APKs and lint pass; Windows all 11 CTest tests and native ARM64/QEMU portable/audio/support/runtime tests pass. Both revised live downloads and checksums were verified without restarting the Node server. No device app/runtime was restarted. The owner subsequently said the revised update looks good and requested immediate release documentation. This closes the normal-use presentation baseline, not every independently witnessed discovery, storage-failure or lifecycle test.
Dashboard Settings assessment — proposal, not implemented
Moving Settings into the existing PhoneCast dashboard is moderate work rather than a settings-model rewrite. Keep the portable controller, transactional Apply/Cancel and live previews; add dashboard page navigation (Home → Settings → category), a dashboard-sized layout and shared settings pointer/slider handling. The existing dashboard handles only quick-action mouse-downs, whereas the floating panel owns settings row/drag events, so this is not just replacing a texture. Navigation, dirty-draft cancellation, dashboard closing/recreation and preview cleanup need regression coverage. Phone/notification/start-location previews can remain independent scene surfaces even if the settings menu stops floating.
A preliminary estimate is 1–2 focused development days plus physical headset layout/input tuning; it is not a committed delivery date. The current candidate still uses the floating Settings surface. Do not implement this proposal without the owner's follow-up approval.
Extended physical validation matrix (remaining cases deferred by release acceptance)
- Install both test endpoints; check About version/build information and retain saved settings/pairing. Stop casting and quit the receiver before updating.
- Receiver absent/wrong IP: amber error, no misleading green capture text, local drops explained, retry visible.
- Wrong pairing code and incompatible receiver: useful guidance, no claim that capture means pairing success.
- Correct receiver: green only after response, regular video/audio/control behavior unchanged; loss/reconnect removes/restores green and resets RTT.
- Find one and multiple receivers; require selection, check remembered-name hint, changed-IP search, activity cancellation and repeated search. Test blocked/guest network and manual fallback.
- Phone/headset exports are readable in Downloads, show correct versions, have bounded size, contain useful connection diagnostics, and exclude pairing/private content. Exercise storage failure separately.
- Validate portrait/landscape, consent cancellation, activity resume, stop/restart, and standalone-game input coexistence. Retain screen-timeout restoration checks.
Do not mark these physical cases complete from compilation, loopback tests or simulated receivers.