/* * Copyright (c) 2026 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #ifndef MODULES_VIDEO_CODING_SFRAME_PACKET_BUFFER_H_ #define MODULES_VIDEO_CODING_SFRAME_PACKET_BUFFER_H_ #include #include #include #include #include #include #include #include "absl/strings/string_view.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" #include "modules/rtp_rtcp/source/sframe_descriptor.h" #include "modules/rtp_rtcp/source/sframe_rtp_packet_received.h" #include "rtc_base/numerics/sequence_number_unwrapper.h" namespace webrtc { // Buffers incoming SFrame RTP packets and validates complete S->E runs. // // Implements the receiver-side validation from // draft-ietf-avtcore-rtp-sframe section 5.2: // 1. Add each packet to the set. // 2. Find the smallest consecutive S=1->E=1 run. // 3. Validate T-bits are identical, PTs are identical. // 4. Return the validated packets + metadata. // // Uses a circular buffer indexed by (seq_num % buffer_size), similar to // PacketBuffer, to avoid per-packet heap allocations. // // Descriptor stripping, payload assembly, and decryption are handled // downstream by the packet transformer. // This buffer sits before SFrame decryption and before the codec depacketizer. class SFramePacketBuffer { public: // Outcome of InsertPacket() when no frame was assembled. enum class InsertResult { // Packet was buffered but no complete frame yet. kNoFrame, // Buffer was full and had to be cleared. Caller should request a // keyframe. Any partially assembled state is discarded. kBufferCleared, }; struct AssembledFrame { // Encryption granularity from the SFrame descriptor T bit. SframeEncryptionLevel encryption_level = SframeEncryptionLevel::kFrame; // The RTP packets forming the validated S->E run, in sequence-number // order. std::vector> packets; }; explicit SFramePacketBuffer(size_t buffer_size = 2048); ~SFramePacketBuffer(); // Insert an SFrame-depacketized RTP packet (descriptor already parsed and // stripped). If this packet completes an S->E run, returns an // AssembledFrame. Otherwise returns an InsertResult status. std::variant InsertPacket( std::unique_ptr packet); // Discard all packets up to and including `seq_num`. void ClearTo(uint16_t seq_num); // Clear all buffered state. void Clear(); private: // Check whether the newly inserted packet at `seq_num` completes an S->E // run. Walks backward from `seq_num` to find S=1, then forward to find E=1. std::optional FindFrame(int64_t seq_num); // Walk backward from `seq_num` to find the S=1 packet (start of frame). std::optional FindFrameStart(int64_t seq_num); // Walk forward from `seq_num` to find the E=1 packet (end of frame). std::optional FindFrameEnd(int64_t seq_num, int64_t start); // Validate the S->E run, extract packets, and remove them from the buffer. std::optional AssembleFrame(int64_t start, int64_t end); // Clear all packets in [start, end] on validation failure and log `reason`. void DropFrame(absl::string_view reason, uint16_t bad_seq, int64_t start, int64_t end); // Update first_seq_num_ to track the lowest sequence number in the window. // Returns false if the packet is too old to fit in the buffer. bool UpdateWindowStart(int64_t seq_num); // Outcome of ResolveSlot: found an available slot, detected a duplicate // packet, or ran out of buffer space. enum class SlotOutcome { kOk, kDuplicate, kFull }; // Resolve the buffer slot for `seq_num`. Returns the outcome and the // slot index (only valid when kOk). Does NOT clear the buffer on // overflow — the caller decides how to handle that. std::pair ResolveSlot(int64_t seq_num); size_t ToIdx(int64_t seq_num) const { return static_cast(seq_num) % buffer_.size(); } // Circular buffer indexed by ToIdx(unwrapped_seq_num). std::vector> buffer_; std::optional first_seq_num_; // True after ClearTo() has been called. Prevents UpdateWindowStart from // moving first_seq_num_ backward past the cleared point. bool is_cleared_to_first_seq_num_ = false; // Unwraps uint16_t RTP sequence numbers to monotonic int64_t values. SeqNumUnwrapper seq_num_unwrapper_; }; } // namespace webrtc #endif // MODULES_VIDEO_CODING_SFRAME_PACKET_BUFFER_H_