diff options
Diffstat (limited to 'third_party/libwebrtc/modules/rtp_rtcp/source/packet_sequencer.cc')
-rw-r--r-- | third_party/libwebrtc/modules/rtp_rtcp/source/packet_sequencer.cc | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/packet_sequencer.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/packet_sequencer.cc new file mode 100644 index 0000000000..55edd768a8 --- /dev/null +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/packet_sequencer.cc @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2021 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. + */ + +#include "modules/rtp_rtcp/source/packet_sequencer.h" + +#include "rtc_base/checks.h" +#include "rtc_base/random.h" + +namespace webrtc { + +namespace { +// RED header is first byte of payload, if present. +constexpr size_t kRedForFecHeaderLength = 1; + +// Timestamps use a 90kHz clock. +constexpr uint32_t kTimestampTicksPerMs = 90; +} // namespace + +PacketSequencer::PacketSequencer(uint32_t media_ssrc, + absl::optional<uint32_t> rtx_ssrc, + bool require_marker_before_media_padding, + Clock* clock) + : media_ssrc_(media_ssrc), + rtx_ssrc_(rtx_ssrc), + require_marker_before_media_padding_(require_marker_before_media_padding), + clock_(clock), + media_sequence_number_(0), + rtx_sequence_number_(0), + last_payload_type_(-1), + last_rtp_timestamp_(0), + last_capture_time_ms_(0), + last_timestamp_time_ms_(0), + last_packet_marker_bit_(false) { + Random random(clock_->TimeInMicroseconds()); + // Random start, 16 bits. Upper half of range is avoided in order to prevent + // wraparound issues during startup. Sequence number 0 is avoided for + // historical reasons, presumably to avoid debugability or test usage + // conflicts. + constexpr uint16_t kMaxInitRtpSeqNumber = 0x7fff; // 2^15 - 1. + media_sequence_number_ = random.Rand(1, kMaxInitRtpSeqNumber); + rtx_sequence_number_ = random.Rand(1, kMaxInitRtpSeqNumber); +} + +void PacketSequencer::Sequence(RtpPacketToSend& packet) { + if (packet.Ssrc() == media_ssrc_) { + if (packet.packet_type() == RtpPacketMediaType::kRetransmission) { + // Retransmission of an already sequenced packet, ignore. + return; + } else if (packet.packet_type() == RtpPacketMediaType::kPadding) { + PopulatePaddingFields(packet); + } + packet.SetSequenceNumber(media_sequence_number_++); + if (packet.packet_type() != RtpPacketMediaType::kPadding) { + UpdateLastPacketState(packet); + } + } else if (packet.Ssrc() == rtx_ssrc_) { + if (packet.packet_type() == RtpPacketMediaType::kPadding) { + PopulatePaddingFields(packet); + } + packet.SetSequenceNumber(rtx_sequence_number_++); + } else { + RTC_DCHECK_NOTREACHED() << "Unexpected ssrc " << packet.Ssrc(); + } +} + +void PacketSequencer::SetRtpState(const RtpState& state) { + media_sequence_number_ = state.sequence_number; + last_rtp_timestamp_ = state.timestamp; + last_capture_time_ms_ = state.capture_time_ms; + last_timestamp_time_ms_ = state.last_timestamp_time_ms; +} + +void PacketSequencer::PopulateRtpState(RtpState& state) const { + state.sequence_number = media_sequence_number_; + state.timestamp = last_rtp_timestamp_; + state.capture_time_ms = last_capture_time_ms_; + state.last_timestamp_time_ms = last_timestamp_time_ms_; +} + +void PacketSequencer::UpdateLastPacketState(const RtpPacketToSend& packet) { + // Remember marker bit to determine if padding can be inserted with + // sequence number following `packet`. + last_packet_marker_bit_ = packet.Marker(); + // Remember media payload type to use in the padding packet if rtx is + // disabled. + if (packet.is_red()) { + RTC_DCHECK_GE(packet.payload_size(), kRedForFecHeaderLength); + last_payload_type_ = packet.PayloadBuffer()[0]; + } else { + last_payload_type_ = packet.PayloadType(); + } + // Save timestamps to generate timestamp field and extensions for the padding. + last_rtp_timestamp_ = packet.Timestamp(); + last_timestamp_time_ms_ = clock_->TimeInMilliseconds(); + last_capture_time_ms_ = packet.capture_time().ms(); +} + +void PacketSequencer::PopulatePaddingFields(RtpPacketToSend& packet) { + if (packet.Ssrc() == media_ssrc_) { + RTC_DCHECK(CanSendPaddingOnMediaSsrc()); + + packet.SetTimestamp(last_rtp_timestamp_); + packet.set_capture_time(Timestamp::Millis(last_capture_time_ms_)); + packet.SetPayloadType(last_payload_type_); + return; + } + + RTC_DCHECK(packet.Ssrc() == rtx_ssrc_); + if (packet.payload_size() > 0) { + // This is payload padding packet, don't update timestamp fields. + return; + } + + packet.SetTimestamp(last_rtp_timestamp_); + packet.set_capture_time(Timestamp::Millis(last_capture_time_ms_)); + + // Only change the timestamp of padding packets sent over RTX. + // Padding only packets over RTP has to be sent as part of a media + // frame (and therefore the same timestamp). + int64_t now_ms = clock_->TimeInMilliseconds(); + if (last_timestamp_time_ms_ > 0) { + packet.SetTimestamp(packet.Timestamp() + + (now_ms - last_timestamp_time_ms_) * + kTimestampTicksPerMs); + if (packet.capture_time() > Timestamp::Zero()) { + packet.set_capture_time( + packet.capture_time() + + TimeDelta::Millis(now_ms - last_timestamp_time_ms_)); + } + } +} + +bool PacketSequencer::CanSendPaddingOnMediaSsrc() const { + if (last_payload_type_ == -1) { + return false; + } + + // Without RTX we can't send padding in the middle of frames. + // For audio marker bits doesn't mark the end of a frame and frames + // are usually a single packet, so for now we don't apply this rule + // for audio. + if (require_marker_before_media_padding_ && !last_packet_marker_bit_) { + return false; + } + + return true; +} + +} // namespace webrtc |