diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 0fab313c955..7ae12b36dcd 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -89,8 +89,8 @@ from .webrtc import ( RTCIceServer, WebRTCClientConfiguration, async_get_supported_providers, + async_register_ice_servers, async_register_rtsp_to_web_rtc_provider, # noqa: F401 - register_ice_server, 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 ) - async def get_ice_server() -> RTCIceServer: - return RTCIceServer(urls="stun:stun.home-assistant.io:80") + @callback + 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 @@ -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.""" config = await self._async_get_webrtc_client_configuration() - ice_servers = await asyncio.gather( - *[server() for server in self.hass.data.get(DATA_ICE_SERVERS, [])] - ) + ice_servers = [ + server + for servers in self.hass.data.get(DATA_ICE_SERVERS, []) + for server in servers() + ] config.configuration.ice_servers.extend(ice_servers) return config diff --git a/homeassistant/components/camera/webrtc.py b/homeassistant/components/camera/webrtc.py index fb9f05b58da..963fb705941 100644 --- a/homeassistant/components/camera/webrtc.py +++ b/homeassistant/components/camera/webrtc.py @@ -3,7 +3,7 @@ from __future__ import annotations import asyncio -from collections.abc import Awaitable, Callable, Coroutine +from collections.abc import Awaitable, Callable, Iterable from dataclasses import dataclass, field from typing import TYPE_CHECKING, Any, Protocol @@ -24,8 +24,8 @@ if TYPE_CHECKING: DATA_WEBRTC_PROVIDERS: HassKey[set[CameraWebRTCProvider]] = HassKey( "camera_web_rtc_providers" ) -DATA_ICE_SERVERS: HassKey[list[Callable[[], Coroutine[Any, Any, RTCIceServer]]]] = ( - HassKey("camera_web_rtc_ice_servers") +DATA_ICE_SERVERS: HassKey[list[Callable[[], Iterable[RTCIceServer]]]] = HassKey( + "camera_web_rtc_ice_servers" ) @@ -188,9 +188,9 @@ async def async_get_supported_providers( @callback -def register_ice_server( +def async_register_ice_servers( hass: HomeAssistant, - get_ice_server_fn: Callable[[], Coroutine[Any, Any, RTCIceServer]], + get_ice_server_fn: Callable[[], Iterable[RTCIceServer]], ) -> Callable[[], None]: """Register a ICE server. diff --git a/homeassistant/components/rtsp_to_webrtc/__init__.py b/homeassistant/components/rtsp_to_webrtc/__init__.py index 948ba8929fc..ee55171e9e9 100644 --- a/homeassistant/components/rtsp_to_webrtc/__init__.py +++ b/homeassistant/components/rtsp_to_webrtc/__init__.py @@ -26,9 +26,12 @@ from rtsp_to_webrtc.exceptions import ClientError, ResponseError from rtsp_to_webrtc.interface import WebRTCClientInterface 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.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError 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) if server := entry.options.get(CONF_STUN_SERVER): - async def get_server() -> RTCIceServer: - return RTCIceServer(urls=[server]) + @callback + 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( stream_source: str, diff --git a/tests/components/camera/test_webrtc.py b/tests/components/camera/test_webrtc.py index f92d7fbdacb..de7eee8c183 100644 --- a/tests/components/camera/test_webrtc.py +++ b/tests/components/camera/test_webrtc.py @@ -9,11 +9,11 @@ from homeassistant.components.camera.webrtc import ( DATA_ICE_SERVERS, CameraWebRTCProvider, RTCIceServer, + async_register_ice_servers, async_register_webrtc_provider, - register_ice_server, ) 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 tests.typing import WebSocketGenerator @@ -131,37 +131,48 @@ async def test_async_register_ice_server( called = 0 - async def get_ice_server() -> RTCIceServer: + @callback + def get_ice_servers() -> list[RTCIceServer]: nonlocal called 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 camera = get_camera_from_entity_id(hass, "camera.demo_camera") 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 # register another ICE server called_2 = 0 - async def get_ice_server_2() -> RTCIceServer: + @callback + def get_ice_servers_2() -> RTCIceServer: nonlocal called_2 called_2 += 1 - return RTCIceServer( - urls=["stun:example2.com", "turn:example2.com"], - username="user", - credential="pass", - ) + return [ + RTCIceServer( + urls=["stun:example2.com", "turn:example2.com"], + 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() assert config.configuration.ice_servers == [ RTCIceServer(urls="stun:example.com"), + RTCIceServer(urls="turn:example.com"), RTCIceServer( urls=["stun:example2.com", "turn:example2.com"], username="user",