webrtc/modules/rtp_rtcp/source/rtp_packet_history.h
Erik Språng 6cacef2402 Reset packet history on ssrc/seqno reset
If the SSRC of an RTP module is changed at runtime, we may get conflicts
with packets already there. Eg:
* Put seq# 123 in the history for SSRC 1.
* Change the SSRC to 2.
* Send a NACK for seq# 123 from SSRC 2.

Currently, we will respond with the packet belonging to SSRC 1 (and not
if the NACK specifies SSRC 1, to boot).

We can gen similar issues if the sequence number is changed, where
half frame are left in the buffer.

In these cases, the stream is likely being reset so we should just
clear the packet history too.

Bug: webrtc:10794
Change-Id: I28147c2532cf1c78840d4808c4366d4a647541f7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/145729
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28658}
2019-07-24 12:52:23 +00:00

218 lines
8.8 KiB
C++

/*
* 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 <map>
#include <memory>
#include <set>
#include <vector>
#include "api/function_view.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/critical_section.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.
};
// Snapshot indicating the state of a packet in the history.
struct PacketState {
PacketState();
PacketState(const PacketState&);
~PacketState();
uint16_t rtp_sequence_number = 0;
absl::optional<int64_t> send_time_ms;
int64_t capture_time_ms = 0;
uint32_t ssrc = 0;
size_t packet_size = 0;
// Number of times RE-transmitted, ie not including the first transmission.
size_t times_retransmitted = 0;
bool pending_transmission = false;
};
// Maximum number of packets we ever allow in the history.
static constexpr size_t kMaxCapacity = 9600;
// Don't remove packets within max(1000ms, 3x RTT).
static constexpr int64_t kMinPacketDurationMs = 1000;
static constexpr int kMinPacketDurationRtt = 3;
// With kStoreAndCull, always remove packets after 3x max(1000ms, 3x rtt).
static constexpr int kPacketCullingDelayFactor = 3;
explicit RtpPacketHistory(Clock* clock);
~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(int64_t rtt_ms);
// If |send_time| is set, packet was sent without using pacer, so state will
// be set accordingly.
void PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet,
StorageType type,
absl::optional<int64_t> send_time_ms);
// Gets stored RTP packet corresponding to the input |sequence number|.
// Returns nullptr if packet is not found or was (re)sent too recently.
std::unique_ptr<RtpPacketToSend> GetPacketAndSetSendTime(
uint16_t sequence_number);
// 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<RtpPacketToSend> 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<RtpPacketToSend> GetPacketAndMarkAsPending(
uint16_t sequence_number,
rtc::FunctionView<std::unique_ptr<RtpPacketToSend>(
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);
// Similar to GetPacketAndSetSendTime(), but only returns a snapshot of the
// current state for packet, and never updates internal state.
absl::optional<PacketState> 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<RtpPacketToSend> 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<RtpPacketToSend> GetPayloadPaddingPacket(
rtc::FunctionView<std::unique_ptr<RtpPacketToSend>(
const RtpPacketToSend&)> encapsulate);
// Cull packets that have been acknowledged as received by the remote end.
void CullAcknowledgedPackets(rtc::ArrayView<const uint16_t> sequence_numbers);
// Mark packet as queued for transmission. This will prevent premature
// removal or duplicate retransmissions in the pacer queue.
// Returns true if status was set, false if packet was not found.
bool SetPendingTransmission(uint16_t sequence_number);
// Remove all pending packets from the history, but keep storage mode and
// capacity.
void Clear();
private:
struct MoreUseful;
class StoredPacket;
using PacketPrioritySet = std::set<StoredPacket*, MoreUseful>;
class StoredPacket {
public:
StoredPacket(std::unique_ptr<RtpPacketToSend> packet,
StorageType storage_type,
absl::optional<int64_t> send_time_ms,
uint64_t insert_order);
StoredPacket(StoredPacket&&);
StoredPacket& operator=(StoredPacket&&);
~StoredPacket();
StorageType storage_type() const { return storage_type_; }
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.
absl::optional<int64_t> send_time_ms_;
// The actual packet.
std::unique_ptr<RtpPacketToSend> packet_;
// True if the packet is currently in the pacer queue pending transmission.
bool pending_transmission_;
private:
// Storing a packet with |storage_type| = kDontRetransmit indicates this is
// only used as temporary storage until sent by the pacer sender.
StorageType storage_type_;
// 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;
};
using StoredPacketIterator = std::map<uint16_t, StoredPacket>::iterator;
// Helper method used by GetPacketAndSetSendTime() and GetPacketState() to
// check if packet has too recently been sent.
bool VerifyRtt(const StoredPacket& packet, int64_t now_ms) const
RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
void Reset() RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
void CullOldPackets(int64_t now_ms) 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<RtpPacketToSend> RemovePacket(StoredPacketIterator packet)
RTC_EXCLUSIVE_LOCKS_REQUIRED(lock_);
static PacketState StoredPacketToPacketState(
const StoredPacket& stored_packet);
Clock* const clock_;
rtc::CriticalSection lock_;
size_t number_to_store_ RTC_GUARDED_BY(lock_);
StorageMode mode_ RTC_GUARDED_BY(lock_);
int64_t rtt_ms_ RTC_GUARDED_BY(lock_);
// Map from rtp sequence numbers to stored packet.
std::map<uint16_t, StoredPacket> packet_history_ RTC_GUARDED_BY(lock_);
// Total number of packets with StorageType::kAllowsRetransmission inserted.
uint64_t retransmittable_packets_inserted_ RTC_GUARDED_BY(lock_);
// Retransmittable objects from |packet_history_| ordered by
// "most likely to be useful", used in GetPayloadPaddingPacket().
PacketPrioritySet padding_priority_ RTC_GUARDED_BY(lock_);
// The earliest packet in the history. This might not be the lowest sequence
// number, in case there is a wraparound.
absl::optional<uint16_t> start_seqno_ RTC_GUARDED_BY(lock_);
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpPacketHistory);
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_RTP_PACKET_HISTORY_H_