ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
rtsp_session.h
Go to the documentation of this file.
1#pragma once
2
4
5#ifdef USE_CAMERA
6
7#include <array>
8#include <memory>
9
13
14namespace esphome::rtsp_server {
15
16static constexpr size_t INTERLEAVED_HEADER_LEN = 4;
17static constexpr size_t RTP_HEADER_LEN = 12;
18static constexpr size_t JPEG_HEADER_LEN = 8;
19static constexpr size_t QUANT_HEADER_LEN = 4;
20static constexpr size_t QTABLE_LEN = 64; // one 8-bit precision quantization table
21static constexpr size_t RTP_JPEG_PAYLOAD_SIZE = 1024;
22static constexpr size_t MAX_PACKET_SIZE = INTERLEAVED_HEADER_LEN + RTP_HEADER_LEN + JPEG_HEADER_LEN + QUANT_HEADER_LEN +
23 2 * QTABLE_LEN + RTP_JPEG_PAYLOAD_SIZE;
24// RFC 2435 stores width and height in units of 8 pixels in one byte each.
25static constexpr uint16_t RTP_JPEG_MAX_DIMENSION = 255 * 8;
26// A frame whose packets make no write progress for this long is dropped, so a stalled client cannot hold
27// the camera image (esp32_camera captures nothing while any copy is held).
28static constexpr uint32_t FRAME_STALL_MS = 500;
29
31struct JpegInfo {
32 const uint8_t *qtable0{nullptr};
33 const uint8_t *qtable1{nullptr}; // same as qtable0 when the frame has one table
34 const uint8_t *scan_data{nullptr};
35 size_t scan_len{0}; // entropy-coded data, without the trailing EOI marker
36 uint16_t width{0};
37 uint16_t height{0};
38 uint8_t type{0}; // RFC 2435 type: 0 = 4:2:2 subsampling, 1 = 4:2:0
39};
40
41bool parse_jpeg_info(const uint8_t *data, size_t len, JpegInfo &out);
42
48 public:
49 bool is_active() const { return this->socket_ != nullptr; }
50 bool is_playing() const { return this->state_ == State::PLAYING; }
51
52 void open(std::unique_ptr<socket::Socket> socket, uint32_t now);
53 void loop(uint32_t now, uint16_t port);
55 void on_new_frame(const std::shared_ptr<camera::CameraImage> &image, const JpegInfo &jpeg, uint32_t now);
56
57 protected:
58 enum class State : uint8_t { INIT, READY, PLAYING };
59
60 void service_(uint32_t now, uint16_t port);
61 void close_();
62 void read_requests_(uint32_t now, uint16_t port);
64 bool process_input_(uint16_t port);
65 void consume_input_(size_t len);
66 void handle_request_(StringRef request, uint16_t port);
67 void handle_setup_(StringRef transport_header);
68 void handle_play_();
70 void queue_response_(uint16_t code, const char *reason, const char *extra_headers_fmt = nullptr, ...)
71 __attribute__((format(printf, 4, 5)));
72 void stop_playing_();
73 bool queue_next_packet_();
75 void drop_frame_();
77 bool flush_(uint32_t now);
78
79 std::unique_ptr<socket::Socket> socket_;
80 // Held until its last packet is written; esp32_camera captures nothing new while any copy is held.
81 std::shared_ptr<camera::CameraImage> frame_;
83 size_t frame_sent_{0};
84
91 // Bytes of an interleaved packet (RTCP) or request body from the client still to discard.
93 uint16_t sequence_number_{0};
94 uint16_t request_len_{0};
95 // Zeros still owed for a packet whose frame was dropped part way through.
96 uint16_t filler_len_{0};
97
98 // Pending output: a response or one RTP packet. Packets point at the frame's tables and scan data.
99 std::array<struct iovec, 4> iov_{};
100 uint8_t iov_pos_{0};
101 uint8_t iov_count_{0};
102
104 bool should_close_{false};
105 bool close_after_send_{false};
106 bool sending_packet_{false}; // iov_ holds an RTP packet rather than a response
107 bool read_pending_{false}; // reading stopped before EAGAIN; read again without waiting for ready()
108 char session_id_[9]{};
109
110 // Requests and interleaved packets from the client. A request is NUL terminated in place before it is
111 // handled, for StringRef::find(), which uses strstr.
112 std::array<char, 512> request_buf_{};
113 // Response text, or the header of the RTP packet being sent.
114 std::array<char, 256> send_buf_{};
115};
116
117} // namespace esphome::rtsp_server
118
119#endif
StringRef is a reference to a string owned by something else.
Definition string_ref.h:31
A single RTSP client: one TCP connection carrying both the RTSP control channel and,...
void drop_frame_()
Releases the frame; the frame-backed rest of the current packet is sent as zeros to keep the framing.
bool flush_(uint32_t now)
Writes what is queued; true once all of it is written, false while backlogged or after a failure.
void service_(uint32_t now, uint16_t port)
std::unique_ptr< socket::Socket > socket_
std::array< char, 512 > request_buf_
void handle_setup_(StringRef transport_header)
std::array< char, 256 > send_buf_
std::shared_ptr< camera::CameraImage > frame_
void read_requests_(uint32_t now, uint16_t port)
std::array< struct iovec, 4 > iov_
void open(std::unique_ptr< socket::Socket > socket, uint32_t now)
bool process_input_(uint16_t port)
Consumes buffered input up to and including the next request; true once a request was handled.
void handle_request_(StringRef request, uint16_t port)
void queue_response_(uint16_t code, const char *reason, const char *extra_headers_fmt=nullptr,...) __attribute__((format(printf
Queues "RTSP/1.0 <code> <reason>", CSeq, Session once set up, the extra headers and the blank line.
void on_new_frame(const std::shared_ptr< camera::CameraImage > &image, const JpegInfo &jpeg, uint32_t now)
Ignored unless playing with no output pending; packets of the frame being sent point into that frame.
std::vector< uint8_t > & out
Definition gif.cpp:49
void loop()
const char * format
bool parse_jpeg_info(const uint8_t *data, size_t len, JpegInfo &out)
Scans JPEG marker segments (SOF0/1, DQT, SOS) for the dimensions, quantization tables and the start o...
const void size_t len
Definition hal.h:68
STL namespace.
static void uint32_t
The fields of a JPEG frame that an RFC 2435 RTP/JPEG payload needs. Pointers refer into the frame.