| /* |
| * 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 <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/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_ |