Route non-TTS media through ESPHome ffmpeg proxy (#126287)

* Route non-TTS media through proxy

* Use media_id_source
This commit is contained in:
Michael Hansen 2024-09-20 12:57:55 -05:00 committed by GitHub
parent e8d5ebef7e
commit 123b6b687e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 3 deletions

View File

@ -14,6 +14,7 @@ import wave
from aioesphomeapi import (
MediaPlayerFormatPurpose,
MediaPlayerSupportedFormat,
VoiceAssistantAnnounceFinished,
VoiceAssistantAudioSettings,
VoiceAssistantCommandFlag,
@ -44,6 +45,7 @@ from .const import DOMAIN
from .entity import EsphomeAssistEntity
from .entry_data import ESPHomeConfigEntry, RuntimeEntryData
from .enum_mapper import EsphomeEnumMapper
from .ffmpeg_proxy import async_create_proxy_url
_LOGGER = logging.getLogger(__name__)
@ -325,8 +327,34 @@ class EsphomeAssistSatellite(
announcement.message,
announcement.media_id,
)
media_id = announcement.media_id
if announcement.media_id_source != "tts":
# Route non-TTS media through the proxy
format_to_use: MediaPlayerSupportedFormat | None = None
for supported_format in chain(
*self.entry_data.media_player_formats.values()
):
if supported_format.purpose == MediaPlayerFormatPurpose.ANNOUNCEMENT:
format_to_use = supported_format
break
if format_to_use is not None:
assert (self.registry_entry is not None) and (
self.registry_entry.device_id is not None
)
proxy_url = async_create_proxy_url(
self.hass,
self.registry_entry.device_id,
media_id,
media_format=format_to_use.format,
rate=format_to_use.sample_rate or None,
channels=format_to_use.num_channels or None,
width=format_to_use.sample_bytes or None,
)
media_id = async_process_play_media_url(self.hass, proxy_url)
await self.cli.send_voice_assistant_announcement_await_response(
announcement.media_id, _ANNOUNCEMENT_TIMEOUT_SEC, announcement.message
media_id, _ANNOUNCEMENT_TIMEOUT_SEC, announcement.message
)
async def handle_pipeline_start(

View File

@ -1222,11 +1222,29 @@ async def test_announce_media_id(
[APIClient, list[EntityInfo], list[UserService], list[EntityState]],
Awaitable[MockESPHomeDevice],
],
device_registry: dr.DeviceRegistry,
) -> None:
"""Test announcement with media id."""
mock_device: MockESPHomeDevice = await mock_esphome_device(
mock_client=mock_client,
entity_info=[],
entity_info=[
MediaPlayerInfo(
object_id="mymedia_player",
key=1,
name="my media_player",
unique_id="my_media_player",
supports_pause=True,
supported_formats=[
MediaPlayerSupportedFormat(
format="flac",
sample_rate=48000,
num_channels=2,
purpose=MediaPlayerFormatPurpose.ANNOUNCEMENT,
sample_bytes=2,
),
],
)
],
user_service=[],
states=[],
device_info={
@ -1238,6 +1256,10 @@ async def test_announce_media_id(
)
await hass.async_block_till_done()
dev = device_registry.async_get_device(
connections={(dr.CONNECTION_NETWORK_MAC, mock_device.entry.unique_id)}
)
satellite = get_satellite_entity(hass, mock_device.device_info.mac_address)
assert satellite is not None
@ -1247,7 +1269,7 @@ async def test_announce_media_id(
media_id: str, timeout: float, text: str
):
assert satellite.state == AssistSatelliteState.RESPONDING
assert media_id == "https://www.home-assistant.io/resolved.mp3"
assert media_id == "https://www.home-assistant.io/proxied.flac"
done.set()
@ -1257,6 +1279,10 @@ async def test_announce_media_id(
"send_voice_assistant_announcement_await_response",
new=send_voice_assistant_announcement_await_response,
),
patch(
"homeassistant.components.esphome.assist_satellite.async_create_proxy_url",
return_value="https://www.home-assistant.io/proxied.flac",
) as mock_async_create_proxy_url,
):
async with asyncio.timeout(1):
await hass.services.async_call(
@ -1271,6 +1297,16 @@ async def test_announce_media_id(
await done.wait()
assert satellite.state == AssistSatelliteState.LISTENING_WAKE_WORD
mock_async_create_proxy_url.assert_called_once_with(
hass,
dev.id,
"https://www.home-assistant.io/resolved.mp3",
media_format="flac",
rate=48000,
channels=2,
width=2,
)
async def test_satellite_unloaded_on_disconnect(
hass: HomeAssistant,