Skip to content

feat: throttle the broadcast under thermal and Low Power pressure#15

Merged
joeblau merged 1 commit into
mainfrom
feat/thermal-power-governor
Jul 4, 2026
Merged

feat: throttle the broadcast under thermal and Low Power pressure#15
joeblau merged 1 commit into
mainfrom
feat/thermal-power-governor

Conversation

@joeblau

@joeblau joeblau commented Jul 4, 2026

Copy link
Copy Markdown
Owner

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

Device state Bitrate FPS cap Facecam
Nominal / Fair full full on
Low Power Mode ×0.75 30 off
Serious (warm) ×0.6 24 off
Critical (hot) ×0.35 10 off
  • ThermalPowerGovernor (new) — pure ProcessInfo thermal + Low-Power state → ThermalPowerCeiling{ bitRateScale, frameRateCap, allowPiP, notice }.
  • BroadcastAdaptiveBitRateController — the thermal ceiling folds into effectiveMaximum (so the upward probe can't exceed it) and a shared frameInterval(severe:) (takes the more restrictive of congestion vs thermal). Both RTMP and SRT/WHIP inherit it.
  • ScreenCaptureController — observes thermalStateDidChange + NSProcessInfoPowerStateDidChange, dedupes via lastAppliedCeiling, slows capture pacing (targetFrameInterval), drops the facecam under pressure, and exposes an observable thermalNotice for the future stats HUD (M3).

Robustness (from an adversarial review of the diff)

An automated review flagged four issues, all fixed here:

  • Interface change (Wi-Fi↔5G) re-seeds bitrate → now clamped to effectiveMaximum, so the thermal cap survives the switch.
  • SRT/WHIP go-live while hot — those transports emit no .reset, so the encoder is now seeded from the controller target in makeVideoSettings and re-asserted with applyCurrentTarget(to:) right after connect.
  • Out-of-order applies — the per-event Task chains on the previous one (submission-ordered).
  • Recovery starvation — dropped a healthySeconds reset 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

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>
@joeblau joeblau merged commit fe7c954 into main Jul 4, 2026
1 check passed
@joeblau joeblau deleted the feat/thermal-power-governor branch July 4, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant