feat: SRT/WHIP resilience parity via a shared supervision layer (#20) - #31
Merged
Conversation
joeblau
force-pushed
the
feat/20-srt-whip-resilience-parity
branch
from
July 4, 2026 22:30
896350c to
b6b1ee7
Compare
SRT/WHIP — chosen for low latency — were the LEAST resilient transports: no NWPath supervision, no queue-stall watchdog, no per-path bitrate ceiling, an inert VideoFrameAdmission (setQueueDepth never called → admit() always true), no mic-stall failover, and a plain 1s→30s backoff that burned reconnect attempts while the network was down. Extract RTMP's supervision DECISIONS into a shared, unit-tested StreamCore layer and adopt it in both publishers: - StreamCore (pure, CI-tested; +27 tests): ReconnectBackoff (jittered 1s→30s ladder), classifyPathTransition (path-update classifier), WatchdogEvaluator (queue-stall recycle math), MicStallEvaluator, PathDebounce. Relocated VideoFrameAdmission + NetworkPathSnapshot here (public). The tests pin RTMP's exact constants/rules — including the frozen-queue-no-recycle (app-backgrounding) and metadata-flip-no-clock-bump guards — so the extraction can't drift RTMP's hard-won behavior. - RTMPPublisher: delegates ONLY isolated arithmetic to those deciders; control flow, socket-close ordering, and supervisors are byte-for-byte unchanged (−141 lines, no behavior change). - SessionPublisher: gains the full supervision additively — NWPath supervision, a 2s queue-stall watchdog, single-flight path-gated jittered reconnect (parks instead of burning attempts while down), per-path setPathProfile ceilings (re-seeded on reconnect), live frame-shedding (setQueueDepth + reset), mic-stall failover, and setMaxRetryCount(0) so HaishinKit's retry can't race the app loop. Recovery kicked off from a path debounce runs on a dedicated task so a route-return cancellation can't contaminate the parking reconnect loop. Closes all ~5 gaps. Built via an understand→design pass and three adversarial multi-agent review passes, which caught and this fixes a permanent-dead-air-after-dropout bug and a backoff-defeating task-cancellation bug. StreamCore: 96 tests pass; full app builds against the iOS 27 SDK. Network resilience itself is device-only and must be validated on hardware. fixes #20 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
joeblau
force-pushed
the
feat/20-srt-whip-resilience-parity
branch
from
July 4, 2026 22:47
b6b1ee7 to
8a8ba40
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings SRT/WHIP (
SessionPublisher) up to the RTMP publisher's network-resilience, by extracting RTMP's supervision decisions into a shared, unit-tested StreamCore layer that both publishers use.The gaps (SRT/WHIP had none of these)
NWPath supervision · queue-stall watchdog · per-path bitrate ceiling · frame-shedding admission (
setQueueDepthwas never called →admit()always true) · mic-stall failover · path-gated backoff (the old 1s→30s loop burned attempts while down).Approach — hybrid (pure deciders shared, transport machinery per-publisher)
ReconnectBackoff,classifyPathTransition,WatchdogEvaluator,MicStallEvaluator,PathDebounce. RelocatedVideoFrameAdmission+NetworkPathSnapshothere (public). The tests pin RTMP's exact constants/rules — including the frozen-queue-no-recycle (app-backgrounding) and metadata-flip-no-clock-bump guards.setPathProfile(re-seeded on reconnect), live frame-shedding, mic-stall failover,setMaxRetryCount(0). Recovery from a path debounce runs on a dedicated task so a route-return cancellation can't contaminate the parking reconnect loop.Process
Built via an understand→design workflow and three adversarial multi-agent review passes, which caught and this fixes: a permanent-dead-air-after-dropout bug (
confirmPathLoststranded a still-connectedsession) and a backoff-defeating task-cancellation bug (recovery ran inside a debounce task the route-return cancels).Verification
fixes #20
🤖 Generated with Claude Code