/* * 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 "api/units/timestamp.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "system_wrappers/include/clock.h" #include "test/gmock.h" #include "test/gtest.h" namespace webrtc { namespace { constexpr Timestamp kStartTime = Timestamp::Millis(98765); constexpr uint32_t kMediaSsrc = 123456; constexpr uint32_t kRtxSsrc = 123457; constexpr uint8_t kMediaPayloadType = 42; constexpr uint16_t kMediaStartSequenceNumber = 123; constexpr uint16_t kRtxStartSequenceNumber = 234; constexpr uint16_t kDefaultSequenceNumber = 0x1234; constexpr uint32_t kStartRtpTimestamp = 798; class PacketSequencerTest : public ::testing::Test { public: PacketSequencerTest() : clock_(kStartTime), sequencer_(kMediaSsrc, kRtxSsrc, /*require_marker_before_media_padding=*/true, &clock_) {} RtpPacketToSend CreatePacket(RtpPacketMediaType type, uint32_t ssrc) { RtpPacketToSend packet(/*extension_manager=*/nullptr); packet.set_packet_type(type); packet.SetSsrc(ssrc); packet.SetSequenceNumber(kDefaultSequenceNumber); packet.set_capture_time(clock_.CurrentTime()); packet.SetTimestamp( kStartRtpTimestamp + static_cast(packet.capture_time().ms() - kStartTime.ms())); return packet; } protected: SimulatedClock clock_; PacketSequencer sequencer_; }; TEST_F(PacketSequencerTest, IgnoresMediaSsrcRetransmissions) { RtpPacketToSend packet = CreatePacket(RtpPacketMediaType::kRetransmission, kMediaSsrc); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(packet); EXPECT_EQ(packet.SequenceNumber(), kDefaultSequenceNumber); EXPECT_EQ(sequencer_.media_sequence_number(), kMediaStartSequenceNumber); } TEST_F(PacketSequencerTest, SequencesAudio) { RtpPacketToSend packet = CreatePacket(RtpPacketMediaType::kAudio, kMediaSsrc); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(packet); EXPECT_EQ(packet.SequenceNumber(), kMediaStartSequenceNumber); EXPECT_EQ(sequencer_.media_sequence_number(), kMediaStartSequenceNumber + 1); } TEST_F(PacketSequencerTest, SequencesVideo) { RtpPacketToSend packet = CreatePacket(RtpPacketMediaType::kVideo, kMediaSsrc); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(packet); EXPECT_EQ(packet.SequenceNumber(), kMediaStartSequenceNumber); EXPECT_EQ(sequencer_.media_sequence_number(), kMediaStartSequenceNumber + 1); } TEST_F(PacketSequencerTest, SequencesUlpFec) { RtpPacketToSend packet = CreatePacket(RtpPacketMediaType::kForwardErrorCorrection, kMediaSsrc); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(packet); EXPECT_EQ(packet.SequenceNumber(), kMediaStartSequenceNumber); EXPECT_EQ(sequencer_.media_sequence_number(), kMediaStartSequenceNumber + 1); } TEST_F(PacketSequencerTest, SequencesRtxRetransmissions) { RtpPacketToSend packet = CreatePacket(RtpPacketMediaType::kRetransmission, kRtxSsrc); sequencer_.set_rtx_sequence_number(kRtxStartSequenceNumber); sequencer_.Sequence(packet); EXPECT_EQ(packet.SequenceNumber(), kRtxStartSequenceNumber); EXPECT_EQ(sequencer_.rtx_sequence_number(), kRtxStartSequenceNumber + 1); } TEST_F(PacketSequencerTest, ProhibitsPaddingWithinVideoFrame) { // Send a video packet with the marker bit set to false (indicating it is not // the last packet of a frame). RtpPacketToSend media_packet = CreatePacket(RtpPacketMediaType::kVideo, kMediaSsrc); media_packet.SetPayloadType(kMediaPayloadType); media_packet.SetMarker(false); sequencer_.Sequence(media_packet); // Sending padding on the media SSRC should not be allowed at this point. EXPECT_FALSE(sequencer_.CanSendPaddingOnMediaSsrc()); // Send a video packet with marker set to true, padding should be allowed // again. media_packet.SetMarker(true); sequencer_.Sequence(media_packet); EXPECT_TRUE(sequencer_.CanSendPaddingOnMediaSsrc()); } TEST_F(PacketSequencerTest, AllowsPaddingAtAnyTimeIfSoConfigured) { PacketSequencer packet_sequencer( kMediaSsrc, kRtxSsrc, /*require_marker_before_media_padding=*/false, &clock_); // Send an audio packet with the marker bit set to false. RtpPacketToSend media_packet = CreatePacket(RtpPacketMediaType::kAudio, kMediaSsrc); media_packet.SetPayloadType(kMediaPayloadType); media_packet.SetMarker(false); packet_sequencer.Sequence(media_packet); // Sending padding on the media SSRC should be allowed despite no marker bit. EXPECT_TRUE(packet_sequencer.CanSendPaddingOnMediaSsrc()); } TEST_F(PacketSequencerTest, UpdatesPaddingBasedOnLastMediaPacket) { // First send a media packet. RtpPacketToSend media_packet = CreatePacket(RtpPacketMediaType::kVideo, kMediaSsrc); media_packet.SetPayloadType(kMediaPayloadType); media_packet.SetMarker(true); // Advance time so current time doesn't exactly match timestamp. clock_.AdvanceTime(TimeDelta::Millis(5)); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(media_packet); // Next send a padding packet and verify the media packet's timestamps and // payload type is transferred to the padding packet. RtpPacketToSend padding_packet = CreatePacket(RtpPacketMediaType::kPadding, kMediaSsrc); padding_packet.SetPadding(/*padding_size=*/100); sequencer_.Sequence(padding_packet); EXPECT_EQ(padding_packet.SequenceNumber(), kMediaStartSequenceNumber + 1); EXPECT_EQ(padding_packet.PayloadType(), kMediaPayloadType); EXPECT_EQ(padding_packet.Timestamp(), media_packet.Timestamp()); EXPECT_EQ(padding_packet.capture_time(), media_packet.capture_time()); } TEST_F(PacketSequencerTest, UpdatesPaddingBasedOnLastRedPacket) { // First send a media packet. RtpPacketToSend media_packet = CreatePacket(RtpPacketMediaType::kVideo, kMediaSsrc); media_packet.SetPayloadType(kMediaPayloadType); // Simulate a packet with RED encapsulation; media_packet.set_is_red(true); uint8_t* payload_buffer = media_packet.SetPayloadSize(1); payload_buffer[0] = kMediaPayloadType + 1; media_packet.SetMarker(true); // Advance time so current time doesn't exactly match timestamp. clock_.AdvanceTime(TimeDelta::Millis(5)); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(media_packet); // Next send a padding packet and verify the media packet's timestamps and // payload type is transferred to the padding packet. RtpPacketToSend padding_packet = CreatePacket(RtpPacketMediaType::kPadding, kMediaSsrc); padding_packet.SetPadding(100); sequencer_.Sequence(padding_packet); EXPECT_EQ(padding_packet.SequenceNumber(), kMediaStartSequenceNumber + 1); EXPECT_EQ(padding_packet.PayloadType(), kMediaPayloadType + 1); EXPECT_EQ(padding_packet.Timestamp(), media_packet.Timestamp()); EXPECT_EQ(padding_packet.capture_time(), media_packet.capture_time()); } TEST_F(PacketSequencerTest, DoesNotUpdateFieldsOnPayloadPadding) { // First send a media packet. RtpPacketToSend media_packet = CreatePacket(RtpPacketMediaType::kVideo, kMediaSsrc); media_packet.SetPayloadType(kMediaPayloadType); media_packet.SetMarker(true); // Advance time so current time doesn't exactly match timestamp. clock_.AdvanceTime(TimeDelta::Millis(5)); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(media_packet); // Simulate a payload padding packet on the RTX SSRC. RtpPacketToSend padding_packet = CreatePacket(RtpPacketMediaType::kPadding, kRtxSsrc); padding_packet.SetPayloadSize(100); padding_packet.SetPayloadType(kMediaPayloadType + 1); padding_packet.SetTimestamp(kStartRtpTimestamp + 1); padding_packet.set_capture_time(kStartTime + TimeDelta::Millis(1)); sequencer_.set_rtx_sequence_number(kRtxStartSequenceNumber); sequencer_.Sequence(padding_packet); // The sequence number should be updated, but timestamps kept. EXPECT_EQ(padding_packet.SequenceNumber(), kRtxStartSequenceNumber); EXPECT_EQ(padding_packet.PayloadType(), kMediaPayloadType + 1); EXPECT_EQ(padding_packet.Timestamp(), kStartRtpTimestamp + 1); EXPECT_EQ(padding_packet.capture_time(), kStartTime + TimeDelta::Millis(1)); } TEST_F(PacketSequencerTest, UpdatesRtxPaddingBasedOnLastMediaPacket) { constexpr uint32_t kTimestampTicksPerMs = 90; // First send a media packet. RtpPacketToSend media_packet = CreatePacket(RtpPacketMediaType::kVideo, kMediaSsrc); media_packet.SetPayloadType(kMediaPayloadType); media_packet.SetMarker(true); sequencer_.set_media_sequence_number(kMediaStartSequenceNumber); sequencer_.Sequence(media_packet); // Advance time, this time delta will be used to interpolate padding // timestamps. constexpr TimeDelta kTimeDelta = TimeDelta::Millis(10); clock_.AdvanceTime(kTimeDelta); RtpPacketToSend padding_packet = CreatePacket(RtpPacketMediaType::kPadding, kRtxSsrc); padding_packet.SetPadding(100); padding_packet.SetPayloadType(kMediaPayloadType + 1); sequencer_.set_rtx_sequence_number(kRtxStartSequenceNumber); sequencer_.Sequence(padding_packet); // Assigned RTX sequence number, but payload type unchanged in this case. EXPECT_EQ(padding_packet.SequenceNumber(), kRtxStartSequenceNumber); EXPECT_EQ(padding_packet.PayloadType(), kMediaPayloadType + 1); // Timestamps are offset realtive to last media packet. EXPECT_EQ( padding_packet.Timestamp(), media_packet.Timestamp() + (kTimeDelta.ms() * kTimestampTicksPerMs)); EXPECT_EQ(padding_packet.capture_time(), media_packet.capture_time() + kTimeDelta); } } // namespace } // namespace webrtc