Files
punktfunk/clients/apple/Config/Info.plist
T
enricobuehler 14c5e7c11c feat(apple/M2): opt-in background keep-alive (audio + video-drop + timeout)
Backgrounding a live session no longer freezes it when the user opts in: audio
keeps playing (UIBackgroundModes audio), the QUIC connection + pump stay live,
video decode is DROPPED, and a bounded timer auto-disconnects. Off by default.

- PunktfunkConnection.setVideoDropped/isVideoDropped: a tiny lock-guarded flag
  both pumps read every iteration. StreamPump (stage-1), Stage2Pipeline (VT +
  PyroWave) drain nextAU() for flow control but DISCARD the AU before any
  VideoToolbox/Metal work — the crash/jetsam-safe seam (no GPU off-screen).
- SessionModel.enterBackground(timeoutMinutes:) / exitBackground(): set the drop
  flag, mute the mic (privacy — SessionAudio.setMicMuted pauses the capture
  engine), arm a DispatchSourceTimer that disconnect(deliberate:false)s on fire
  (keeps host linger → fast late reconnect). exitBackground clears the flag and
  requestKeyframe()s; the pump's freeze gate auto-arms on the resumed
  frame-index gap so concealed frames are withheld until the IDR re-anchors.
  disconnect() cancels the timer + clears isBackgrounded.
- ContentView scenePhase driver (iOS): .background+streaming+setting →
  enterBackground; .active → exitBackground. scenePhase (not willResignActive)
  so Control-Center/app-switcher peeks don't start the timer.
- Settings → General (iOS-only keepAliveSection): toggle + 1/5/10/30 timeout;
  new keys backgroundKeepAlive (def off) / backgroundTimeoutMinutes (def 10).
- Info.plist: UIBackgroundModes [audio] + NSSupportsLiveActivities (for M3).

macOS swift build + swift test green (142 tests). The iOS-gated scenePhase
handler + settings section are not exercised by the macOS CI target (known §9
gap) — need on-glass verification (audio never gaps, video re-anchors <1s LAN,
timeout ends the session, phone-call audio-steal degrades gracefully).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 18:41:46 +02:00

51 lines
1.8 KiB
Plaintext

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>GCSupportedGameControllers</key>
<array>
<dict>
<key>ProfileName</key>
<string>ExtendedGamepad</string>
</dict>
<dict>
<key>ProfileName</key>
<string>MicroGamepad</string>
</dict>
</array>
<key>NSBonjourServices</key>
<array>
<string>_punktfunk._udp</string>
</array>
<!-- Background keep-alive (opt-in, iOS/iPadOS): the ONLY sanctioned way to keep the long-lived
QUIC socket + pump-thread set alive while backgrounded is the audio background mode, backed
by the session's real, audible remote audio (AVAudioEngine keeps rendering). Video decode is
dropped; a bounded timer auto-disconnects. Never silence-as-keepalive (App Review 2.5.4).
tvOS ignores/tolerates the key; macOS is not gated by it. -->
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<!-- Live Activities (iOS/iPadOS): the Lock-Screen / Dynamic-Island session surface. Updated
locally (pushType nil) from the alive app process — no aps-environment. tvOS/macOS ignore it. -->
<key>NSSupportsLiveActivities</key>
<true/>
<!-- Deep links: punktfunk://connect/<host-uuid>[?launch=<GameEntry.id>]. Emitted by the
launcher widget and Siri/Shortcuts; routed by ContentView.onOpenURL into the existing
connect path. Shared across all three targets (tvOS/macOS accept it harmlessly). -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>io.unom.punktfunk.deeplink</string>
<key>CFBundleURLSchemes</key>
<array>
<string>punktfunk</string>
</array>
</dict>
</array>
</dict>
</plist>