src.nth.io/

summaryrefslogtreecommitdiff
path: root/main/app_main.c
diff options
context:
space:
mode:
authorLuke Hoersten <[email protected]>2026-06-19 19:59:14 -0500
committerLuke Hoersten <[email protected]>2026-06-19 19:59:14 -0500
commitb97c2502b74277f9ea9dace97e8188201d5570fb (patch)
tree5a36c4f3f06ae3e310da5d42e3df84e989e91e3b /main/app_main.c
parentc89f832eb2c10f007ecf000165625c9953216a82 (diff)
streaming pivot: raw TCP data plane, drop per-frame HTTP entirely
Replaces the per-frame HTTP POST loop with a single long-lived TCP connection on port 81. The HTTP control plane (/state, /config, /frame for snapshot) stays unchanged. Wire protocol (big-endian, repeating until connection close): [4 bytes jpeg_len][4 bytes seq][jpeg_len bytes JPEG] Why --- The HTTP path hit a measured floor of ~37ms p50 with intermittent ~230ms p95 spikes that survived every Nagle/keep-alive fix attempt. Each frame paid: TCP setup (or pool churn), HTTP parsing, body recv, decode, paint, response write, response ACK. Streaming removes everything except recv + decode + paint. Firmware (main/stream_server.[ch], new) --------------------------------------- - TCP listen on configurable port (81) in its own FreeRTOS task, one client at a time (matches the one-stream-per-device model). - Per accepted socket: TCP_NODELAY on, then loop reading 8-byte header → jpeg body → through the existing jpeg_decoder + display paths. Same stale-seq guard as the HTTP /frame handler (reset per connection so each session starts at seq 1). - Frames received while asleep are still drained (to stay framed) but not painted. The HTTP control-plane POST /state {wake} resumes painting on the next frame. - Every 30 painted frames a structured serial log shows per-stage timing + sustained MB/s — replaces the cross-side Server-Timing header (no HTTP response to attach it to anymore). Scrypted side ------------- - net.createConnection({ host, port: 81, noDelay: true }) opened once per stream session. On disconnect/error/close we auto- reconnect after 500ms. - ffmpeg stdout demux writes [header][body] directly to the socket. sock.write() returning false sets a backpressured flag that drops incoming ffmpeg frames until 'drain' fires — natural TCP backpressure handles "firmware can't keep up" without us modeling it manually. - Stripped the entire fetch-based timing infrastructure (pushStreamFrame, fetchSamples, parseServerTiming, depth histogram, Server-Timing parser). Replaced with one stream-shaped log every 10s: fps + MB/s + socket.write p50/p95/max + drop count + backpressured flag. - pushSnapshot (one-shot first-paint) still uses the HTTP /frame endpoint — small and infrequent, not worth reworking. - postJSON still uses node:http for /state and /config. State machine status flags -------------------------- Extended boot-time flags array from 6 → 7 slots so the stream server's bring-up shows up alongside ETH/MDNS/HTTP. Layout is now E M H S D J T (was E M H D J T).
Diffstat (limited to 'main/app_main.c')
-rw-r--r--main/app_main.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/main/app_main.c b/main/app_main.c
index 00a77bb..a6174c8 100644
--- a/main/app_main.c
+++ b/main/app_main.c
@@ -7,6 +7,7 @@
#include "nvs_config.h"
#include "state_client.h"
#include "state_machine.h"
+#include "stream_server.h"
#include "touch.h"
#include "viewport_state.h"
@@ -52,7 +53,7 @@ void app_main(void)
// don't get a DHCP lease. mDNS + HTTP advertise / bind anyway and will
// start serving the moment the link comes up.
// ------------------------------------------------------------------
- char flags[7] = { '-','-','-','-','-','-', 0 }; // E M H D J T
+ char flags[8] = { '-','-','-','-','-','-','-', 0 }; // E M H S D J T
esp_err_t eth_err = net_eth_init();
mark(eth_err, 'E', &flags[0]);
@@ -71,6 +72,10 @@ void app_main(void)
ESP_ERROR_CHECK(state_client_init());
mark(mdns_service_start(), 'M', &flags[1]);
mark(http_api_start(), 'H', &flags[2]);
+ // Data plane: raw TCP on :81 for back-to-back JPEG streaming,
+ // bypassing per-frame HTTP overhead. /frame HTTP stays alive for
+ // the snapshot one-shot and for curl debugging.
+ mark(stream_server_start(81), 'S', &flags[3]);
// ------------------------------------------------------------------
// Display + I²C-bound peripherals run on their own task. ESP-IDF's