From 999f3e0d7753a0ba29d29652cc3ad8798a7b8533 Mon Sep 17 00:00:00 2001 From: Robert Resch Date: Tue, 19 Nov 2024 03:41:50 +0100 Subject: [PATCH] Use RTCIceCandidateInit instead of RTCIceCandidate (#130901) --- homeassistant/components/camera/__init__.py | 4 +- homeassistant/components/camera/webrtc.py | 13 +++-- homeassistant/components/go2rtc/__init__.py | 6 +-- homeassistant/components/nest/camera.py | 4 +- tests/components/camera/common.py | 4 +- tests/components/camera/conftest.py | 4 +- tests/components/camera/test_init.py | 4 +- tests/components/camera/test_webrtc.py | 50 +++++++++++++++++--- tests/components/go2rtc/test_init.py | 8 ++-- tests/components/unifiprotect/test_camera.py | 4 +- 10 files changed, 72 insertions(+), 29 deletions(-) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index b6bf794a05f..64a4480d9d3 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -20,7 +20,7 @@ from aiohttp import hdrs, web import attr from propcache import cached_property, under_cached_property import voluptuous as vol -from webrtc_models import RTCIceCandidate, RTCIceServer +from webrtc_models import RTCIceCandidateInit, RTCIceServer from homeassistant.components import websocket_api from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView @@ -865,7 +865,7 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_): return config async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle a WebRTC candidate.""" if self._webrtc_provider: diff --git a/homeassistant/components/camera/webrtc.py b/homeassistant/components/camera/webrtc.py index f43e86fad38..f020df61092 100644 --- a/homeassistant/components/camera/webrtc.py +++ b/homeassistant/components/camera/webrtc.py @@ -11,7 +11,12 @@ import logging from typing import TYPE_CHECKING, Any, Protocol import voluptuous as vol -from webrtc_models import RTCConfiguration, RTCIceCandidate, RTCIceServer +from webrtc_models import ( + RTCConfiguration, + RTCIceCandidate, + RTCIceCandidateInit, + RTCIceServer, +) from homeassistant.components import websocket_api from homeassistant.core import HomeAssistant, callback @@ -78,7 +83,7 @@ class WebRTCAnswer(WebRTCMessage): class WebRTCCandidate(WebRTCMessage): """WebRTC candidate.""" - candidate: RTCIceCandidate + candidate: RTCIceCandidate | RTCIceCandidateInit def as_dict(self) -> dict[str, Any]: """Return a dict representation of the message.""" @@ -146,7 +151,7 @@ class CameraWebRTCProvider(ABC): @abstractmethod async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle the WebRTC candidate.""" @@ -338,7 +343,7 @@ async def ws_candidate( ) -> None: """Handle WebRTC candidate websocket command.""" await camera.async_on_webrtc_candidate( - msg["session_id"], RTCIceCandidate(msg["candidate"]) + msg["session_id"], RTCIceCandidateInit(msg["candidate"]) ) connection.send_message(websocket_api.result_message(msg["id"])) diff --git a/homeassistant/components/go2rtc/__init__.py b/homeassistant/components/go2rtc/__init__.py index f1f6e44abc1..31acdd2de50 100644 --- a/homeassistant/components/go2rtc/__init__.py +++ b/homeassistant/components/go2rtc/__init__.py @@ -16,7 +16,7 @@ from go2rtc_client.ws import ( WsError, ) import voluptuous as vol -from webrtc_models import RTCIceCandidate +from webrtc_models import RTCIceCandidateInit from homeassistant.components.camera import ( Camera, @@ -264,7 +264,7 @@ class WebRTCProvider(CameraWebRTCProvider): value: WebRTCMessage match message: case WebRTCCandidate(): - value = HAWebRTCCandidate(RTCIceCandidate(message.candidate)) + value = HAWebRTCCandidate(RTCIceCandidateInit(message.candidate)) case WebRTCAnswer(): value = HAWebRTCAnswer(message.sdp) case WsError(): @@ -277,7 +277,7 @@ class WebRTCProvider(CameraWebRTCProvider): await ws_client.send(WebRTCOffer(offer_sdp, config.configuration.ice_servers)) async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle the WebRTC candidate.""" diff --git a/homeassistant/components/nest/camera.py b/homeassistant/components/nest/camera.py index 0a46d67a3ad..281e6b0bb28 100644 --- a/homeassistant/components/nest/camera.py +++ b/homeassistant/components/nest/camera.py @@ -19,7 +19,7 @@ from google_nest_sdm.camera_traits import ( from google_nest_sdm.device import Device from google_nest_sdm.device_manager import DeviceManager from google_nest_sdm.exceptions import ApiException -from webrtc_models import RTCIceCandidate +from webrtc_models import RTCIceCandidateInit from homeassistant.components.camera import ( Camera, @@ -304,7 +304,7 @@ class NestWebRTCEntity(NestCameraBaseEntity): self._refresh_unsub[session_id] = refresh.unsub async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Ignore WebRTC candidates for Nest cloud based cameras.""" return diff --git a/tests/components/camera/common.py b/tests/components/camera/common.py index 569756c2640..19ac2cc168b 100644 --- a/tests/components/camera/common.py +++ b/tests/components/camera/common.py @@ -6,7 +6,7 @@ components. Instead call the service directly. from unittest.mock import Mock -from webrtc_models import RTCIceCandidate +from webrtc_models import RTCIceCandidateInit from homeassistant.components.camera import ( Camera, @@ -66,7 +66,7 @@ class SomeTestProvider(CameraWebRTCProvider): send_message(WebRTCAnswer(answer="answer")) async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle the WebRTC candidate.""" diff --git a/tests/components/camera/conftest.py b/tests/components/camera/conftest.py index f0c418711c7..cb25b366029 100644 --- a/tests/components/camera/conftest.py +++ b/tests/components/camera/conftest.py @@ -4,7 +4,7 @@ from collections.abc import AsyncGenerator, Generator from unittest.mock import AsyncMock, Mock, PropertyMock, patch import pytest -from webrtc_models import RTCIceCandidate +from webrtc_models import RTCIceCandidateInit from homeassistant.components import camera from homeassistant.components.camera.const import StreamType @@ -192,7 +192,7 @@ async def mock_test_webrtc_cameras(hass: HomeAssistant) -> None: send_message(WebRTCAnswer(WEBRTC_ANSWER)) async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle a WebRTC candidate.""" # Do nothing diff --git a/tests/components/camera/test_init.py b/tests/components/camera/test_init.py index 32024694b7e..af8c220bbe4 100644 --- a/tests/components/camera/test_init.py +++ b/tests/components/camera/test_init.py @@ -7,7 +7,7 @@ from unittest.mock import ANY, AsyncMock, Mock, PropertyMock, mock_open, patch import pytest from syrupy.assertion import SnapshotAssertion -from webrtc_models import RTCIceCandidate +from webrtc_models import RTCIceCandidateInit from homeassistant.components import camera from homeassistant.components.camera import ( @@ -954,7 +954,7 @@ async def _test_capabilities( send_message(WebRTCAnswer("answer")) async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle the WebRTC candidate.""" diff --git a/tests/components/camera/test_webrtc.py b/tests/components/camera/test_webrtc.py index be9f3aae6d7..89bd74be301 100644 --- a/tests/components/camera/test_webrtc.py +++ b/tests/components/camera/test_webrtc.py @@ -6,7 +6,7 @@ from typing import Any from unittest.mock import AsyncMock, Mock, patch import pytest -from webrtc_models import RTCIceCandidate, RTCIceServer +from webrtc_models import RTCIceCandidate, RTCIceCandidateInit, RTCIceServer from homeassistant.components.camera import ( DATA_ICE_SERVERS, @@ -481,11 +481,30 @@ async def test_websocket_webrtc_offer( assert msg["success"] +@pytest.mark.filterwarnings( + "ignore:Using RTCIceCandidate is deprecated. Use RTCIceCandidateInit instead" +) +@pytest.mark.usefixtures("mock_stream_source", "mock_camera") +async def test_websocket_webrtc_offer_webrtc_provider_deprecated( + hass: HomeAssistant, + hass_ws_client: WebSocketGenerator, + register_test_provider: SomeTestProvider, +) -> None: + """Test initiating a WebRTC stream with a webrtc provider with the deprecated class.""" + await _test_websocket_webrtc_offer_webrtc_provider( + hass, + hass_ws_client, + register_test_provider, + WebRTCCandidate(RTCIceCandidate("candidate")), + {"type": "candidate", "candidate": "candidate"}, + ) + + @pytest.mark.parametrize( ("message", "expected_frontend_message"), [ ( - WebRTCCandidate(RTCIceCandidate("candidate")), + WebRTCCandidate(RTCIceCandidateInit("candidate")), {"type": "candidate", "candidate": "candidate"}, ), ( @@ -503,6 +522,23 @@ async def test_websocket_webrtc_offer_webrtc_provider( register_test_provider: SomeTestProvider, message: WebRTCMessage, expected_frontend_message: dict[str, Any], +) -> None: + """Test initiating a WebRTC stream with a webrtc provider.""" + await _test_websocket_webrtc_offer_webrtc_provider( + hass, + hass_ws_client, + register_test_provider, + message, + expected_frontend_message, + ) + + +async def _test_websocket_webrtc_offer_webrtc_provider( + hass: HomeAssistant, + hass_ws_client: WebSocketGenerator, + register_test_provider: SomeTestProvider, + message: WebRTCMessage, + expected_frontend_message: dict[str, Any], ) -> None: """Test initiating a WebRTC stream with a webrtc provider.""" client = await hass_ws_client(hass) @@ -934,7 +970,7 @@ async def test_ws_webrtc_candidate( assert response["type"] == TYPE_RESULT assert response["success"] mock_on_webrtc_candidate.assert_called_once_with( - session_id, RTCIceCandidate(candidate) + session_id, RTCIceCandidateInit(candidate) ) @@ -986,7 +1022,7 @@ async def test_ws_webrtc_candidate_webrtc_provider( assert response["type"] == TYPE_RESULT assert response["success"] mock_on_webrtc_candidate.assert_called_once_with( - session_id, RTCIceCandidate(candidate) + session_id, RTCIceCandidateInit(candidate) ) @@ -1088,7 +1124,7 @@ async def test_webrtc_provider_optional_interface(hass: HomeAssistant) -> None: send_message(WebRTCAnswer(answer="answer")) async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle the WebRTC candidate.""" @@ -1098,7 +1134,9 @@ async def test_webrtc_provider_optional_interface(hass: HomeAssistant) -> None: await provider.async_handle_async_webrtc_offer( Mock(), "offer_sdp", "session_id", Mock() ) - await provider.async_on_webrtc_candidate("session_id", RTCIceCandidate("candidate")) + await provider.async_on_webrtc_candidate( + "session_id", RTCIceCandidateInit("candidate") + ) provider.async_close_session("session_id") diff --git a/tests/components/go2rtc/test_init.py b/tests/components/go2rtc/test_init.py index dba3b4d3a54..38ff82fc9c8 100644 --- a/tests/components/go2rtc/test_init.py +++ b/tests/components/go2rtc/test_init.py @@ -18,7 +18,7 @@ from go2rtc_client.ws import ( WsError, ) import pytest -from webrtc_models import RTCIceCandidate +from webrtc_models import RTCIceCandidateInit from homeassistant.components.camera import ( DOMAIN as CAMERA_DOMAIN, @@ -423,7 +423,7 @@ async def message_callbacks( [ ( WebRTCCandidate("candidate"), - HAWebRTCCandidate(RTCIceCandidate("candidate")), + HAWebRTCCandidate(RTCIceCandidateInit("candidate")), ), ( WebRTCAnswer(ANSWER_SDP), @@ -459,7 +459,7 @@ async def test_on_candidate( session_id = "session_id" # Session doesn't exist - await camera.async_on_webrtc_candidate(session_id, RTCIceCandidate("candidate")) + await camera.async_on_webrtc_candidate(session_id, RTCIceCandidateInit("candidate")) assert ( "homeassistant.components.go2rtc", logging.DEBUG, @@ -479,7 +479,7 @@ async def test_on_candidate( ) ws_client.reset_mock() - await camera.async_on_webrtc_candidate(session_id, RTCIceCandidate("candidate")) + await camera.async_on_webrtc_candidate(session_id, RTCIceCandidateInit("candidate")) ws_client.send.assert_called_once_with(WebRTCCandidate("candidate")) assert caplog.record_tuples == [] diff --git a/tests/components/unifiprotect/test_camera.py b/tests/components/unifiprotect/test_camera.py index 379f443923a..689352d8aa3 100644 --- a/tests/components/unifiprotect/test_camera.py +++ b/tests/components/unifiprotect/test_camera.py @@ -9,12 +9,12 @@ from uiprotect.api import DEVICE_UPDATE_INTERVAL from uiprotect.data import Camera as ProtectCamera, CameraChannel, StateType from uiprotect.exceptions import NvrError from uiprotect.websocket import WebsocketState +from webrtc_models import RTCIceCandidateInit from homeassistant.components.camera import ( CameraEntityFeature, CameraState, CameraWebRTCProvider, - RTCIceCandidate, StreamType, WebRTCSendMessage, async_get_image, @@ -77,7 +77,7 @@ class MockWebRTCProvider(CameraWebRTCProvider): """Handle the WebRTC offer and return the answer via the provided callback.""" async def async_on_webrtc_candidate( - self, session_id: str, candidate: RTCIceCandidate + self, session_id: str, candidate: RTCIceCandidateInit ) -> None: """Handle the WebRTC candidate."""