feat: throttle the broadcast under thermal and Low Power pressure#15
Merged
Conversation
The broadcast had no environmental awareness: a healthy-network stream encoded at full bitrate and frame rate until iOS hard-throttled or terminated it under heat — the critical risk for the long streams the app targets. Add a thermal + Low Power governor that sheds encoder, network, and camera load first, reusing the existing adaptive path rather than adding a parallel one. - ThermalPowerGovernor maps ProcessInfo thermal + Low Power state to a ceiling (bitrate scale, frame-rate cap, facecam on/off): nominal = full, Low Power = 0.75x/30fps, serious = 0.6x/24fps, critical = 0.35x/10fps. - BroadcastAdaptiveBitRateController folds the thermal ceiling into effectiveMaximum (so the upward probe cannot exceed it) and a shared frameInterval() helper (the more restrictive of congestion vs thermal). Both RTMP and SRT/WHIP inherit it. - ScreenCaptureController observes thermalStateDidChange and the power-state notification, dedupes, slows capture pacing, drops the facecam under pressure, and exposes an observable thermalNotice for the future stats HUD. Holds across interface changes (clamped to effectiveMaximum) and on SRT/WHIP connect — which emit no reset event — by seeding the encoder from the controller target. ScreenCaptureKit is device-only, so this is verified by compiling both the simulator and device SDKs; on-device runtime validation is still required. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Implements M1 from the architecture audit — the highest-leverage critical gap: the broadcast had no thermal or battery awareness at all, so a healthy-network stream encoded at full bitrate/frame rate until iOS hard-throttled or killed it under heat (the critical risk for the long streams this app targets).
This adds a governor that sheds encoder, network, and camera load first, and it reuses the existing adaptive path rather than adding a parallel throttle.
How it works
ThermalPowerGovernor(new) — pureProcessInfothermal + Low-Power state →ThermalPowerCeiling{ bitRateScale, frameRateCap, allowPiP, notice }.BroadcastAdaptiveBitRateController— the thermal ceiling folds intoeffectiveMaximum(so the upward probe can't exceed it) and a sharedframeInterval(severe:)(takes the more restrictive of congestion vs thermal). Both RTMP and SRT/WHIP inherit it.ScreenCaptureController— observesthermalStateDidChange+NSProcessInfoPowerStateDidChange, dedupes vialastAppliedCeiling, slows capture pacing (targetFrameInterval), drops the facecam under pressure, and exposes an observablethermalNoticefor the future stats HUD (M3).Robustness (from an adversarial review of the diff)
An automated review flagged four issues, all fixed here:
effectiveMaximum, so the thermal cap survives the switch..reset, so the encoder is now seeded from the controller target inmakeVideoSettingsand re-asserted withapplyCurrentTarget(to:)right after connect.healthySecondsreset so brief thermal flapping can't keep restarting the up-probe.Verification
ScreenCaptureKit is device-only, so this is compile-verified on both the iOS Simulator SDK (governor + publishers + ABR + stub) and the iOS device SDK (real
ScreenCaptureController+ capture-side profile). On-device runtime validation under sustained thermal load is still required before this can be considered done (a 30-min hot-stream test per the audit's Phase-1 verification note).🤖 Generated with Claude Code