Improve shutdown of esphome ffmpeg proxy (#129326)
* Improve shutdown of esphome ffmpeg proxy * Add test
This commit is contained in:
parent
db81edfb2b
commit
b4e69bab71
2 changed files with 59 additions and 3 deletions
|
@ -194,7 +194,11 @@ class FFmpegConvertResponse(web.StreamResponse):
|
||||||
# Only one conversion process per device is allowed
|
# Only one conversion process per device is allowed
|
||||||
self.convert_info.proc = proc
|
self.convert_info.proc = proc
|
||||||
|
|
||||||
await self._write_ffmpeg_data(request, writer, proc)
|
# Create background task which will be cancelled when home assistant shuts down
|
||||||
|
write_task = self.hass.async_create_background_task(
|
||||||
|
self._write_ffmpeg_data(request, writer, proc), "ESPHome media proxy"
|
||||||
|
)
|
||||||
|
await write_task
|
||||||
|
|
||||||
async def _write_ffmpeg_data(
|
async def _write_ffmpeg_data(
|
||||||
self,
|
self,
|
||||||
|
@ -215,6 +219,11 @@ class FFmpegConvertResponse(web.StreamResponse):
|
||||||
):
|
):
|
||||||
await self.write(chunk)
|
await self.write(chunk)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
|
_LOGGER.debug("ffmpeg transcoding cancelled")
|
||||||
|
# Abort the transport, we don't wait for ESPHome to drain the write buffer;
|
||||||
|
# it may need a very long time or never finish if the player is paused.
|
||||||
|
if request.transport:
|
||||||
|
request.transport.abort()
|
||||||
raise # don't log error
|
raise # don't log error
|
||||||
except:
|
except:
|
||||||
_LOGGER.exception("Unexpected error during ffmpeg conversion")
|
_LOGGER.exception("Unexpected error during ffmpeg conversion")
|
||||||
|
@ -234,8 +243,9 @@ class FFmpegConvertResponse(web.StreamResponse):
|
||||||
if proc.returncode is None:
|
if proc.returncode is None:
|
||||||
proc.kill()
|
proc.kill()
|
||||||
|
|
||||||
# Close connection
|
# Close connection by writing EOF unless already closing
|
||||||
await writer.write_eof()
|
if request.transport and not request.transport.is_closing():
|
||||||
|
await writer.write_eof()
|
||||||
|
|
||||||
|
|
||||||
class FFmpegProxyView(HomeAssistantView):
|
class FFmpegProxyView(HomeAssistantView):
|
||||||
|
|
|
@ -9,6 +9,7 @@ from unittest.mock import patch
|
||||||
from urllib.request import pathname2url
|
from urllib.request import pathname2url
|
||||||
import wave
|
import wave
|
||||||
|
|
||||||
|
from aiohttp import client_exceptions
|
||||||
import mutagen
|
import mutagen
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -286,3 +287,48 @@ async def test_max_conversions_per_device(
|
||||||
for url in urls[1:]:
|
for url in urls[1:]:
|
||||||
req = await client.get(url)
|
req = await client.get(url)
|
||||||
assert req.status == HTTPStatus.OK
|
assert req.status == HTTPStatus.OK
|
||||||
|
|
||||||
|
|
||||||
|
async def test_abort_on_shutdown(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
|
) -> None:
|
||||||
|
"""Test we abort on Home Assistant shutdown."""
|
||||||
|
device_id = "1234"
|
||||||
|
|
||||||
|
await async_setup_component(hass, esphome.DOMAIN, {esphome.DOMAIN: {}})
|
||||||
|
client = await hass_client()
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(mode="wb+", suffix=".wav") as temp_file:
|
||||||
|
with wave.open(temp_file.name, "wb") as wav_file:
|
||||||
|
wav_file.setframerate(16000)
|
||||||
|
wav_file.setsampwidth(2)
|
||||||
|
wav_file.setnchannels(1)
|
||||||
|
wav_file.writeframes(bytes(16000 * 2)) # 1s
|
||||||
|
|
||||||
|
wav_url = pathname2url(temp_file.name)
|
||||||
|
convert_id = "test-id"
|
||||||
|
url = f"/api/esphome/ffmpeg_proxy/{device_id}/{convert_id}.mp3"
|
||||||
|
|
||||||
|
wav_url = pathname2url(temp_file.name)
|
||||||
|
url = async_create_proxy_url(
|
||||||
|
hass,
|
||||||
|
device_id,
|
||||||
|
wav_url,
|
||||||
|
media_format="wav",
|
||||||
|
rate=22050,
|
||||||
|
channels=2,
|
||||||
|
width=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get URL and start reading
|
||||||
|
req = await client.get(url)
|
||||||
|
assert req.status == HTTPStatus.OK
|
||||||
|
initial_mp3_data = await req.content.read(4)
|
||||||
|
assert initial_mp3_data == b"RIFF"
|
||||||
|
|
||||||
|
# Shut down Home Assistant
|
||||||
|
await hass.async_stop()
|
||||||
|
|
||||||
|
with pytest.raises(client_exceptions.ClientPayloadError):
|
||||||
|
await req.content.read()
|
||||||
|
|
Loading…
Add table
Reference in a new issue