mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Remove all ice_servers on native sync WebRTC cameras (#129819)
This commit is contained in:
parent
f6e36615d6
commit
df796d432e
@ -827,16 +827,17 @@ 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 = self._async_get_webrtc_client_configuration()
|
config = self._async_get_webrtc_client_configuration()
|
||||||
|
|
||||||
ice_servers = [
|
if not self._webrtc_sync_offer:
|
||||||
server
|
# Until 2024.11, the frontend was not resolving any ice servers
|
||||||
for servers in self.hass.data.get(DATA_ICE_SERVERS, [])
|
# The async approach was added 2024.11 and new integrations need to use it
|
||||||
for server in servers()
|
ice_servers = [
|
||||||
]
|
server
|
||||||
config.configuration.ice_servers.extend(ice_servers)
|
for servers in self.hass.data.get(DATA_ICE_SERVERS, [])
|
||||||
|
for server in servers()
|
||||||
|
]
|
||||||
|
config.configuration.ice_servers.extend(ice_servers)
|
||||||
|
|
||||||
config.get_candidates_upfront = (
|
config.get_candidates_upfront = self._legacy_webrtc_provider is not None
|
||||||
self._webrtc_sync_offer or self._legacy_webrtc_provider is not None
|
|
||||||
)
|
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
"""Test helpers for camera."""
|
"""Test helpers for camera."""
|
||||||
|
|
||||||
from collections.abc import AsyncGenerator, Generator
|
from collections.abc import AsyncGenerator, Generator
|
||||||
from unittest.mock import AsyncMock, PropertyMock, patch
|
from unittest.mock import AsyncMock, Mock, PropertyMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import camera
|
from homeassistant.components import camera
|
||||||
from homeassistant.components.camera.const import StreamType
|
from homeassistant.components.camera.const import StreamType
|
||||||
from homeassistant.components.camera.webrtc import WebRTCAnswer, WebRTCSendMessage
|
from homeassistant.components.camera.webrtc import WebRTCAnswer, WebRTCSendMessage
|
||||||
|
from homeassistant.config_entries import ConfigEntry, ConfigFlow
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
@ -15,6 +16,15 @@ from homeassistant.setup import async_setup_component
|
|||||||
|
|
||||||
from .common import STREAM_SOURCE, WEBRTC_ANSWER
|
from .common import STREAM_SOURCE, WEBRTC_ANSWER
|
||||||
|
|
||||||
|
from tests.common import (
|
||||||
|
MockConfigEntry,
|
||||||
|
MockModule,
|
||||||
|
mock_config_flow,
|
||||||
|
mock_integration,
|
||||||
|
mock_platform,
|
||||||
|
setup_test_component_platform,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
async def setup_homeassistant(hass: HomeAssistant) -> None:
|
async def setup_homeassistant(hass: HomeAssistant) -> None:
|
||||||
@ -142,3 +152,66 @@ def mock_stream_source_fixture() -> Generator[AsyncMock]:
|
|||||||
return_value=STREAM_SOURCE,
|
return_value=STREAM_SOURCE,
|
||||||
) as mock_stream_source:
|
) as mock_stream_source:
|
||||||
yield mock_stream_source
|
yield mock_stream_source
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def mock_camera_webrtc_native_sync_offer(hass: HomeAssistant) -> None:
|
||||||
|
"""Initialize a test camera with native sync WebRTC support."""
|
||||||
|
|
||||||
|
# Cannot use the fixture mock_camera_web_rtc as it's mocking Camera.async_handle_web_rtc_offer
|
||||||
|
# and native support is checked by verify the function "async_handle_web_rtc_offer" was
|
||||||
|
# overwritten(implemented) or not
|
||||||
|
class MockCamera(camera.Camera):
|
||||||
|
"""Mock Camera Entity."""
|
||||||
|
|
||||||
|
_attr_name = "Test"
|
||||||
|
_attr_supported_features: camera.CameraEntityFeature = (
|
||||||
|
camera.CameraEntityFeature.STREAM
|
||||||
|
)
|
||||||
|
_attr_frontend_stream_type: camera.StreamType = camera.StreamType.WEB_RTC
|
||||||
|
|
||||||
|
async def stream_source(self) -> str | None:
|
||||||
|
return STREAM_SOURCE
|
||||||
|
|
||||||
|
async def async_handle_web_rtc_offer(self, offer_sdp: str) -> str | None:
|
||||||
|
return WEBRTC_ANSWER
|
||||||
|
|
||||||
|
domain = "test"
|
||||||
|
|
||||||
|
entry = MockConfigEntry(domain=domain)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
async def async_setup_entry_init(
|
||||||
|
hass: HomeAssistant, config_entry: ConfigEntry
|
||||||
|
) -> bool:
|
||||||
|
"""Set up test config entry."""
|
||||||
|
await hass.config_entries.async_forward_entry_setups(
|
||||||
|
config_entry, [camera.DOMAIN]
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def async_unload_entry_init(
|
||||||
|
hass: HomeAssistant, config_entry: ConfigEntry
|
||||||
|
) -> bool:
|
||||||
|
"""Unload test config entry."""
|
||||||
|
await hass.config_entries.async_forward_entry_unload(
|
||||||
|
config_entry, camera.DOMAIN
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
mock_integration(
|
||||||
|
hass,
|
||||||
|
MockModule(
|
||||||
|
domain,
|
||||||
|
async_setup_entry=async_setup_entry_init,
|
||||||
|
async_unload_entry=async_unload_entry_init,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
setup_test_component_platform(
|
||||||
|
hass, camera.DOMAIN, [MockCamera()], from_config_entry=True
|
||||||
|
)
|
||||||
|
mock_platform(hass, f"{domain}.config_flow", Mock())
|
||||||
|
|
||||||
|
with mock_config_flow(domain, ConfigFlow):
|
||||||
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
@ -25,7 +25,6 @@ from homeassistant.components.camera.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.components.camera.helper import get_camera_from_entity_id
|
from homeassistant.components.camera.helper import get_camera_from_entity_id
|
||||||
from homeassistant.components.websocket_api import TYPE_RESULT
|
from homeassistant.components.websocket_api import TYPE_RESULT
|
||||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
EVENT_HOMEASSISTANT_STARTED,
|
EVENT_HOMEASSISTANT_STARTED,
|
||||||
@ -38,18 +37,12 @@ from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
|||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .common import EMPTY_8_6_JPEG, STREAM_SOURCE, WEBRTC_ANSWER, mock_turbo_jpeg
|
from .common import EMPTY_8_6_JPEG, STREAM_SOURCE, mock_turbo_jpeg
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
MockConfigEntry,
|
|
||||||
MockModule,
|
|
||||||
async_fire_time_changed,
|
async_fire_time_changed,
|
||||||
help_test_all,
|
help_test_all,
|
||||||
import_and_test_deprecated_constant_enum,
|
import_and_test_deprecated_constant_enum,
|
||||||
mock_config_flow,
|
|
||||||
mock_integration,
|
|
||||||
mock_platform,
|
|
||||||
setup_test_component_platform,
|
|
||||||
)
|
)
|
||||||
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
||||||
|
|
||||||
@ -986,62 +979,13 @@ async def test_camera_capabilities_hls(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_camera_webrtc_native_sync_offer")
|
||||||
async def test_camera_capabilities_webrtc(
|
async def test_camera_capabilities_webrtc(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_ws_client: WebSocketGenerator,
|
hass_ws_client: WebSocketGenerator,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test WebRTC camera capabilities."""
|
"""Test WebRTC camera capabilities."""
|
||||||
|
|
||||||
# Cannot use the fixture mock_camera_web_rtc as it's mocking Camera.async_handle_web_rtc_offer
|
|
||||||
# Camera capabilities are determined by by checking if the function was overwritten(implemented) or not
|
|
||||||
class MockCamera(camera.Camera):
|
|
||||||
"""Mock Camera Entity."""
|
|
||||||
|
|
||||||
_attr_name = "Test"
|
|
||||||
_attr_supported_features: camera.CameraEntityFeature = (
|
|
||||||
camera.CameraEntityFeature.STREAM
|
|
||||||
)
|
|
||||||
|
|
||||||
async def stream_source(self) -> str | None:
|
|
||||||
return STREAM_SOURCE
|
|
||||||
|
|
||||||
async def async_handle_web_rtc_offer(self, offer_sdp: str) -> str | None:
|
|
||||||
return WEBRTC_ANSWER
|
|
||||||
|
|
||||||
domain = "test"
|
|
||||||
|
|
||||||
entry = MockConfigEntry(domain=domain)
|
|
||||||
entry.add_to_hass(hass)
|
|
||||||
|
|
||||||
async def async_setup_entry_init(
|
|
||||||
hass: HomeAssistant, config_entry: ConfigEntry
|
|
||||||
) -> bool:
|
|
||||||
"""Set up test config entry."""
|
|
||||||
await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN])
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def async_unload_entry_init(
|
|
||||||
hass: HomeAssistant, config_entry: ConfigEntry
|
|
||||||
) -> bool:
|
|
||||||
"""Unload test config entry."""
|
|
||||||
await hass.config_entries.async_forward_entry_unload(config_entry, DOMAIN)
|
|
||||||
return True
|
|
||||||
|
|
||||||
mock_integration(
|
|
||||||
hass,
|
|
||||||
MockModule(
|
|
||||||
domain,
|
|
||||||
async_setup_entry=async_setup_entry_init,
|
|
||||||
async_unload_entry=async_unload_entry_init,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
setup_test_component_platform(hass, DOMAIN, [MockCamera()], from_config_entry=True)
|
|
||||||
mock_platform(hass, f"{domain}.config_flow", Mock())
|
|
||||||
|
|
||||||
with mock_config_flow(domain, ConfigFlow):
|
|
||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
await _test_capabilities(
|
await _test_capabilities(
|
||||||
hass, hass_ws_client, "camera.test", {StreamType.WEB_RTC}, {StreamType.WEB_RTC}
|
hass, hass_ws_client, "camera.test", {StreamType.WEB_RTC}, {StreamType.WEB_RTC}
|
||||||
)
|
)
|
||||||
|
@ -393,6 +393,29 @@ async def test_ws_get_client_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_camera_webrtc_native_sync_offer")
|
||||||
|
async def test_ws_get_client_config_sync_offer(
|
||||||
|
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||||
|
) -> None:
|
||||||
|
"""Test get WebRTC client config, when camera is supporting sync offer."""
|
||||||
|
await async_setup_component(hass, "camera", {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
client = await hass_ws_client(hass)
|
||||||
|
await client.send_json_auto_id(
|
||||||
|
{"type": "camera/webrtc/get_client_config", "entity_id": "camera.test"}
|
||||||
|
)
|
||||||
|
msg = await client.receive_json()
|
||||||
|
|
||||||
|
# Assert WebSocket response
|
||||||
|
assert msg["type"] == TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
assert msg["result"] == {
|
||||||
|
"configuration": {},
|
||||||
|
"getCandidatesUpfront": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("mock_camera_webrtc")
|
@pytest.mark.usefixtures("mock_camera_webrtc")
|
||||||
async def test_ws_get_client_config_custom_config(
|
async def test_ws_get_client_config_custom_config(
|
||||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
||||||
|
Loading…
x
Reference in New Issue
Block a user