Skip to content

fix(camera): attach the WebRTC provider once the stream source is known - #38

Merged
equake merged 1 commit into
mainfrom
fix/webrtc-provider-refresh
Jul 26, 2026
Merged

equake merged 1 commit into
mainfrom
fix/webrtc-provider-refresh

Conversation

@equake

@equake equake commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Follow-up to #37. The go2rtc registration in v0.8.0 works — confirmed in the field, all three H.265 channels present with both producers:

streams:
  xmeye_…_ch0_camera:
    - rtsp://192.168.16.10:554/…&channel=1&stream=0.sdp
    - ffmpeg:xmeye_…_ch0_camera#video=h264#audio=opus

But nothing consumed them. Companion played H.265 directly, Chrome fell back to the still-image proxy at ~1 fps, and both took a few seconds to start — the signature of the HLS path, not WebRTC.

Cause

Camera.async_refresh_providers() only runs from async_internal_added_to_hass(), when a provider registers/unregisters, or when the CameraEntityFeature.STREAM bit flips. At that first moment:

  • XMEyeCoordinator.async_setup() schedules _connection_loop() as a background task and returns immediately, so coordinator.connected is still False;
  • stream_source() had if not self._coordinator.connected: return None;
  • async_get_supported_provider() gets None and returns None → _webrtc_provider stays None → camera_capabilities is {HLS} for the life of the entity.

The after_dependencies: ["go2rtc"] added in #37 made it worse: previously, if the go2rtc integration set up after the cameras, its async_register_webrtc_provider() fired _async_refresh_providers(hass) and gave a second chance to attach.

Fix

  1. Drop the connected guard from stream_source() — RTSP does not go through the DVRIP alarm socket. This was already listed as an open item in docs/STREAM_INVESTIGATION.md §7.
  2. await self.async_refresh_providers() at the end of _probe_urls(), once the real URL and codec are known.
  3. Re-evaluate providers when privacy is toggled — privacy nulls stream_source(), and HA does not re-check that on its own.

Verifying

With the HA frontend open, in the browser console:

await document.querySelector("home-assistant").hass
  .callWS({type: "camera/capabilities", entity_id: "camera.<your_camera>"})

Before: {frontend_stream_types: ["hls"]}. After: ["hls", "webrtc"].

Then the live view should start near-instantly in Chrome, and /api/streams should show a consumer on xmeye_…_camera plus the ffmpeg producer dialled.

🤖 Generated with Claude Code

https://claude.ai/code/session_011UpaDKeLbpQB7EapQBpKoJ

v0.8.0 registered the go2rtc streams correctly but nothing ever consumed
them: Companion played H.265 directly and Chrome fell back to the
still-image proxy at ~1 fps, both after a few seconds of buffering — the
HLS path, not WebRTC.

Camera.async_refresh_providers() only runs from
async_internal_added_to_hass, when a provider registers/unregisters, or
when the STREAM feature bit flips. At entity-add time
XMEyeCoordinator.async_setup() has only scheduled _connection_loop() as a
background task, so coordinator.connected is still False — and
stream_source() returned None on exactly that condition.
async_get_supported_provider() therefore got None, no provider was
attached, and camera_capabilities stayed HLS-only for the life of the
entity. The after_dependencies on go2rtc added in v0.8.0 made this worse
by removing the second chance the provider's own registration used to
give.

- Drop the `connected` guard from stream_source(); RTSP does not go
  through the DVRIP alarm socket.
- Refresh providers at the end of _probe_urls(), once the real URL and
  codec are known.
- Refresh providers when privacy is toggled, since privacy nulls the
  stream source and HA does not re-evaluate that on its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011UpaDKeLbpQB7EapQBpKoJ
@equake
equake merged commit b82649e into main Jul 26, 2026
4 checks passed
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