| /* | 
 |  *  Copyright (c) 2022 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_PACING_PRIORITIZED_PACKET_QUEUE_H_ | 
 | #define MODULES_PACING_PRIORITIZED_PACKET_QUEUE_H_ | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include <array> | 
 | #include <cstdint> | 
 | #include <deque> | 
 | #include <list> | 
 | #include <memory> | 
 | #include <unordered_map> | 
 |  | 
 | #include "absl/container/inlined_vector.h" | 
 | #include "api/units/data_size.h" | 
 | #include "api/units/time_delta.h" | 
 | #include "api/units/timestamp.h" | 
 | #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" | 
 | #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | // Describes how long time a packet may stay in the queue before being dropped. | 
 | struct PacketQueueTTL { | 
 |   TimeDelta audio_retransmission = TimeDelta::PlusInfinity(); | 
 |   TimeDelta video_retransmission = TimeDelta::PlusInfinity(); | 
 |   TimeDelta video = TimeDelta::PlusInfinity(); | 
 | }; | 
 |  | 
 | class PrioritizedPacketQueue { | 
 |  public: | 
 |   explicit PrioritizedPacketQueue( | 
 |       Timestamp creation_time, | 
 |       bool prioritize_audio_retransmission = false, | 
 |       PacketQueueTTL packet_queue_ttl = PacketQueueTTL()); | 
 |   PrioritizedPacketQueue(const PrioritizedPacketQueue&) = delete; | 
 |   PrioritizedPacketQueue& operator=(const PrioritizedPacketQueue&) = delete; | 
 |  | 
 |   // Add a packet to the queue. The enqueue time is used for queue time stats | 
 |   // and to report the leading packet enqueue time per packet type. | 
 |   void Push(Timestamp enqueue_time, std::unique_ptr<RtpPacketToSend> packet); | 
 |  | 
 |   // Remove the next packet from the queue. Packets a prioritized first | 
 |   // according to packet type, in the following order: | 
 |   // - audio, retransmissions, video / fec, padding | 
 |   // For each packet type, we use one FIFO-queue per SSRC and emit from | 
 |   // those queues in a round-robin fashion. | 
 |   std::unique_ptr<RtpPacketToSend> Pop(); | 
 |  | 
 |   // Number of packets in the queue. | 
 |   int SizeInPackets() const; | 
 |  | 
 |   // Sum of all payload bytes in the queue, where the payload is calculated | 
 |   // as `packet->payload_size() + packet->padding_size()`. | 
 |   DataSize SizeInPayloadBytes() const; | 
 |  | 
 |   // Convenience method for `SizeInPackets() == 0`. | 
 |   bool Empty() const; | 
 |  | 
 |   // Total packets in the queue per media type (RtpPacketMediaType values are | 
 |   // used as lookup index). | 
 |   const std::array<int, kNumMediaTypes>& SizeInPacketsPerRtpPacketMediaType() | 
 |       const; | 
 |  | 
 |   // The enqueue time of the next packet this queue will return via the Pop() | 
 |   // method, for the given packet type. If queue has no packets, of that type, | 
 |   // returns Timestamp::MinusInfinity(). | 
 |   Timestamp LeadingPacketEnqueueTime(RtpPacketMediaType type) const; | 
 |   Timestamp LeadingPacketEnqueueTimeForRetransmission() const; | 
 |  | 
 |   // Enqueue time of the oldest packet in the queue, | 
 |   // Timestamp::MinusInfinity() if queue is empty. | 
 |   Timestamp OldestEnqueueTime() const; | 
 |  | 
 |   // Average queue time for the packets currently in the queue. | 
 |   // The queuing time is calculated from Push() to the last UpdateQueueTime() | 
 |   // call - with any time spent in a paused state subtracted. | 
 |   // Returns TimeDelta::Zero() for an empty queue. | 
 |   TimeDelta AverageQueueTime() const; | 
 |  | 
 |   // Called during packet processing or when pause stats changes. Since the | 
 |   // AverageQueueTime() method does not look at the wall time, this method | 
 |   // needs to be called before querying queue time. | 
 |   void UpdateAverageQueueTime(Timestamp now); | 
 |  | 
 |   // Set the pause state, while `paused` is true queuing time is not counted. | 
 |   void SetPauseState(bool paused, Timestamp now); | 
 |  | 
 |   // Remove any packets matching the given SSRC. | 
 |   void RemovePacketsForSsrc(uint32_t ssrc); | 
 |  | 
 |   // Checks if the queue for the given SSRC has original (retransmissions not | 
 |   // counted) video packets containing keyframe data. | 
 |   bool HasKeyframePackets(uint32_t ssrc) const; | 
 |  | 
 |  private: | 
 |   static constexpr int kNumPriorityLevels = 5; | 
 |  | 
 |   class QueuedPacket { | 
 |    public: | 
 |     DataSize PacketSize() const; | 
 |  | 
 |     std::unique_ptr<RtpPacketToSend> packet; | 
 |     Timestamp enqueue_time; | 
 |     std::list<Timestamp>::iterator enqueue_time_iterator; | 
 |   }; | 
 |  | 
 |   // Class containing packets for an RTP stream. | 
 |   // For each priority level, packets are simply stored in a fifo queue. | 
 |   class StreamQueue { | 
 |    public: | 
 |     explicit StreamQueue(Timestamp creation_time); | 
 |     StreamQueue(StreamQueue&&) = default; | 
 |     StreamQueue& operator=(StreamQueue&&) = default; | 
 |  | 
 |     StreamQueue(const StreamQueue&) = delete; | 
 |     StreamQueue& operator=(const StreamQueue&) = delete; | 
 |  | 
 |     // Enqueue packet at the given priority level. Returns true if the packet | 
 |     // count for that priority level went from zero to non-zero. | 
 |     bool EnqueuePacket(QueuedPacket packet, int priority_level); | 
 |  | 
 |     QueuedPacket DequeuePacket(int priority_level); | 
 |  | 
 |     bool HasPacketsAtPrio(int priority_level) const; | 
 |     bool IsEmpty() const; | 
 |     Timestamp LeadingPacketEnqueueTime(int priority_level) const; | 
 |     Timestamp LastEnqueueTime() const; | 
 |     bool has_keyframe_packets() const { return num_keyframe_packets_ > 0; } | 
 |  | 
 |     std::array<std::deque<QueuedPacket>, kNumPriorityLevels> DequeueAll(); | 
 |  | 
 |    private: | 
 |     std::deque<QueuedPacket> packets_[kNumPriorityLevels]; | 
 |     Timestamp last_enqueue_time_; | 
 |     int num_keyframe_packets_; | 
 |   }; | 
 |  | 
 |   // Remove the packet from the internal state, e.g. queue time / size etc. | 
 |   void DequeuePacketInternal(QueuedPacket& packet); | 
 |  | 
 |   // Check if the queue pointed to by `top_active_prio_level_` is empty and | 
 |   // if so move it to the lowest non-empty index. | 
 |   void MaybeUpdateTopPrioLevel(); | 
 |  | 
 |   void PurgeOldPacketsAtPriorityLevel(int prio_level, Timestamp now); | 
 |  | 
 |   static absl::InlinedVector<TimeDelta, kNumPriorityLevels> ToTtlPerPrio( | 
 |       PacketQueueTTL); | 
 |  | 
 |   const bool prioritize_audio_retransmission_; | 
 |   const absl::InlinedVector<TimeDelta, kNumPriorityLevels> | 
 |       time_to_live_per_prio_; | 
 |  | 
 |   // Cumulative sum, over all packets, of time spent in the queue. | 
 |   TimeDelta queue_time_sum_; | 
 |   // Cumulative sum of time the queue has spent in a paused state. | 
 |   TimeDelta pause_time_sum_; | 
 |   // Total number of packets stored in this queue. | 
 |   int size_packets_; | 
 |   // Total number of packets stored in this queue per RtpPacketMediaType. | 
 |   std::array<int, kNumMediaTypes> size_packets_per_media_type_; | 
 |   // Sum of payload sizes for all packts stored in this queue. | 
 |   DataSize size_payload_; | 
 |   // The last time queue/pause time sums were updated. | 
 |   Timestamp last_update_time_; | 
 |   bool paused_; | 
 |  | 
 |   // Last time `streams_` was culled for inactive streams. | 
 |   Timestamp last_culling_time_; | 
 |  | 
 |   // Map from SSRC to packet queues for the associated RTP stream. | 
 |   std::unordered_map<uint32_t, std::unique_ptr<StreamQueue>> streams_; | 
 |  | 
 |   // For each priority level, a queue of StreamQueues which have at least one | 
 |   // packet pending for that prio level. | 
 |   std::deque<StreamQueue*> streams_by_prio_[kNumPriorityLevels]; | 
 |  | 
 |   // The first index into `stream_by_prio_` that is non-empty. | 
 |   int top_active_prio_level_; | 
 |  | 
 |   // Ordered list of enqueue times. Additions are always increasing and added to | 
 |   // the end. QueuedPacket instances have a iterators into this list for fast | 
 |   // removal. | 
 |   std::list<Timestamp> enqueue_times_; | 
 | }; | 
 |  | 
 | }  // namespace webrtc | 
 |  | 
 | #endif  // MODULES_PACING_PRIORITIZED_PACKET_QUEUE_H_ |