1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
// Raw-TCP frame ingestion server. Replaces the per-frame HTTP /frame
// POST loop with a single long-lived TCP connection that streams
// length+seq prefixed JPEGs back-to-back. Eliminates per-frame TCP
// setup, HTTP parsing, and the 200ms Nagle/delayed-ACK deadlocks
// that intermittently spiked the HTTP path to ~250ms wall.
//
// Wire protocol — one connection, repeating; all integers big-endian.
// Two formats are accepted on every connection:
//
// v1 (16-byte header, current):
// [u32 magic = 0x56505254 "VPRT"]
// [u32 jpeg_len]
// [u32 seq]
// [u32 event_us_low] low 32 bits of Scrypted-host monotonic µs
// at camera-event arrival; firmware passes
// this through verbatim to /state so the
// script can compute glass-to-glass.
// [jpeg_len bytes: JPEG body]
//
// v0 (8-byte header, legacy):
// [u32 jpeg_len]
// [u32 seq]
// [jpeg_len bytes: JPEG body]
//
// We sniff the first 4 bytes: if they spell "VPRT" the connection is
// v1, otherwise we interpret bytes 0-3 as jpeg_len (v0) and continue.
// The v0 path will be removed once all Scrypted scripts in the field
// have rolled forward.
//
// One client at a time. New client = previous client's seq counter
// is reset (so each stream session starts fresh, and stale frames
// from a previous reconnect can't paint over current ones).
esp_err_t stream_server_start(uint16_t port);
// Snapshot of the most recent 30-frame window plus the latest
// painted frame's pass-through event timestamp. Locking is internal
// to stream_server — the caller just reads. All durations in
// microseconds. Fields are zero before the first window rolls.
typedef struct {
uint64_t frames; // count of painted frames in the window
uint64_t bytes; // total body bytes received in the window
uint64_t window_us; // wall-clock span of the window
uint64_t window_end_us; // esp_timer_get_time() at window roll
uint32_t recv_min_us, recv_avg_us, recv_max_us;
uint32_t dec_min_us, dec_avg_us, dec_max_us;
uint32_t pnt_min_us, pnt_avg_us, pnt_max_us;
uint32_t idle_min_us, idle_avg_us, idle_max_us;
uint32_t last_paint_event_us_low; // last v1 frame's event_us_low,
// 0 if none seen yet on this
// boot or last frame was v0
} stream_server_stats_t;
void stream_server_snapshot_stats(stream_server_stats_t *out);
|