mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Use RTCIceCandidate instead of str for candidate (#129793)
This commit is contained in:
parent
0c40fcdaeb
commit
d75dda0c05
@ -20,7 +20,7 @@ from aiohttp import hdrs, web
|
|||||||
import attr
|
import attr
|
||||||
from propcache import cached_property, under_cached_property
|
from propcache import cached_property, under_cached_property
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from webrtc_models import RTCIceServer
|
from webrtc_models import RTCIceCandidate, RTCIceServer
|
||||||
|
|
||||||
from homeassistant.components import websocket_api
|
from homeassistant.components import websocket_api
|
||||||
from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView
|
from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView
|
||||||
@ -840,7 +840,9 @@ class Camera(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
async def async_on_webrtc_candidate(self, session_id: str, candidate: str) -> None:
|
async def async_on_webrtc_candidate(
|
||||||
|
self, session_id: str, candidate: RTCIceCandidate
|
||||||
|
) -> None:
|
||||||
"""Handle a WebRTC candidate."""
|
"""Handle a WebRTC candidate."""
|
||||||
if self._webrtc_provider:
|
if self._webrtc_provider:
|
||||||
await self._webrtc_provider.async_on_webrtc_candidate(session_id, candidate)
|
await self._webrtc_provider.async_on_webrtc_candidate(session_id, candidate)
|
||||||
|
@ -11,7 +11,7 @@ import logging
|
|||||||
from typing import TYPE_CHECKING, Any, Protocol
|
from typing import TYPE_CHECKING, Any, Protocol
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from webrtc_models import RTCConfiguration, RTCIceServer
|
from webrtc_models import RTCConfiguration, RTCIceCandidate, RTCIceServer
|
||||||
|
|
||||||
from homeassistant.components import websocket_api
|
from homeassistant.components import websocket_api
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
@ -78,7 +78,14 @@ class WebRTCAnswer(WebRTCMessage):
|
|||||||
class WebRTCCandidate(WebRTCMessage):
|
class WebRTCCandidate(WebRTCMessage):
|
||||||
"""WebRTC candidate."""
|
"""WebRTC candidate."""
|
||||||
|
|
||||||
candidate: str
|
candidate: RTCIceCandidate
|
||||||
|
|
||||||
|
def as_dict(self) -> dict[str, Any]:
|
||||||
|
"""Return a dict representation of the message."""
|
||||||
|
return {
|
||||||
|
"type": self._get_type(),
|
||||||
|
"candidate": self.candidate.candidate,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -138,7 +145,9 @@ class CameraWebRTCProvider(ABC):
|
|||||||
"""Handle the WebRTC offer and return the answer via the provided callback."""
|
"""Handle the WebRTC offer and return the answer via the provided callback."""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def async_on_webrtc_candidate(self, session_id: str, candidate: str) -> None:
|
async def async_on_webrtc_candidate(
|
||||||
|
self, session_id: str, candidate: RTCIceCandidate
|
||||||
|
) -> None:
|
||||||
"""Handle the WebRTC candidate."""
|
"""Handle the WebRTC candidate."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -319,7 +328,9 @@ async def ws_candidate(
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
await camera.async_on_webrtc_candidate(msg["session_id"], msg["candidate"])
|
await camera.async_on_webrtc_candidate(
|
||||||
|
msg["session_id"], RTCIceCandidate(msg["candidate"])
|
||||||
|
)
|
||||||
connection.send_message(websocket_api.result_message(msg["id"]))
|
connection.send_message(websocket_api.result_message(msg["id"]))
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ from go2rtc_client.ws import (
|
|||||||
WsError,
|
WsError,
|
||||||
)
|
)
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
from webrtc_models import RTCIceCandidate
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
Camera,
|
Camera,
|
||||||
@ -219,7 +220,7 @@ class WebRTCProvider(CameraWebRTCProvider):
|
|||||||
value: WebRTCMessage
|
value: WebRTCMessage
|
||||||
match message:
|
match message:
|
||||||
case WebRTCCandidate():
|
case WebRTCCandidate():
|
||||||
value = HAWebRTCCandidate(message.candidate)
|
value = HAWebRTCCandidate(RTCIceCandidate(message.candidate))
|
||||||
case WebRTCAnswer():
|
case WebRTCAnswer():
|
||||||
value = HAWebRTCAnswer(message.sdp)
|
value = HAWebRTCAnswer(message.sdp)
|
||||||
case WsError():
|
case WsError():
|
||||||
@ -231,11 +232,13 @@ class WebRTCProvider(CameraWebRTCProvider):
|
|||||||
config = camera.async_get_webrtc_client_configuration()
|
config = camera.async_get_webrtc_client_configuration()
|
||||||
await ws_client.send(WebRTCOffer(offer_sdp, config.configuration.ice_servers))
|
await ws_client.send(WebRTCOffer(offer_sdp, config.configuration.ice_servers))
|
||||||
|
|
||||||
async def async_on_webrtc_candidate(self, session_id: str, candidate: str) -> None:
|
async def async_on_webrtc_candidate(
|
||||||
|
self, session_id: str, candidate: RTCIceCandidate
|
||||||
|
) -> None:
|
||||||
"""Handle the WebRTC candidate."""
|
"""Handle the WebRTC candidate."""
|
||||||
|
|
||||||
if ws_client := self._sessions.get(session_id):
|
if ws_client := self._sessions.get(session_id):
|
||||||
await ws_client.send(WebRTCCandidate(candidate))
|
await ws_client.send(WebRTCCandidate(candidate.candidate))
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug("Unknown session %s. Ignoring candidate", session_id)
|
_LOGGER.debug("Unknown session %s. Ignoring candidate", session_id)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from unittest.mock import ANY, AsyncMock, Mock, PropertyMock, mock_open, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
from webrtc_models import RTCIceCandidate
|
||||||
|
|
||||||
from homeassistant.components import camera
|
from homeassistant.components import camera
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
@ -960,7 +961,7 @@ async def _test_capabilities(
|
|||||||
send_message(WebRTCAnswer("answer"))
|
send_message(WebRTCAnswer("answer"))
|
||||||
|
|
||||||
async def async_on_webrtc_candidate(
|
async def async_on_webrtc_candidate(
|
||||||
self, session_id: str, candidate: str
|
self, session_id: str, candidate: RTCIceCandidate
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle the WebRTC candidate."""
|
"""Handle the WebRTC candidate."""
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ from typing import Any
|
|||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from webrtc_models import RTCIceCandidate, RTCIceServer
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
DATA_ICE_SERVERS,
|
DATA_ICE_SERVERS,
|
||||||
@ -13,7 +14,6 @@ from homeassistant.components.camera import (
|
|||||||
Camera,
|
Camera,
|
||||||
CameraEntityFeature,
|
CameraEntityFeature,
|
||||||
CameraWebRTCProvider,
|
CameraWebRTCProvider,
|
||||||
RTCIceServer,
|
|
||||||
StreamType,
|
StreamType,
|
||||||
WebRTCAnswer,
|
WebRTCAnswer,
|
||||||
WebRTCCandidate,
|
WebRTCCandidate,
|
||||||
@ -81,7 +81,9 @@ class SomeTestProvider(CameraWebRTCProvider):
|
|||||||
"""
|
"""
|
||||||
send_message(WebRTCAnswer(answer="answer"))
|
send_message(WebRTCAnswer(answer="answer"))
|
||||||
|
|
||||||
async def async_on_webrtc_candidate(self, session_id: str, candidate: str) -> None:
|
async def async_on_webrtc_candidate(
|
||||||
|
self, session_id: str, candidate: RTCIceCandidate
|
||||||
|
) -> None:
|
||||||
"""Handle the WebRTC candidate."""
|
"""Handle the WebRTC candidate."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -503,7 +505,10 @@ async def test_websocket_webrtc_offer(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("message", "expected_frontend_message"),
|
("message", "expected_frontend_message"),
|
||||||
[
|
[
|
||||||
(WebRTCCandidate("candidate"), {"type": "candidate", "candidate": "candidate"}),
|
(
|
||||||
|
WebRTCCandidate(RTCIceCandidate("candidate")),
|
||||||
|
{"type": "candidate", "candidate": "candidate"},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
WebRTCError("webrtc_offer_failed", "error"),
|
WebRTCError("webrtc_offer_failed", "error"),
|
||||||
{"type": "error", "code": "webrtc_offer_failed", "message": "error"},
|
{"type": "error", "code": "webrtc_offer_failed", "message": "error"},
|
||||||
@ -989,7 +994,9 @@ async def test_ws_webrtc_candidate(
|
|||||||
response = await client.receive_json()
|
response = await client.receive_json()
|
||||||
assert response["type"] == TYPE_RESULT
|
assert response["type"] == TYPE_RESULT
|
||||||
assert response["success"]
|
assert response["success"]
|
||||||
mock_on_webrtc_candidate.assert_called_once_with(session_id, candidate)
|
mock_on_webrtc_candidate.assert_called_once_with(
|
||||||
|
session_id, RTCIceCandidate(candidate)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("mock_camera_webrtc")
|
@pytest.mark.usefixtures("mock_camera_webrtc")
|
||||||
@ -1039,7 +1046,9 @@ async def test_ws_webrtc_candidate_webrtc_provider(
|
|||||||
response = await client.receive_json()
|
response = await client.receive_json()
|
||||||
assert response["type"] == TYPE_RESULT
|
assert response["type"] == TYPE_RESULT
|
||||||
assert response["success"]
|
assert response["success"]
|
||||||
mock_on_webrtc_candidate.assert_called_once_with(session_id, candidate)
|
mock_on_webrtc_candidate.assert_called_once_with(
|
||||||
|
session_id, RTCIceCandidate(candidate)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("mock_camera_webrtc")
|
@pytest.mark.usefixtures("mock_camera_webrtc")
|
||||||
@ -1140,7 +1149,7 @@ async def test_webrtc_provider_optional_interface(hass: HomeAssistant) -> None:
|
|||||||
send_message(WebRTCAnswer(answer="answer"))
|
send_message(WebRTCAnswer(answer="answer"))
|
||||||
|
|
||||||
async def async_on_webrtc_candidate(
|
async def async_on_webrtc_candidate(
|
||||||
self, session_id: str, candidate: str
|
self, session_id: str, candidate: RTCIceCandidate
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle the WebRTC candidate."""
|
"""Handle the WebRTC candidate."""
|
||||||
|
|
||||||
@ -1150,7 +1159,7 @@ async def test_webrtc_provider_optional_interface(hass: HomeAssistant) -> None:
|
|||||||
await provider.async_handle_async_webrtc_offer(
|
await provider.async_handle_async_webrtc_offer(
|
||||||
Mock(), "offer_sdp", "session_id", Mock()
|
Mock(), "offer_sdp", "session_id", Mock()
|
||||||
)
|
)
|
||||||
await provider.async_on_webrtc_candidate("session_id", "candidate")
|
await provider.async_on_webrtc_candidate("session_id", RTCIceCandidate("candidate"))
|
||||||
provider.async_close_session("session_id")
|
provider.async_close_session("session_id")
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ from go2rtc_client.ws import (
|
|||||||
WsError,
|
WsError,
|
||||||
)
|
)
|
||||||
import pytest
|
import pytest
|
||||||
|
from webrtc_models import RTCIceCandidate
|
||||||
|
|
||||||
from homeassistant.components.camera import (
|
from homeassistant.components.camera import (
|
||||||
DOMAIN as CAMERA_DOMAIN,
|
DOMAIN as CAMERA_DOMAIN,
|
||||||
@ -379,7 +380,7 @@ async def message_callbacks(
|
|||||||
[
|
[
|
||||||
(
|
(
|
||||||
WebRTCCandidate("candidate"),
|
WebRTCCandidate("candidate"),
|
||||||
HAWebRTCCandidate("candidate"),
|
HAWebRTCCandidate(RTCIceCandidate("candidate")),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
WebRTCAnswer(ANSWER_SDP),
|
WebRTCAnswer(ANSWER_SDP),
|
||||||
@ -415,7 +416,7 @@ async def test_on_candidate(
|
|||||||
session_id = "session_id"
|
session_id = "session_id"
|
||||||
|
|
||||||
# Session doesn't exist
|
# Session doesn't exist
|
||||||
await camera.async_on_webrtc_candidate(session_id, "candidate")
|
await camera.async_on_webrtc_candidate(session_id, RTCIceCandidate("candidate"))
|
||||||
assert (
|
assert (
|
||||||
"homeassistant.components.go2rtc",
|
"homeassistant.components.go2rtc",
|
||||||
logging.DEBUG,
|
logging.DEBUG,
|
||||||
@ -435,7 +436,7 @@ async def test_on_candidate(
|
|||||||
)
|
)
|
||||||
ws_client.reset_mock()
|
ws_client.reset_mock()
|
||||||
|
|
||||||
await camera.async_on_webrtc_candidate(session_id, "candidate")
|
await camera.async_on_webrtc_candidate(session_id, RTCIceCandidate("candidate"))
|
||||||
ws_client.send.assert_called_once_with(WebRTCCandidate("candidate"))
|
ws_client.send.assert_called_once_with(WebRTCCandidate("candidate"))
|
||||||
assert caplog.record_tuples == []
|
assert caplog.record_tuples == []
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user