Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use executor to finish stream recording #75776

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 27 additions & 17 deletions homeassistant/components/stream/recorder.py
Expand Up @@ -4,6 +4,7 @@
from io import BytesIO
import logging
import os
from typing import TYPE_CHECKING

import av

Expand All @@ -16,6 +17,9 @@
)
from .core import PROVIDERS, IdleTimer, Segment, StreamOutput, StreamSettings

if TYPE_CHECKING:
import deque

_LOGGER = logging.getLogger(__name__)


Expand Down Expand Up @@ -139,6 +143,25 @@ def write_segment(segment: Segment) -> None:

source.close()

def finish_writing(
segments: deque[Segment], output: av.OutputContainer, video_path: str
) -> None:
"""Finish writing output."""
# Should only have 0 or 1 segments, but loop through just in case
while segments:
write_segment(segments.popleft())
if output is None:
_LOGGER.error("Recording failed to capture anything")
return
output.close()
try:
os.rename(video_path + ".tmp", video_path)
except FileNotFoundError:
_LOGGER.error(
"Error writing to '%s'. There are likely multiple recordings writing to the same file",
video_path,
)

# Write lookback segments
while len(self._segments) > 1: # The last segment is in progress
await self._hass.async_add_executor_job(
Expand All @@ -153,20 +176,7 @@ def write_segment(segment: Segment) -> None:
await self._hass.async_add_executor_job(
write_segment, self._segments.popleft()
)
# Write remaining segments
# Should only have 0 or 1 segments, but loop through just in case
while self._segments:
await self._hass.async_add_executor_job(
write_segment, self._segments.popleft()
)
if output is None:
_LOGGER.error("Recording failed to capture anything")
else:
output.close()
try:
os.rename(self.video_path + ".tmp", self.video_path)
except FileNotFoundError:
_LOGGER.error(
"Error writing to '%s'. There are likely multiple recordings writing to the same file",
self.video_path,
)
# Write remaining segments and close output
await self._hass.async_add_executor_job(
finish_writing, self._segments, output, self.video_path
)