Compare commits

...

2 Commits

Author SHA1 Message Date
Robert Resch
dfdfa7fef0 Merge branch 'dev' into edenhaus-go2rtc-preload 2025-12-19 10:47:20 +01:00
Robert Resch
7cd02988a0 Add support for camera preloading to go2rtc 2025-12-09 16:47:22 +01:00
4 changed files with 67 additions and 0 deletions

View File

@@ -691,6 +691,10 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
)
if old_provider != new_provider:
if old_provider:
await old_provider.async_unregister_camera(self)
if new_provider:
await new_provider.async_register_camera(self)
self._webrtc_provider = new_provider
self._invalidate_camera_capabilities_cache()
if write_state:
@@ -947,6 +951,10 @@ async def websocket_update_prefs(
_LOGGER.error("Error setting camera preferences: %s", ex)
connection.send_error(msg["id"], "update_failed", str(ex))
else:
if (camera := hass.data[DATA_COMPONENT].get_entity(entity_id)) and (
provider := camera._webrtc_provider # noqa: SLF001
):
await provider.async_on_camera_prefs_update(camera)
connection.send_result(msg["id"], entity_prefs)

View File

@@ -157,6 +157,27 @@ class CameraWebRTCProvider(ABC):
"""Get an image from the camera."""
return None
async def async_register_camera(
self,
camera: Camera,
) -> None:
"""Will be called when the provider is registered for a camera."""
return ## This is an optional method so we need a default here.
async def async_unregister_camera(
self,
camera: Camera,
) -> None:
"""Will be called when the provider is unregistered for a camera."""
return ## This is an optional method so we need a default here.
async def async_on_camera_prefs_update(
self,
camera: Camera,
) -> None:
"""Will be called when the camera preferences are updated."""
return ## This is an optional method so we need a default here.
@callback
def async_register_webrtc_provider(

View File

@@ -413,12 +413,49 @@ class WebRTCProvider(CameraWebRTCProvider):
],
)
if camera_prefs.preload_stream:
await self._rest_client.preload.enable(camera.entity_id)
else:
await self._rest_client.preload.disable(camera.entity_id)
async def teardown(self) -> None:
"""Tear down the provider."""
for ws_client in self._sessions.values():
await ws_client.close()
self._sessions.clear()
async def async_register_camera(
self,
camera: Camera,
) -> None:
"""Will be called when the provider is registered for a camera."""
camera_prefs = await get_dynamic_camera_stream_settings(
self._hass, camera.entity_id
)
if camera_prefs.preload_stream:
# Stream source is required to enable preload
# _update_stream_source will enable preload if enabled
await self._update_stream_source(camera)
async def async_unregister_camera(
self,
camera: Camera,
) -> None:
"""Will be called when the provider is unregistered for a camera."""
streams = await self._rest_client.streams.list()
if streams.get(camera.entity_id):
# If no stream exists, no need to disable preload
# as a stream is required to enable preload
await self._rest_client.preload.disable(camera.entity_id)
async def async_on_camera_prefs_update(
self,
camera: Camera,
) -> None:
"""Will be called when the camera preferences are updated."""
# Update the stream source to apply new preferences
await self._update_stream_source(camera)
@dataclass
class Go2RtcConfig:

View File

@@ -74,6 +74,7 @@ _API_ALLOW_PATHS = (
"/", # UI static page and version control
"/api", # Main API path
"/api/frame.jpeg", # Snapshot functionality
"/api/preload", # Preload functionality
"/api/schemes", # Supported stream schemes
"/api/streams", # Stream management
"/api/webrtc", # Webrtc functionality