diff options
| -rw-r--r-- | main/stream_server.c | 14 | ||||
| -rw-r--r-- | scrypted/scrypted-viewport.ts | 21 | ||||
| -rw-r--r-- | sdkconfig.defaults | 19 |
3 files changed, 40 insertions, 14 deletions
diff --git a/main/stream_server.c b/main/stream_server.c index 7876968..10d1e1b 100644 --- a/main/stream_server.c +++ b/main/stream_server.c @@ -9,6 +9,7 @@ #include "freertos/task.h" #include "lwip/netdb.h" #include "lwip/sockets.h" +#include "sys/ioctl.h" #include "display.h" #include "jpeg_decoder.h" @@ -132,6 +133,19 @@ static void handle_client(int fd, const char *peer) continue; } + // "Always paint the latest" — if the socket already has more + // bytes queued in the kernel receive buffer, at least one more + // header is on the way. The frame we just finished receiving + // is no longer the freshest possible; skip its decode+paint + // (saves ~6ms per skip) and loop straight to the next header. + // This trades some intermediate frames for lower + // glass-to-glass latency on the latest one. + int queued = 0; + if (ioctl(fd, FIONREAD, &queued) == 0 && queued >= HEADER_BYTES) { + jpeg_decoder_unlock(); + continue; + } + size_t back_size = 0; void *back = display_back_buffer(&back_size); uint16_t w = 0, h = 0; diff --git a/scrypted/scrypted-viewport.ts b/scrypted/scrypted-viewport.ts index f25f557..fddfd28 100644 --- a/scrypted/scrypted-viewport.ts +++ b/scrypted/scrypted-viewport.ts @@ -6,7 +6,7 @@ // short git hash of the commit that added this constant — if the // hash in the log doesn't match the HEAD this file came from, the // Scrypted Script editor is still on stale code. -const SCRIPT_VERSION = "521de7e"; +const SCRIPT_VERSION = "pending"; // // Architecture // ------------ @@ -947,12 +947,15 @@ class ScryptedViewportProvider extends ScryptedDeviceBase workBuf = workBuf.subarray(eoi + 2); if (frame.length < 4 || frame[0] !== 0xff || frame[1] !== 0xd8) continue; - // Drop if the socket isn't connected yet (initial - // open) or if the kernel send buffer is full - // (firmware can't ingest as fast as ffmpeg emits). - // Frame is gone forever — TCP doesn't queue what - // we don't write. - if (!socketReady || socketBackpressured) { + // Drop only when the socket isn't connected yet + // (initial-open race) — once it's up we just keep + // writing. Node buffers internally if the kernel + // send buffer is full; under 16 MB/s ffmpeg output + // and ~5-7 MB/s firmware ingest the buffer rarely + // exceeds a frame or two. The firmware's FIONREAD- + // skip ensures it always paints the LATEST queued + // frame, so any backlog gets shed there for free. + if (!socketReady) { droppedFrames++; continue; } @@ -969,7 +972,11 @@ class ScryptedViewportProvider extends ScryptedDeviceBase if (writeLatencies.length > 200) writeLatencies.shift(); bytesSent += 8 + frame.length; sentFrames++; + // Track but don't gate on backpressure — the metric + // is still useful as a "kernel buffer was full" + // indicator for diagnostics. if (!ok) socketBackpressured = true; + else socketBackpressured = false; } }); diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 4c50a23..1ba8375 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -29,13 +29,18 @@ CONFIG_LWIP_IPV4=y CONFIG_LWIP_IPV6=y CONFIG_MDNS_MAX_INTERFACES=1 -# TCP receive-window tuning attempted (WND/SND_BUF=32k, RECVMBOX=16, -# SACK on). Measured net-negative on the /frame path: ttfb regressed -# from ~350µs to ~1.2ms, body unchanged, and periodic 250+ms stalls -# appeared. Reason: Scrypted's per-frame fetch() opens a fresh TCP -# socket each time, so the larger window just slows slow-start. -# Reverted; revisit once we switch to HTTP keep-alive on the Scrypted -# side. Keeping the lwIP defaults. +# TCP receive-window + buffer tuning. Earlier attempt under HTTP +# regressed because every /frame opened a fresh socket and we ate +# the slow-start cost repeatedly. Under the streaming pivot the +# socket is long-lived: slow-start happens once, then we run with +# the full window for the rest of the session — which is exactly +# the workload these knobs are designed for. Larger WND lets the +# sender keep more bytes in flight per ACK and pushes our recv +# throughput ceiling up from ~5.3 MB/s. +CONFIG_LWIP_TCP_WND_DEFAULT=65535 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65535 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=16 +CONFIG_LWIP_TCP_SACK_OUT=y # HTTP server CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 |
