Refactor camera.webrtc.register_ice_server (#129024)

* Refactor camera.webrtc.register_ice_server

* Apply suggestions from code review

Co-authored-by: Robert Resch <robert@resch.dev>

* Add missing import

---------

Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
Erik Montnemery 2024-10-23 11:49:39 +02:00 committed by GitHub
parent eb45b89557
commit 2c79173d20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 48 additions and 30 deletions

View File

@ -89,8 +89,8 @@ from .webrtc import (
RTCIceServer, RTCIceServer,
WebRTCClientConfiguration, WebRTCClientConfiguration,
async_get_supported_providers, async_get_supported_providers,
async_register_ice_servers,
async_register_rtsp_to_web_rtc_provider, # noqa: F401 async_register_rtsp_to_web_rtc_provider, # noqa: F401
register_ice_server,
ws_get_client_config, ws_get_client_config,
) )
@ -401,10 +401,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
SERVICE_RECORD, CAMERA_SERVICE_RECORD, async_handle_record_service SERVICE_RECORD, CAMERA_SERVICE_RECORD, async_handle_record_service
) )
async def get_ice_server() -> RTCIceServer: @callback
return RTCIceServer(urls="stun:stun.home-assistant.io:80") def get_ice_servers() -> list[RTCIceServer]:
return [RTCIceServer(urls="stun:stun.home-assistant.io:80")]
register_ice_server(hass, get_ice_server) async_register_ice_servers(hass, get_ice_servers)
return True return True
@ -741,9 +742,11 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
"""Return the WebRTC client configuration and extend it with the registered ice servers.""" """Return the WebRTC client configuration and extend it with the registered ice servers."""
config = await self._async_get_webrtc_client_configuration() config = await self._async_get_webrtc_client_configuration()
ice_servers = await asyncio.gather( ice_servers = [
*[server() for server in self.hass.data.get(DATA_ICE_SERVERS, [])] server
) for servers in self.hass.data.get(DATA_ICE_SERVERS, [])
for server in servers()
]
config.configuration.ice_servers.extend(ice_servers) config.configuration.ice_servers.extend(ice_servers)
return config return config

View File

@ -3,7 +3,7 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from collections.abc import Awaitable, Callable, Coroutine from collections.abc import Awaitable, Callable, Iterable
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any, Protocol from typing import TYPE_CHECKING, Any, Protocol
@ -24,8 +24,8 @@ if TYPE_CHECKING:
DATA_WEBRTC_PROVIDERS: HassKey[set[CameraWebRTCProvider]] = HassKey( DATA_WEBRTC_PROVIDERS: HassKey[set[CameraWebRTCProvider]] = HassKey(
"camera_web_rtc_providers" "camera_web_rtc_providers"
) )
DATA_ICE_SERVERS: HassKey[list[Callable[[], Coroutine[Any, Any, RTCIceServer]]]] = ( DATA_ICE_SERVERS: HassKey[list[Callable[[], Iterable[RTCIceServer]]]] = HassKey(
HassKey("camera_web_rtc_ice_servers") "camera_web_rtc_ice_servers"
) )
@ -188,9 +188,9 @@ async def async_get_supported_providers(
@callback @callback
def register_ice_server( def async_register_ice_servers(
hass: HomeAssistant, hass: HomeAssistant,
get_ice_server_fn: Callable[[], Coroutine[Any, Any, RTCIceServer]], get_ice_server_fn: Callable[[], Iterable[RTCIceServer]],
) -> Callable[[], None]: ) -> Callable[[], None]:
"""Register a ICE server. """Register a ICE server.

View File

@ -26,9 +26,12 @@ from rtsp_to_webrtc.exceptions import ClientError, ResponseError
from rtsp_to_webrtc.interface import WebRTCClientInterface from rtsp_to_webrtc.interface import WebRTCClientInterface
from homeassistant.components import camera from homeassistant.components import camera
from homeassistant.components.camera.webrtc import RTCIceServer, register_ice_server from homeassistant.components.camera.webrtc import (
RTCIceServer,
async_register_ice_servers,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
@ -59,10 +62,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN][CONF_STUN_SERVER] = entry.options.get(CONF_STUN_SERVER) hass.data[DOMAIN][CONF_STUN_SERVER] = entry.options.get(CONF_STUN_SERVER)
if server := entry.options.get(CONF_STUN_SERVER): if server := entry.options.get(CONF_STUN_SERVER):
async def get_server() -> RTCIceServer: @callback
return RTCIceServer(urls=[server]) def get_servers() -> list[RTCIceServer]:
return [RTCIceServer(urls=[server])]
entry.async_on_unload(register_ice_server(hass, get_server)) entry.async_on_unload(async_register_ice_servers(hass, get_servers))
async def async_offer_for_stream_source( async def async_offer_for_stream_source(
stream_source: str, stream_source: str,

View File

@ -9,11 +9,11 @@ from homeassistant.components.camera.webrtc import (
DATA_ICE_SERVERS, DATA_ICE_SERVERS,
CameraWebRTCProvider, CameraWebRTCProvider,
RTCIceServer, RTCIceServer,
async_register_ice_servers,
async_register_webrtc_provider, async_register_webrtc_provider,
register_ice_server,
) )
from homeassistant.components.websocket_api import TYPE_RESULT from homeassistant.components.websocket_api import TYPE_RESULT
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from tests.typing import WebSocketGenerator from tests.typing import WebSocketGenerator
@ -131,37 +131,48 @@ async def test_async_register_ice_server(
called = 0 called = 0
async def get_ice_server() -> RTCIceServer: @callback
def get_ice_servers() -> list[RTCIceServer]:
nonlocal called nonlocal called
called += 1 called += 1
return RTCIceServer(urls="stun:example.com") return [
RTCIceServer(urls="stun:example.com"),
RTCIceServer(urls="turn:example.com"),
]
unregister = register_ice_server(hass, get_ice_server) unregister = async_register_ice_servers(hass, get_ice_servers)
assert not called assert not called
camera = get_camera_from_entity_id(hass, "camera.demo_camera") camera = get_camera_from_entity_id(hass, "camera.demo_camera")
config = await camera.async_get_webrtc_client_configuration() config = await camera.async_get_webrtc_client_configuration()
assert config.configuration.ice_servers == [RTCIceServer(urls="stun:example.com")] assert config.configuration.ice_servers == [
RTCIceServer(urls="stun:example.com"),
RTCIceServer(urls="turn:example.com"),
]
assert called == 1 assert called == 1
# register another ICE server # register another ICE server
called_2 = 0 called_2 = 0
async def get_ice_server_2() -> RTCIceServer: @callback
def get_ice_servers_2() -> RTCIceServer:
nonlocal called_2 nonlocal called_2
called_2 += 1 called_2 += 1
return RTCIceServer( return [
urls=["stun:example2.com", "turn:example2.com"], RTCIceServer(
username="user", urls=["stun:example2.com", "turn:example2.com"],
credential="pass", username="user",
) credential="pass",
)
]
unregister_2 = register_ice_server(hass, get_ice_server_2) unregister_2 = async_register_ice_servers(hass, get_ice_servers_2)
config = await camera.async_get_webrtc_client_configuration() config = await camera.async_get_webrtc_client_configuration()
assert config.configuration.ice_servers == [ assert config.configuration.ice_servers == [
RTCIceServer(urls="stun:example.com"), RTCIceServer(urls="stun:example.com"),
RTCIceServer(urls="turn:example.com"),
RTCIceServer( RTCIceServer(
urls=["stun:example2.com", "turn:example2.com"], urls=["stun:example2.com", "turn:example2.com"],
username="user", username="user",