blob: bb6465d75573d6e4bf7adeb3ddefc1e091d74b1a [file] [log] [blame]
/*
* 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_