fix(connection): retry startup and clarify sharing status

Public invitations could stop after an early tunnel-process exit, and connection progress and Viewer status did not consistently describe the current attempt or Host state. This maintenance release adds bounded startup retries, aligns enhanced NAT retry feedback across entry paths, and fixes camera-preview and room-entry layout.

The existing route owner and published contracts remain in place. Four-attempt progress is advertised and opted into; older readers retain supported messages. Interaction/chat experiments are outside this PR.

Validation: npm run check (74 files, 1072 tests and production build), npm run check:go (including Windows capture compile), documentation/repository hygiene, 10 production Viewer-entry discovery cases, and a real public-link gate with remote HTTP/WebSocket access and shutdown cleanup all passed. Existing device/network evidence limits remain documented.

## Release notes

### 中文

这是一次维护更新,重点改善公网邀请启动、连接重试反馈和分享状态提示,并修正两处界面布局问题。

- 公网邀请服务在连接就绪前意外退出时,会自动重试,最多重试 3 次;所有尝试仍共用 30 秒启动预算。
- 增强穿透连接在首次尝试失败后最多重试 3 次,重试进度显示为 1/3、2/3、3/3。邀请链接和房间号加入都支持新版进度提示。
- 修正观众状态提示:房主离线时不再误报“没有可用的媒体线路”,服务器连接恢复与媒体恢复也会分别呈现。
- 修正电视内房间号输入界面的居中位置,以及摄像头选择预览被裁切的问题。
- 尚未确认来源声音状态时,不再提前提示“未分享来源声音”。

本次保持现有版本兼容;新版重试进度需要页面与服务端均支持。额外重试不能保证所有网络都能直连。

### English

This maintenance update improves public invitation startup, connection retry feedback, and sharing status messages, with two layout fixes.

- If the public invitation service exits before connecting, Piik retries up to three times within the existing shared 30-second startup budget.
- Enhanced NAT traversal now allows up to three retries after the initial attempt, shown as 1/3, 2/3, and 3/3. Both invitation links and room-code entry support the updated progress display.
- Viewer status now distinguishes an offline host from an unavailable media route, and reports server reconnection separately from media recovery.
- Fixed the alignment of room-code entry inside the TV and cropping in camera-selection previews.
- The missing-source-audio notice now waits until the source's audio availability is known.

Existing version compatibility is preserved. Updated retry progress requires support from both the page and server. Additional retries cannot guarantee a direct connection on every network.
This commit is contained in:
AAA authored and GitHub committed 2026-09-23 22:27:56 +08:00
1 parent 6cc6863294
commit 01821ae7ac
41 files changed
+671 -175

No files matched your search

