Change the API boundary between camera and stream with initial improvement for nest expiring stream urls (#45431)
* Change the API boundary between stream and camera Shift more of the stream lifecycle management to the camera. The motivation is to support stream urls that expire giving the camera the ability to change the stream once it is created. * Document stream lifecycle and simplify stream/camera interaction * Reorder create_stream function to reduce diffs * Increase test coverage for camera_sdm.py * Fix ffmpeg typo. * Add a stream identifier for each stream, managed by camera * Remove stream record service * Update homeassistant/components/stream/__init__.py Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io> * Unroll changes to Stream interface back into camera component * Fix preload stream to actually start the background worker * Reduce unncessary diffs for readability * Remove redundant camera stream start code Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
889baef456
commit
2bcf87b980
14 changed files with 254 additions and 356 deletions
|
@ -155,25 +155,20 @@ async def test_websocket_camera_thumbnail(hass, hass_ws_client, mock_camera):
|
|||
async def test_websocket_stream_no_source(
|
||||
hass, hass_ws_client, mock_camera, mock_stream
|
||||
):
|
||||
"""Test camera/stream websocket command."""
|
||||
"""Test camera/stream websocket command with camera with no source."""
|
||||
await async_setup_component(hass, "camera", {})
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.camera.request_stream",
|
||||
return_value="http://home.assistant/playlist.m3u8",
|
||||
) as mock_request_stream:
|
||||
# Request playlist through WebSocket
|
||||
client = await hass_ws_client(hass)
|
||||
await client.send_json(
|
||||
{"id": 6, "type": "camera/stream", "entity_id": "camera.demo_camera"}
|
||||
)
|
||||
msg = await client.receive_json()
|
||||
# Request playlist through WebSocket
|
||||
client = await hass_ws_client(hass)
|
||||
await client.send_json(
|
||||
{"id": 6, "type": "camera/stream", "entity_id": "camera.demo_camera"}
|
||||
)
|
||||
msg = await client.receive_json()
|
||||
|
||||
# Assert WebSocket response
|
||||
assert not mock_request_stream.called
|
||||
assert msg["id"] == 6
|
||||
assert msg["type"] == TYPE_RESULT
|
||||
assert not msg["success"]
|
||||
# Assert WebSocket response
|
||||
assert msg["id"] == 6
|
||||
assert msg["type"] == TYPE_RESULT
|
||||
assert not msg["success"]
|
||||
|
||||
|
||||
async def test_websocket_camera_stream(hass, hass_ws_client, mock_camera, mock_stream):
|
||||
|
@ -181,9 +176,9 @@ async def test_websocket_camera_stream(hass, hass_ws_client, mock_camera, mock_s
|
|||
await async_setup_component(hass, "camera", {})
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.camera.request_stream",
|
||||
"homeassistant.components.camera.Stream.endpoint_url",
|
||||
return_value="http://home.assistant/playlist.m3u8",
|
||||
) as mock_request_stream, patch(
|
||||
) as mock_stream_view_url, patch(
|
||||
"homeassistant.components.demo.camera.DemoCamera.stream_source",
|
||||
return_value="http://example.com",
|
||||
):
|
||||
|
@ -195,7 +190,7 @@ async def test_websocket_camera_stream(hass, hass_ws_client, mock_camera, mock_s
|
|||
msg = await client.receive_json()
|
||||
|
||||
# Assert WebSocket response
|
||||
assert mock_request_stream.called
|
||||
assert mock_stream_view_url.called
|
||||
assert msg["id"] == 6
|
||||
assert msg["type"] == TYPE_RESULT
|
||||
assert msg["success"]
|
||||
|
@ -248,9 +243,7 @@ async def test_play_stream_service_no_source(hass, mock_camera, mock_stream):
|
|||
ATTR_ENTITY_ID: "camera.demo_camera",
|
||||
camera.ATTR_MEDIA_PLAYER: "media_player.test",
|
||||
}
|
||||
with patch("homeassistant.components.camera.request_stream"), pytest.raises(
|
||||
HomeAssistantError
|
||||
):
|
||||
with pytest.raises(HomeAssistantError):
|
||||
# Call service
|
||||
await hass.services.async_call(
|
||||
camera.DOMAIN, camera.SERVICE_PLAY_STREAM, data, blocking=True
|
||||
|
@ -265,7 +258,7 @@ async def test_handle_play_stream_service(hass, mock_camera, mock_stream):
|
|||
)
|
||||
await async_setup_component(hass, "media_player", {})
|
||||
with patch(
|
||||
"homeassistant.components.camera.request_stream"
|
||||
"homeassistant.components.camera.Stream.endpoint_url",
|
||||
) as mock_request_stream, patch(
|
||||
"homeassistant.components.demo.camera.DemoCamera.stream_source",
|
||||
return_value="http://example.com",
|
||||
|
@ -289,7 +282,7 @@ async def test_no_preload_stream(hass, mock_stream):
|
|||
"""Test camera preload preference."""
|
||||
demo_prefs = CameraEntityPreferences({PREF_PRELOAD_STREAM: False})
|
||||
with patch(
|
||||
"homeassistant.components.camera.request_stream"
|
||||
"homeassistant.components.camera.Stream.endpoint_url",
|
||||
) as mock_request_stream, patch(
|
||||
"homeassistant.components.camera.prefs.CameraPreferences.get",
|
||||
return_value=demo_prefs,
|
||||
|
@ -308,8 +301,8 @@ async def test_preload_stream(hass, mock_stream):
|
|||
"""Test camera preload preference."""
|
||||
demo_prefs = CameraEntityPreferences({PREF_PRELOAD_STREAM: True})
|
||||
with patch(
|
||||
"homeassistant.components.camera.request_stream"
|
||||
) as mock_request_stream, patch(
|
||||
"homeassistant.components.camera.create_stream"
|
||||
) as mock_create_stream, patch(
|
||||
"homeassistant.components.camera.prefs.CameraPreferences.get",
|
||||
return_value=demo_prefs,
|
||||
), patch(
|
||||
|
@ -322,7 +315,7 @@ async def test_preload_stream(hass, mock_stream):
|
|||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
await hass.async_block_till_done()
|
||||
assert mock_request_stream.called
|
||||
assert mock_create_stream.called
|
||||
|
||||
|
||||
async def test_record_service_invalid_path(hass, mock_camera):
|
||||
|
@ -348,10 +341,9 @@ async def test_record_service(hass, mock_camera, mock_stream):
|
|||
"homeassistant.components.demo.camera.DemoCamera.stream_source",
|
||||
return_value="http://example.com",
|
||||
), patch(
|
||||
"homeassistant.components.stream.async_handle_record_service",
|
||||
) as mock_record_service, patch.object(
|
||||
hass.config, "is_allowed_path", return_value=True
|
||||
):
|
||||
"homeassistant.components.stream.Stream.async_record",
|
||||
autospec=True,
|
||||
) as mock_record:
|
||||
# Call service
|
||||
await hass.services.async_call(
|
||||
camera.DOMAIN,
|
||||
|
@ -361,4 +353,4 @@ async def test_record_service(hass, mock_camera, mock_stream):
|
|||
)
|
||||
# So long as we call stream.record, the rest should be covered
|
||||
# by those tests.
|
||||
assert mock_record_service.called
|
||||
assert mock_record.called
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue