Skip to content

feat(player): sync Philips Hue lights to the picture on tvOS - #374

Merged
bilipp merged 1 commit into
mainfrom
feat/hue-sync
Nov 3, 2026
Merged

bilipp merged 1 commit into
mainfrom
feat/hue-sync

Conversation

@bilipp

@bilipp bilipp commented Nov 3, 2026

Copy link
Copy Markdown
Owner

Summary

Philips Hue light sync on Apple TV, without a Sync Box. Each lamp in the chosen Hue entertainment area takes the colour of the picture beside it, about 50 times a second, changing on cuts. Intensity is set from the player menu (Off, Subtle, Moderate, High, Intense). In multiview the lamps follow the tile with the sound. When playback stops, the lamps go back to how they were.

Implementation

  • Lume/Services/Hue/: pairing over CLIP v2 HTTPS (bridge's self-signed cert via HueTrustDelegate), entertainment-area selection, and HueStream v2 over DTLS 1.2 PSK from a 20 ms tick, driven by HueSyncController.shared.
  • Frame sources per engine (HueFrameSource): KSPlayer (MEPlayer pixel buffer, HuePlayerItemTap for KSAVPlayer), AetherEngine (native path via the same tap; software path, which interlaced live channels take, via LumeAetherSession.displayedSoftwareFrame()), LumeEngine (PlayerSession.videoSamples). AVPlayer and VLC report unsupported. HueSourceRouter picks the multiview tile with the sound.
  • Restore: the area's lights are snapshotted (persisted in hue.restoreSnapshot) before start and each light's whole captured state is sent back on stop or at the next launch after a crash. Streamed colours never reach the CLIP light resources, so restore never diffs against what the bridge reports.
  • tvOS settings: Settings › Philips Hue (discovery, pairing, area, intensity, sensitivity notice, Test Lights), plus a Hue panel in the player controls.
  • BonjourServiceBrowser is shared with recording-server discovery.

Decisions

  • tvOS only; Lume Pro (PremiumFeature.hueSync).
  • KSPlayer, AetherEngine and LumeEngine supported; AVPlayer and VLC not.
  • Intensity: Off plus 4 levels, saved device-locally.
  • Application key and clientkey in the Keychain, never synced; bridge host/id and area id in hue.* UserDefaults, excluded from DebugLogExporter. No keys, bridge id/IP or area ids in logs or exports.
  • No retries; a start the bridge refuses (area in use) leaves lamps and any leftover snapshot untouched.
  • Deferred: the 50 Hz tick runs on the MainActor; multiview AVPlayer/VLC tiles hold the last colour; the Local Network Info.plist entries apply on all platforms. Also included, outside Hue: the RecordingServerDiscovery refactor onto the shared browser and a PerfLumeCloudFeed fix.

Testing

  • Acceptance criteria met: verified on an Apple TV with a Hue bridge (KSPlayer, LumeEngine, AetherEngine incl. interlaced channels, Test Lights, restore, multiview)
  • Builds clean (tvOS device; iOS simulator)
  • Tests pass: LumeTests on iPhone 17 Pro / iOS 26.5 (Hue suites re-run green after fixing 4 stale tests)
  • SwiftLint clean
  • Tests added: Hue client, CLIP models, discovery, channel layout, sampler, smoother, stream messages, sync controller, settings, test pattern, localization
  • UI verified on simulator — n/a: tvOS-only feature, verified on device; no UI tests for the tvOS views yet

Platforms

  • iOS / iPadOS
  • tvOS
  • macOS
  • visionOS

Related

  • Requires bilipp/LumeEngine branch feat/frame-sample-tap (VideoSampleTap); merge that first, since ../LumeEngine on main won't compile LumeEngineHueFrameSource.

The lamps of a Hue entertainment area follow the picture beside them at
about 50 Hz over HueStream v2 (DTLS 1.2 PSK), with intensity from Subtle
to Intense in the player menu. In multiview they follow the tile with
the sound. Before streaming, Lume saves each light's state and puts it
back on stop, and at the next launch if a crash left a snapshot.

- Frames come from KSPlayer, AetherEngine (native and software paths)
  and LumeEngine (VideoSampleTap); AVPlayer and VLC are unsupported.
- Pairing, area choice, a sensitivity notice and a Test Lights button
  live in Settings › Philips Hue. Lume Pro, tvOS only.
- Keys stay in the Keychain; bridge, area and keys never reach logs.
- Shares a Bonjour browser with recording-server discovery.

Needs bilipp/LumeEngine feat/frame-sample-tap.
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