/* * Copyright (c) 2012 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_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_ #define MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_ #include #include #include #include #include #include #include "api/function_view.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" namespace webrtc { class Clock; class RtpPacketToSend; class RtpPacketHistory { public: enum class StorageMode { kDisabled, // Don't store any packets. kStoreAndCull // Store up to `number_to_store` packets, but try to remove // packets as they time out or as signaled as received. }; // Maximum number of packets we ever allow in the history. static constexpr size_t kMaxCapacity = 9600; // Maximum number of entries in prioritized queue of padding packets. static constexpr size_t kMaxPaddingHistory = 63; // Don't remove packets within max(1 second, 3x RTT). static constexpr TimeDelta kMinPacketDuration = TimeDelta::Seconds(1); static constexpr int kMinPacketDurationRtt = 3; // With kStoreAndCull, always remove packets after 3x max(1000ms, 3x rtt). static constexpr int kPacketCullingDelayFactor = 3; RtpPacketHistory(Clock* clock, bool enable_padding_prio); RtpPacketHistory() = delete; RtpPacketHistory(const RtpPacketHistory&) = delete; RtpPacketHistory& operator=(const RtpPacketHistory&) = delete; ~RtpPacketHistory(); // Set/get storage mode. Note that setting the state will clear the history, // even if setting the same state as is currently used. void SetStorePacketsStatus(StorageMode mode, size_t number_to_store); StorageMode GetStorageMode() const; // Set RTT, used to avoid premature retransmission and to prevent over-writing // a packet in the history before we are reasonably sure it has been received. void SetRtt(TimeDelta rtt); void PutRtpPacket(std::unique_ptr packet, Timestamp send_time); // Gets stored RTP packet corresponding to the input |sequence number|. // Returns nullptr if packet is not found or was (re)sent too recently. // If a packet copy is returned, it will be marked as pending transmission but // does not update send time, that must be done by MarkPacketAsSent(). std::unique_ptr GetPacketAndMarkAsPending( uint16_t sequence_number); // In addition to getting packet and marking as sent, this method takes an // encapsulator function that takes a reference to the packet and outputs a // copy that may be wrapped in a container, eg RTX. // If the the encapsulator returns nullptr, the retransmit is aborted and the // packet will not be marked as pending. std::unique_ptr GetPacketAndMarkAsPending( uint16_t sequence_number, rtc::FunctionView( const RtpPacketToSend&)> encapsulate); // Updates the send time for the given packet and increments the transmission // counter. Marks the packet as no longer being in the pacer queue. void MarkPacketAsSent(uint16_t sequence_number); // Returns true if history contains packet with `sequence_number` and it can // be retransmitted. bool GetPacketState(uint16_t sequence_number) const; // Get the packet (if any) from the history, that is deemed most likely to // the remote side. This is calculated from heuristics such as packet age // and times retransmitted. Updated the send time of the packet, so is not // a const method. std::unique_ptr GetPayloadPaddingPacket(); // Same as GetPayloadPaddingPacket(void), but adds an encapsulation // that can be used for instance to encapsulate the packet in an RTX // container, or to abort getting the packet if the function returns // nullptr. std::unique_ptr GetPayloadPaddingPacket( rtc::FunctionView( const RtpPacketToSend&)> encapsulate); // Cull packets that have been acknowledged as received by the remote end. void CullAcknowledgedPackets(rtc::ArrayView sequence_numbers); // Remove all pending packets from the history, but keep storage mode and // capacity. void Clear(); private: struct MoreUseful; class StoredPacket; using PacketPrioritySet = std::set; class StoredPacket { public: StoredPacket() = default; StoredPacket(std::unique_ptr packet, Timestamp send_time, uint64_t insert_order); StoredPacket(StoredPacket&&); StoredPacket& operator=(StoredPacket&&); ~StoredPacket(); uint64_t insert_order() const { return insert_order_; } size_t times_retransmitted() const { return times_retransmitted_; } void IncrementTimesRetransmitted(PacketPrioritySet* priority_set); // The time of last transmission, including retransmissions. Timestamp send_time() const { return send_time_; } void set_send_time(Timestamp value) { send_time_ = value; } // The actual packet. std::unique_ptr packet_; // True if the packet is currently in the pacer queue pending transmission. bool pending_transmission_; private: Timestamp send_time_ = Timestamp::Zero(); // Unique number per StoredPacket, incremented by one for each added // packet. Used to sort on insert order. uint64_t insert_order_; // Number of times RE-transmitted, ie excluding the first transmission. size_t times_retransmitted_; }; struct MoreUseful { bool operator()(StoredPacket* lhs, StoredPacket* rhs) const; }; // Helper method to check if packet has too recently been sent. bool VerifyRtt(const StoredPacket& packet) const RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); void Reset() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); void CullOldPackets() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); // Removes the packet from the history, and context/mapping that has been // stored. Returns the RTP packet instance contained within the StoredPacket. std::unique_ptr RemovePacket(int packet_index) RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); int GetPacketIndex(uint16_t sequence_number) const RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); StoredPacket* GetStoredPacket(uint16_t sequence_number) RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_); Clock* const clock_; const bool enable_padding_prio_; mutable Mutex lock_; size_t number_to_store_ RTC_GUARDED_BY(lock_); StorageMode mode_ RTC_GUARDED_BY(lock_); TimeDelta rtt_ RTC_GUARDED_BY(lock_); // Queue of stored packets, ordered by sequence number, with older packets in // the front and new packets being added to the back. Note that there may be // wrap-arounds so the back may have a lower sequence number. // Packets may also be removed out-of-order, in which case there will be // instances of StoredPacket with `packet_` set to nullptr. The first and last // entry in the queue will however always be populated. std::deque packet_history_ RTC_GUARDED_BY(lock_); // Total number of packets with inserted. uint64_t packets_inserted_ RTC_GUARDED_BY(lock_); // Objects from `packet_history_` ordered by "most likely to be useful", used // in GetPayloadPaddingPacket(). PacketPrioritySet padding_priority_ RTC_GUARDED_BY(lock_); }; } // namespace webrtc #endif // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_