@@ -102,7 +102,7 @@ continuous rebalance or general load score is introduced.
A Peer opportunity is fenced by its exact parent and endpoint sessions plus
endpoint-transition strength. With NAT traversal disabled, one failed attempt
consumes it. With traversal enabled, availability acquisition and direct
continuation may create at most three candidate connections for that opportunity.
continuation may create at most four candidate connections for that opportunity.
Only an admitted candidate creation spends an attempt; duplicate failure and
timeout messages cannot spend it again. A preparation rejection that cannot
create a connection remains terminal. A new session or strictly stronger
@@ -168,7 +168,10 @@ remaining Peer budget into the existing round-robin direct continuations, not
another retry ledger. No usable SFU route is interrupted by these attempts.
This permits longer total acquisition while keeping every operation bounded and
requiring no polling or independent retry timer. The prepare message reports
the actual candidate's connection attempt, not inferred UI progress.
the actual candidate's connection attempt, not inferred UI progress. Four-attempt
progress is sent only to recipients opting in after HTTP capability discovery;
older pages receive the same candidate without the optional progress field.
This reader support does not change routing authority or its attempt budget.
The five-second no-transport-progress window advances a silent Peer only while
another bounded candidate or SFU fallback remains. It is a route scheduling
+2 -2
View File
@@ -50,7 +50,7 @@ connection acquisition reuses the route controller's existing opportunity ledger
whether a signaled candidate was ordinary, predicted, or end-of-candidates,
and whether the selected remote foundation was ordinary, predicted, or
unknown.
5. The same per-share gate also enables the three-attempt Peer acquisition
5. The same per-share gate also enables the four-attempt Peer acquisition
budget in [ADR-0005](0005-automatic-hybrid-media-routing.md). Browser and
Native candidates use the ordinary server-owned prepare/rollback lifecycle;
no Viewer-owned ICE-restart loop is added. Local public-link and Hosted
@@ -86,7 +86,7 @@ Negative:
may add connectivity checks for up to eight adjacent UDP ports;
- two endpoint-dependent NATs remain sensitive to candidate scheduling and
intervening mappings, so room-wide coverage is not a success guarantee; and
- enabled acquisition can occupy up to three ordinary operation windows when
- enabled acquisition can occupy up to four ordinary operation windows when
one parent remains, yielding between operations to other waiting Viewers.
Predicted connectivity checks originate from participant ICE agents and target
+19 -6
View File
@@ -15,9 +15,9 @@ its content and design boundary.
| Documentation source | [Reader guides](../guide/README.md), with a separate [developer map](../README.md) |
GitHub Pages serves `piik.tv` behind
Cloudflare; both the GitHub origin and Cloudflare edge use HTTPS. Website DNS is
proxied with strict origin TLS verification and origin cache headers respected.
Demo DNS remains unproxied so its UDP listeners stay reachable.
Cloudflare; both the GitHub origin and Cloudflare edge use HTTPS. Website and
Demo HTTP traffic use proxied DNS with origin cache headers respected.
The separate `stun.piik.tv` hostname stays DNS-only for direct UDP connectivity.
GitHub Pages can serve the complete website: it hosts
[static HTML, CSS and JavaScript](https://docs.github.com/en/pages/getting-started-with-github-pages/what-is-github-pages).
@@ -38,19 +38,32 @@ ALLOWED_ORIGINS=https://demo.piik.tv
SITE_ACCESS_PASSWORD=
ROOM_DATABASE_PATH=/var/lib/piik/rooms.sqlite
MAX_VIEWERS_PER_ROOM=20
STUN_URLS=stun:demo.piik.tv:3478
STUN_URLS=stun:stun.piik.tv:3478
NAT_PREDICTION_ENABLED=true
SFU_UDP_PORT=
```
Point `demo.piik.tv` directly at the US server so UDP reaches its STUN listeners;
allow UDP 3478/3479/3480 and terminate HTTPS/WSS at Caddy. The demo uses the
Point both hostnames at the US server: proxy `demo.piik.tv` through Cloudflare,
but leave `stun.piik.tv` DNS-only. Allow UDP 3478/3479/3480 directly to the server;
Cloudflare's ordinary HTTP proxy does not carry STUN. Caddy terminates origin
HTTPS/WSS. The demo uses the
standard [systemd service](./service-management.md#systemd), with its release
under `/opt/piik/current` and configuration at `/etc/piik/piik.env`. The service
unit provides the SQLite state directory. Room ownership, invitations and private-room
admission still apply. The [configuration reference](../standards/configuration.md)
owns each setting and its bounds.
The Demo's Caddy proxy compresses `/assets/*` with zstd/gzip. Successful
content-hashed JavaScript and CSS responses use
`Cache-Control: public, max-age=31536000, immutable`; other responses default to
`no-store`. Match both the hashed filename and a successful response status so
a missing bundle cannot acquire the long cache lifetime. Keep HTML, room APIs,
health responses and signaling outside static caching. New bundles have new
filenames; do not publish different bytes under an existing hashed URL.
Cloudflare caches those static bundles; HTML and API responses remain uncached,
and WebSocket signaling passes through to the same room authority. Changing the
HTTP delivery path does not enable SFU or proxy peer media.
For updates, follow the [application release boundary](../deployment.md#release-boundary)
and its artifact verification, health checks and recovery rules. Routine application
rollback restores the previous executable while keeping current room data. This
+12 -1
View File
@@ -166,6 +166,15 @@ its HTTP/2 fallback. Piik requests `--protocol auto` and
the existing 30-second startup budget. This affects HTTP/WebSocket control only;
media routes, tunnel identity and ordered shutdown keep their existing owners.
DNS failures, API rejection and networks blocking both transports can still fail.
The preceding Quick Tunnel allocation is a single HTTPS request with a 15-second
dependency timeout; failure exits before transport fallback applies. The App's
pre-readiness exit message and exit code do not identify that cause. Match the
same run's `public-tunnel` dependency diagnostics before classifying a report.
Piik retries a child that exits before readiness, up to four starts with a
one-second pause between starts, all within the same 30-second acquisition
deadline. The previous child, output readers and temporary config retire before
the next start. Cancellation and local setup errors stop acquisition; a ready
tunnel retains its original identity and explicit ordered-close owner.
A 2026-09-21 Windows check used the packaged binary with an isolated UDP sink and
TCP forwarder. The previous arguments timed out at 30 seconds without trying TCP.
@@ -177,7 +186,9 @@ establish regional reachability, uninterrupted connector availability or the
cause of reports without matching diagnostics. Upstream
[Quick Tunnel setup](https://github.com/cloudflare/cloudflared/blob/2026.8.3/cmd/cloudflared/tunnel/quick_tunnel.go)
and [protocol fallback](https://github.com/cloudflare/cloudflared/blob/2026.8.3/supervisor/tunnel.go)
own the dependency behavior; Piik adds no separate retry loop.
own the dependency behavior. An early-exit fixture confirms fourth-start recovery
and bounded exhaustion; these checks do not identify a reporter's API or network
failure or guarantee four starts when earlier attempts consume the deadline.
[HTTP 1033](https://developers.cloudflare.com/support/troubleshooting/http-status-codes/cloudflare-1xxx-errors/error-1033/)
means Cloudflare cannot find a healthy tunnel connector. App readiness requires
+1 -1
View File
@@ -43,7 +43,7 @@ production behavior and remaining acceptance.
unsupported, pending, denied or failed access must leave ordinary capture and
stop controls usable. Other capture sessions can keep the border visible.
Browser indicators remain browser-owned.
- Share and source-switch requests ask the Browser for available audio by
- Display/window/tab capture requests ask the Browser for available audio by
default. Missing audio is reported clearly but does not block video-only
sharing. Native screen capture can include system playback audio and native
window capture can include selected-process audio when the platform exposes it.
+16 -1
View File
@@ -52,7 +52,9 @@ over a reused comic's default; text and pure-visual tooltips retain that context
show a Browser and server, not a failed video path. A media-route failure can
coexist with a healthy server connection, and vice versa.
- Connection notice: signaling recovery may coexist with healthy media. It
cannot convert proved playback into waiting.
cannot convert proved playback into waiting or hide media recovery. The
presentation stage owns the primary media status; a coexisting notice never
selects that status or asserts another connection's health.
- Notices: necessary coexisting issues and operation feedback use the existing
pills near the stage; they are not another primary media status. Raw
PeerConnection errors remain diagnostic observations, not persistent red
@@ -61,6 +63,19 @@ over a reused comic's default; text and pure-visual tooltips retain that context
The operation supplies its outcome tone and matching scene together. Neither
the presence of an illustration nor a default checkmark proves success;
partial application retains a limitation instead of claiming completion.
- Source sound: every capture source with confirmed absent source audio keeps
the same neutral notice and detail, including camera capture. This describes
the captured input, not a failure or the mixed output's sound. The microphone
control owns voice state separately; do not hide facts by source category or
infer missing audio while capture details are unknown.
- Host absence: without a proved current picture, a stopped/unknown Host means
waiting for sharing, and an offline Host means waiting for return. A failed
route does not override those facts. Retain route evidence so reconnection
alone cannot claim media recovery; independent playback/server errors retain
their meaning. An authenticated snapshot with an absent Host does not identify
why the Host is absent: use neutral waiting. Only the explicit sharing-stop
event establishes an intentional stop; do not reconstruct it from a retained
share generation or remembered messages.
- Topology: unready edges use the blue pending treatment. Readiness alone cannot
distinguish initial connection from recovery, so this view does not invent a
warning. Confirmed interruption remains owned by the status projection.
+3 -1
View File
@@ -41,7 +41,9 @@ share generation:
Native uses one media socket for IPv4 and, where available, IPv6
direct connections; its STUN survey and best-effort gateway mapping use IPv4.
Availability and background direct acquisition share a bounded budget of
three actual connection attempts per eligible parent/session opportunity.
four actual connection attempts per eligible parent/session opportunity:
the initial attempt plus three retries. The first has no retry label; subsequent
attempts show retry 1/3, 2/3 and 3/3 on pages supporting that progress format.
Retries use the same serial controller and normal operation deadlines;
waiting Viewers and untried parents receive their opportunities first.
It is not a participant capability, route score, or SFU preference. Candidate
+4 -1
View File
@@ -144,7 +144,10 @@ The microphone comic depicts Host commentary gain;
the Viewer's listening-volume comic remains a different action.
Visual source choices (windows, screens and cameras) share named thumbnail cards,
including their focus, hover and refresh treatment. Microphone selection uses
including their focus, hover and refresh treatment. Thumbnails fit the whole frame
at its original aspect ratio within the card; constrain the media box itself so
portrait and wide sources cannot enlarge its layout or be cropped. Keep both
orientations represented in the source-picker preview. Microphone selection uses
device names in a compact selector. Shared enumeration does not make these two
selection tasks visually interchangeable.
+5 -3
View File
@@ -1,6 +1,6 @@
# Current Status
Last updated: 2026-09-21
Last updated: 2026-09-22
This is the compact execution/deployment index. Product modules own behavior,
[verification status](./verification-status.md) owns unresolved physical limits,
@@ -47,8 +47,10 @@ HTTPS; external LiveKit/coturn services remain disabled. Participants, routes an
media remain process-only. This private service is not a public demonstration.
The separate US [public demo](https://demo.piik.tv) is deployed with open site
entry, persistent room authority and P2P-only media. Caddy owns HTTPS, and the
standard systemd service runs the published Server package. Public DNS,
entry, persistent room authority and P2P-only media. Cloudflare fronts HTTP/WSS
and caches static bundles; STUN uses a separate DNS-only hostname. Caddy owns
origin HTTPS, and the standard systemd service runs the published Server package.
Public DNS,
HTTPS, runtime assets, all three STUN listeners and a bounded browser P2P
sharing/stop check passed; the browser check used synthetic video on one network.
The operator record owns exact identity and postflight evidence.
+12 -8
View File
@@ -1,6 +1,6 @@
# Current TODO Ledger
Last reviewed: 2026-09-22
Last reviewed: 2026-09-23
Only **Now** is executable. Product modules own behavior; Git/PRs own completed
history. A parked idea is not implementation authority.
@@ -20,9 +20,9 @@ history. A parked idea is not implementation authority.
- [ ] **Refine the isolated room-interaction prototype.** Review chat, optional
danmaku and participant-targeted reactions for usability, placement and intended
cross-view synchronization. Preserve room authorization and media-route owners.
Accept its combined layout: sharing settings with the picture, wide-screen chat
beside participants, stacked chat on narrow screens and room actions before
diagnostics. Check its theater chat entry and participant menu on real devices;
Accept its combined layout: sharing settings with the picture, floating chat
without page reflow and room actions before diagnostics. Check narrow-screen
keyboard avoidance, its theater entry and participant menu on real devices;
keep chat available independently of sharing.
Retain current room creation: the first share creates a room, an existing room
can resume, and stopping media keeps the opted-in interaction session. Do not
@@ -31,7 +31,9 @@ history. A parked idea is not implementation authority.
## Awaiting Device Or Reporter Evidence
- [ ] **No available media route.** Obtain matched Host/Viewer diagnostics from
- [ ] **No available media route.** A decline is reported since around v1.4;
establish comparable attempts on the same endpoints/network before attributing
a version regression. Obtain matched Host/Viewer diagnostics from
a failed attempt, with version and mode. Inspect candidate exchange, selected
paths, first-frame admission and route rejection separately. The Browser
candidate-queue rejection defect is repaired and regression-tested; current
@@ -49,7 +51,8 @@ history. A parked idea is not implementation authority.
[#396 timeout](https://github.com/TNTcraftHIM/Piik/issues/396#issuecomment-5691465700)
with the updated App. A controlled UDP-blocked/TCP-available reproduction confirms
a dependency configuration defect; the existing tunnel now uses cloudflared's
bounded protocol fallback. [Runtime evidence](./research/cross-platform-client-runtime.md#public-invitation-startup)
bounded protocol fallback and pre-readiness retries within one startup deadline.
[Runtime evidence](./research/cross-platform-client-runtime.md#public-invitation-startup)
separates this fix from DNS, provider and remote access failures. The reporting
environments still need version and diagnostic evidence before assigning a cause.
Demo access failures and public-link HTTP 1033 also remain unconfirmed: current
@@ -164,8 +167,9 @@ not establish better connection success or speed; this note adds no retry policy
and retain Gitee; do not add a self-hosted mirror. Chrome still blocks the
Gitee attachment when Referer is removed. Reopen for new evidence or a
provider review; the warning remains unresolved.
10. **4K in advanced sharing settings.** Deferred until after the current capture
maintenance phase. Add 3840x2160 without changing the default or recommended
10. **4K in advanced sharing settings.** Hold the isolated candidate for joint
review with the next room-interaction release; its compatibility and release
boundary are not yet accepted. Add 3840x2160 without changing the default or recommended
presets. Extend the existing capture, decode and relay bounds together; verify
H.264 level negotiation for 4K at 60 fps. Current strict quality messages reject
`2160p`, so preserve published Browser/App/Server compatibility through explicit