| /* | 
 |  *  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<uint32_t>(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 |