Skip to content

livestream: read frames with readexactly to avoid truncation#1232

Open
jasoncarreira wants to merge 1 commit into
fronzbot:devfrom
jasoncarreira:fix/livestream-readexactly
Open

livestream: read frames with readexactly to avoid truncation#1232
jasoncarreira wants to merge 1 commit into
fronzbot:devfrom
jasoncarreira:fix/livestream-readexactly

Conversation

@jasoncarreira

Copy link
Copy Markdown

Description

BlinkLiveStream.recv() reads the 9-byte immis frame header and then the
payload with StreamReader.read(n):

data = await self.target_reader.read(9)
if len(data) < 9:
    _LOGGER.warning("Insufficient data for header: %d bytes, expected 9", len(data))
    break

StreamReader.read(n) returns up to n bytes — it resolves as soon as any
data is buffered. When a header or payload is split across TCP segments (very
common for the larger video payloads), read() returns a short buffer, the
len(data) < n guard treats it as EOF, and the stream is torn down mid-frame
even though the connection is perfectly healthy.

This replaces both reads with readexactly(), which waits for the full frame
and raises IncompleteReadError only on a genuine EOF:

try:
    data = await self.target_reader.readexactly(9)
except asyncio.IncompleteReadError:
    _LOGGER.debug("Target closed before a full 9-byte header")
    break

How I found it

While getting live view working through Home Assistant I built a standalone
relay that parses the immis framing from a buffer (accumulate-then-slice) and it
streamed hundreds of H.264 frames reliably. A faithful port that used read(n)
instead would intermittently abort with "Insufficient data". The difference is
exactly this partial-read handling.

Note: this is independent of the recent OAuth/2FA (202) and liveview-endpoint
work in #1227/#1228/#1229/#1231 — it's a latent framing bug that surfaces once a
live view actually connects and starts delivering video.

Checklist

  • Behavior verified against a live immis stream (buffered parse streams reliably; read(n) truncates)
  • tox (no test currently exercises recv() framing; happy to add one if desired)

@mback2k

mback2k commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Thanks a lot, this looks good! You mentioned that you are working on HA integration as well, have you seen my work-in-progress PR which was blocked due to performance issues and the recent changes to the blink API?
home-assistant/core#160708

I would like to avoid double-work.

@fronzbot

Copy link
Copy Markdown
Owner

@jasoncarreira this looks good- just fix the failing test (probably the test is expecting a certain call and your change modified that flow) and I'll merge.

StreamReader.read(n) returns up to n bytes, so a header or payload split
across TCP segments was misread as a short read and aborted the stream.
readexactly() blocks for the full frame and raises IncompleteReadError
only on a genuine EOF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jasoncarreira jasoncarreira force-pushed the fix/livestream-readexactly branch from d69332a to 58fc442 Compare June 14, 2026 17:10
@jasoncarreira

Copy link
Copy Markdown
Author

Thanks @mback2k! No double-work to worry about — I'm not doing a competing HA-core PR. My Blink live-view work was just a local custom_components shim on my own HA while the upstream pieces land, so #160708 is the path forward and I'm glad to help it along.

A few findings from reverse-engineering the immis stream that may help the perf/stability issues:

  • This PR (readexactly) fixes intermittent stream truncation — read(n) under-reads frames split across TCP segments, which shows up as aborted/janky streams.
  • Blink enforces ~1 concurrent live view per account: a 2nd overlapping session (or a rapid re-tap before the ~30s server-side release) gets rejected with a control packet (msgtype 8) then EOF. That likely explains intermittent "won't start" reports — the HA side may need to serialize/preempt live views per account.
  • The v6 liveview endpoint (your Fix changed liveview API endpoints #1227) + motion_event_start_time is required now; v5 returns no usable immis server.

I've got several Blink cameras + a doorbell on HA — happy to test #160708 and give performance feedback.

@mback2k

mback2k commented Jun 16, 2026

Copy link
Copy Markdown
Contributor
  • the HA side may need to serialize/preempt live views per account

From previous experiences with other HA core integrations the core developers will probably ask the library to take care of that, for example via a mutex lock or something similar inside the library API instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants