Use iter_chunked for STT audio stream to prevent LineTooLong (#180831)

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Giacomo Saccaggi
2026-09-02 10:01:24 +00:00
committed by Franck Nijhof
co-authored by Copilot Autofix powered by AI
parent f0fa136a83
commit 079d8e32c9
2 changed files with 37 additions and 2 deletions
+7 -2
View File
@@ -72,6 +72,11 @@ _LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
# Audio is read from the request body in chunks of at most 4096 bytes because
# line-based iteration raises LineTooLong on binary audio without newline bytes.
# At 16 kHz/16-bit/mono, 4096 bytes represents up to 128 ms of audio.
AUDIO_CHUNK_SIZE = 4096
@callback
def async_default_engine(hass: HomeAssistant) -> str | None:
@@ -291,7 +296,7 @@ class SpeechToTextView(HomeAssistantView):
# Process audio stream
result = await stt_provider.async_process_audio_stream(
metadata, request.content
metadata, request.content.iter_chunked(AUDIO_CHUNK_SIZE)
)
else:
# Check format
@@ -300,7 +305,7 @@ class SpeechToTextView(HomeAssistantView):
# Process audio stream
result = await provider_entity.internal_async_process_audio_stream(
metadata, request.content
metadata, request.content.iter_chunked(AUDIO_CHUNK_SIZE)
)
# Return result
+30
View File
@@ -644,3 +644,33 @@ async def test_audio_processing_custom(hass: HomeAssistant, tmp_path: Path) -> N
assert engine.audio_processing.requires_external_vad is False
assert engine.audio_processing.prefers_auto_gain_enabled is False
assert engine.audio_processing.prefers_noise_reduction_enabled is False
@pytest.mark.parametrize(
"setup", ["mock_setup", "mock_config_entry_setup"], indirect=True
)
async def test_stream_audio_large_no_newline_block(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
setup: MockSTTProvider | MockSTTProviderEntity,
) -> None:
"""Test a newline-free audio stream larger than aiohttp's line limit."""
# 600,000 bytes of silence - larger than the 512KB LineTooLong threshold.
# This is the reproduction case from issue #180708.
test_data = b"\x00" * 600_000
client = await hass_client()
response = await client.post(
f"/api/stt/{setup.url_path}",
headers={
"X-Speech-Content": (
"format=wav; codec=pcm; sample_rate=16000; bit_rate=16; channel=1;"
" language=en"
)
},
data=test_data,
)
assert response.status == HTTPStatus.OK
assert await response.json() == {"text": "test_result", "result": "success"}
received_data = b"".join(setup.received)
assert received_data == test_data