Convert stream source to method (#23905)

* Convert stream source to method

* Use async with
This commit is contained in:
Paulus Schoutsen 2019-05-23 09:45:30 -07:00 committed by GitHub
parent 8d22479d24
commit 1de0a0bbb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 50 additions and 39 deletions

View File

@ -203,8 +203,7 @@ class AmcrestCam(Camera):
"""Return the camera model.""" """Return the camera model."""
return self._model return self._model
@property async def stream_source(self):
def stream_source(self):
"""Return the source of the stream.""" """Return the source of the stream."""
return self._api.rtsp_url(typeno=self._resolution) return self._api.rtsp_url(typeno=self._resolution)

View File

@ -58,8 +58,7 @@ class AxisCamera(AxisEntityBase, MjpegCamera):
"""Return supported features.""" """Return supported features."""
return SUPPORT_STREAM return SUPPORT_STREAM
@property async def stream_source(self):
def stream_source(self):
"""Return the stream source.""" """Return the stream source."""
return AXIS_STREAM.format( return AXIS_STREAM.format(
self.device.config_entry.data[CONF_DEVICE][CONF_USERNAME], self.device.config_entry.data[CONF_DEVICE][CONF_USERNAME],

View File

@ -107,11 +107,14 @@ async def async_request_stream(hass, entity_id, fmt):
camera = _get_camera_from_entity_id(hass, entity_id) camera = _get_camera_from_entity_id(hass, entity_id)
camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id) camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id)
if not camera.stream_source: async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support play stream service" raise HomeAssistantError("{} does not support play stream service"
.format(camera.entity_id)) .format(camera.entity_id))
return request_stream(hass, camera.stream_source, fmt=fmt, return request_stream(hass, source, fmt=fmt,
keepalive=camera_prefs.preload_stream) keepalive=camera_prefs.preload_stream)
@ -121,7 +124,7 @@ async def async_get_image(hass, entity_id, timeout=10):
camera = _get_camera_from_entity_id(hass, entity_id) camera = _get_camera_from_entity_id(hass, entity_id)
with suppress(asyncio.CancelledError, asyncio.TimeoutError): with suppress(asyncio.CancelledError, asyncio.TimeoutError):
with async_timeout.timeout(timeout): async with async_timeout.timeout(timeout):
image = await camera.async_camera_image() image = await camera.async_camera_image()
if image: if image:
@ -221,8 +224,16 @@ async def async_setup(hass, config):
async def preload_stream(hass, _): async def preload_stream(hass, _):
for camera in component.entities: for camera in component.entities:
camera_prefs = prefs.get(camera.entity_id) camera_prefs = prefs.get(camera.entity_id)
if camera.stream_source and camera_prefs.preload_stream: if not camera_prefs.preload_stream:
request_stream(hass, camera.stream_source, keepalive=True) continue
async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
continue
request_stream(hass, source, keepalive=True)
async_when_setup(hass, DOMAIN_STREAM, preload_stream) async_when_setup(hass, DOMAIN_STREAM, preload_stream)
@ -328,8 +339,7 @@ class Camera(Entity):
"""Return the interval between frames of the mjpeg stream.""" """Return the interval between frames of the mjpeg stream."""
return 0.5 return 0.5
@property async def stream_source(self):
def stream_source(self):
"""Return the source of the stream.""" """Return the source of the stream."""
return None return None
@ -481,7 +491,7 @@ class CameraImageView(CameraView):
async def handle(self, request, camera): async def handle(self, request, camera):
"""Serve camera image.""" """Serve camera image."""
with suppress(asyncio.CancelledError, asyncio.TimeoutError): with suppress(asyncio.CancelledError, asyncio.TimeoutError):
with async_timeout.timeout(10): async with async_timeout.timeout(10):
image = await camera.async_camera_image() image = await camera.async_camera_image()
if image: if image:
@ -547,18 +557,25 @@ async def ws_camera_stream(hass, connection, msg):
camera = _get_camera_from_entity_id(hass, entity_id) camera = _get_camera_from_entity_id(hass, entity_id)
camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id) camera_prefs = hass.data[DATA_CAMERA_PREFS].get(entity_id)
if not camera.stream_source: async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support play stream service" raise HomeAssistantError("{} does not support play stream service"
.format(camera.entity_id)) .format(camera.entity_id))
fmt = msg['format'] fmt = msg['format']
url = request_stream(hass, camera.stream_source, fmt=fmt, url = request_stream(hass, source, fmt=fmt,
keepalive=camera_prefs.preload_stream) keepalive=camera_prefs.preload_stream)
connection.send_result(msg['id'], {'url': url}) connection.send_result(msg['id'], {'url': url})
except HomeAssistantError as ex: except HomeAssistantError as ex:
_LOGGER.error(ex) _LOGGER.error("Error requesting stream: %s", ex)
connection.send_error( connection.send_error(
msg['id'], 'start_stream_failed', str(ex)) msg['id'], 'start_stream_failed', str(ex))
except asyncio.TimeoutError:
_LOGGER.error("Timeout getting stream source")
connection.send_error(
msg['id'], 'start_stream_failed', "Timeout getting stream source")
@websocket_api.async_response @websocket_api.async_response
@ -622,7 +639,10 @@ async def async_handle_snapshot_service(camera, service):
async def async_handle_play_stream_service(camera, service_call): async def async_handle_play_stream_service(camera, service_call):
"""Handle play stream services calls.""" """Handle play stream services calls."""
if not camera.stream_source: async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support play stream service" raise HomeAssistantError("{} does not support play stream service"
.format(camera.entity_id)) .format(camera.entity_id))
@ -631,7 +651,7 @@ async def async_handle_play_stream_service(camera, service_call):
fmt = service_call.data[ATTR_FORMAT] fmt = service_call.data[ATTR_FORMAT]
entity_ids = service_call.data[ATTR_MEDIA_PLAYER] entity_ids = service_call.data[ATTR_MEDIA_PLAYER]
url = request_stream(hass, camera.stream_source, fmt=fmt, url = request_stream(hass, source, fmt=fmt,
keepalive=camera_prefs.preload_stream) keepalive=camera_prefs.preload_stream)
data = { data = {
ATTR_ENTITY_ID: entity_ids, ATTR_ENTITY_ID: entity_ids,
@ -646,7 +666,10 @@ async def async_handle_play_stream_service(camera, service_call):
async def async_handle_record_service(camera, call): async def async_handle_record_service(camera, call):
"""Handle stream recording service calls.""" """Handle stream recording service calls."""
if not camera.stream_source: async with async_timeout.timeout(10):
source = await camera.stream_source()
if not source:
raise HomeAssistantError("{} does not support record service" raise HomeAssistantError("{} does not support record service"
.format(camera.entity_id)) .format(camera.entity_id))
@ -657,7 +680,7 @@ async def async_handle_record_service(camera, call):
variables={ATTR_ENTITY_ID: camera}) variables={ATTR_ENTITY_ID: camera})
data = { data = {
CONF_STREAM_SOURCE: camera.stream_source, CONF_STREAM_SOURCE: source,
CONF_FILENAME: video_path, CONF_FILENAME: video_path,
CONF_DURATION: call.data[CONF_DURATION], CONF_DURATION: call.data[CONF_DURATION],
CONF_LOOKBACK: call.data[CONF_LOOKBACK], CONF_LOOKBACK: call.data[CONF_LOOKBACK],

View File

@ -57,8 +57,7 @@ class DoorBirdCamera(Camera):
self._last_update = datetime.datetime.min self._last_update = datetime.datetime.min
super().__init__() super().__init__()
@property async def stream_source(self):
def stream_source(self):
"""Return the stream source.""" """Return the stream source."""
return self._stream_url return self._stream_url

View File

@ -47,8 +47,7 @@ class FFmpegCamera(Camera):
"""Return supported features.""" """Return supported features."""
return SUPPORT_STREAM return SUPPORT_STREAM
@property async def stream_source(self):
def stream_source(self):
"""Return the stream source.""" """Return the stream source."""
return self._input.split(' ')[-1] return self._input.split(' ')[-1]

View File

@ -77,8 +77,7 @@ class FoscamCam(Camera):
return SUPPORT_STREAM return SUPPORT_STREAM
return 0 return 0
@property async def stream_source(self):
def stream_source(self):
"""Return the stream source.""" """Return the stream source."""
if self._rtsp_port: if self._rtsp_port:
return 'rtsp://{}:{}@{}:{}/videoMain'.format( return 'rtsp://{}:{}@{}:{}/videoMain'.format(

View File

@ -146,7 +146,6 @@ class GenericCamera(Camera):
"""Return the name of this device.""" """Return the name of this device."""
return self._name return self._name
@property async def stream_source(self):
def stream_source(self):
"""Return the source of the stream.""" """Return the source of the stream."""
return self._stream_source return self._stream_source

View File

@ -123,8 +123,7 @@ class NetatmoCamera(Camera):
"""Return supported features.""" """Return supported features."""
return SUPPORT_STREAM return SUPPORT_STREAM
@property async def stream_source(self):
def stream_source(self):
"""Return the stream source.""" """Return the stream source."""
url = '{0}/live/files/{1}/index.m3u8' url = '{0}/live/files/{1}/index.m3u8'
if self._localurl: if self._localurl:

View File

@ -339,8 +339,7 @@ class ONVIFHassCamera(Camera):
return SUPPORT_STREAM return SUPPORT_STREAM
return 0 return 0
@property async def stream_source(self):
def stream_source(self):
"""Return the stream source.""" """Return the stream source."""
return self._input return self._input

View File

@ -209,8 +209,7 @@ async def test_websocket_camera_stream(hass, hass_ws_client,
return_value='http://home.assistant/playlist.m3u8' return_value='http://home.assistant/playlist.m3u8'
) as mock_request_stream, \ ) as mock_request_stream, \
patch('homeassistant.components.demo.camera.DemoCamera.stream_source', patch('homeassistant.components.demo.camera.DemoCamera.stream_source',
new_callable=PropertyMock) as mock_stream_source: return_value=mock_coro('http://example.com')):
mock_stream_source.return_value = io.BytesIO()
# Request playlist through WebSocket # Request playlist through WebSocket
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
await client.send_json({ await client.send_json({
@ -289,8 +288,7 @@ async def test_handle_play_stream_service(hass, mock_camera, mock_stream):
with patch('homeassistant.components.camera.request_stream' with patch('homeassistant.components.camera.request_stream'
) as mock_request_stream, \ ) as mock_request_stream, \
patch('homeassistant.components.demo.camera.DemoCamera.stream_source', patch('homeassistant.components.demo.camera.DemoCamera.stream_source',
new_callable=PropertyMock) as mock_stream_source: return_value=mock_coro('http://example.com')):
mock_stream_source.return_value = io.BytesIO()
# Call service # Call service
await hass.services.async_call( await hass.services.async_call(
camera.DOMAIN, camera.SERVICE_PLAY_STREAM, data, blocking=True) camera.DOMAIN, camera.SERVICE_PLAY_STREAM, data, blocking=True)
@ -331,8 +329,7 @@ async def test_preload_stream(hass, mock_stream):
patch('homeassistant.components.camera.prefs.CameraPreferences.get', patch('homeassistant.components.camera.prefs.CameraPreferences.get',
return_value=demo_prefs), \ return_value=demo_prefs), \
patch('homeassistant.components.demo.camera.DemoCamera.stream_source', patch('homeassistant.components.demo.camera.DemoCamera.stream_source',
new_callable=PropertyMock) as mock_stream_source: return_value=mock_coro("http://example.com")):
mock_stream_source.return_value = io.BytesIO()
await async_setup_component(hass, 'camera', { await async_setup_component(hass, 'camera', {
DOMAIN: { DOMAIN: {
'platform': 'demo' 'platform': 'demo'
@ -364,12 +361,11 @@ async def test_record_service(hass, mock_camera, mock_stream):
} }
with patch('homeassistant.components.demo.camera.DemoCamera.stream_source', with patch('homeassistant.components.demo.camera.DemoCamera.stream_source',
new_callable=PropertyMock) as mock_stream_source, \ return_value=mock_coro("http://example.com")), \
patch( patch(
'homeassistant.components.stream.async_handle_record_service', 'homeassistant.components.stream.async_handle_record_service',
return_value=mock_coro()) as mock_record_service, \ return_value=mock_coro()) as mock_record_service, \
patch.object(hass.config, 'is_allowed_path', return_value=True): patch.object(hass.config, 'is_allowed_path', return_value=True):
mock_stream_source.return_value = io.BytesIO()
# Call service # Call service
await hass.services.async_call( await hass.services.async_call(
camera.DOMAIN, camera.SERVICE_RECORD, data, blocking=True) camera.DOMAIN, camera.SERVICE_RECORD, data, blocking=True)