Index: webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc |
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc |
index 14bbff781c50bfc3fc4ebff9b43da808043298ac..5a4775959e7b8cdc5232d8440ab02bcfb559a525 100644 |
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc |
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc |
@@ -25,7 +25,9 @@ |
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h" |
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" |
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" |
+#include "webrtc/rtc_base/arraysize.h" |
#include "webrtc/rtc_base/buffer.h" |
+#include "webrtc/rtc_base/ptr_util.h" |
#include "webrtc/rtc_base/rate_limiter.h" |
#include "webrtc/test/field_trial.h" |
#include "webrtc/test/gmock.h" |
@@ -55,6 +57,7 @@ const size_t kMaxPaddingSize = 224u; |
const int kVideoRotationExtensionId = 5; |
const size_t kGenericHeaderLength = 1; |
const uint8_t kPayloadData[] = {47, 11, 32, 93, 89}; |
+const int64_t kDefaultExpectedRetransmissionTimeMs = 125; |
using ::testing::_; |
using ::testing::ElementsAreArray; |
@@ -238,7 +241,8 @@ class RtpSenderTest : public ::testing::TestWithParam<bool> { |
EXPECT_TRUE(rtp_sender_->SendOutgoingData( |
kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData, |
- sizeof(kPayloadData), nullptr, nullptr, nullptr)); |
+ sizeof(kPayloadData), nullptr, nullptr, nullptr, |
+ kDefaultExpectedRetransmissionTimeMs)); |
} |
}; |
@@ -249,15 +253,32 @@ class RtpSenderTestWithoutPacer : public RtpSenderTest { |
void SetUp() override { SetUpRtpSender(false); } |
}; |
+class TestRtpSenderVideo : public RTPSenderVideo { |
+ public: |
+ TestRtpSenderVideo(Clock* clock, |
+ RTPSender* rtp_sender, |
+ FlexfecSender* flexfec_sender) |
+ : RTPSenderVideo(clock, rtp_sender, flexfec_sender) {} |
+ ~TestRtpSenderVideo() override {} |
+ |
+ StorageType GetStorageType(const RTPVideoHeader& header, |
+ int32_t retransmission_settings, |
+ int64_t expected_retransmission_time_ms) { |
+ return RTPSenderVideo::GetStorageType(GetTemporalId(header), |
+ retransmission_settings, |
+ expected_retransmission_time_ms); |
+ } |
+}; |
+ |
class RtpSenderVideoTest : public RtpSenderTest { |
protected: |
void SetUp() override { |
// TODO(pbos): Set up to use pacer. |
SetUpRtpSender(false); |
rtp_sender_video_.reset( |
- new RTPSenderVideo(&fake_clock_, rtp_sender_.get(), nullptr)); |
+ new TestRtpSenderVideo(&fake_clock_, rtp_sender_.get(), nullptr)); |
} |
- std::unique_ptr<RTPSenderVideo> rtp_sender_video_; |
+ std::unique_ptr<TestRtpSenderVideo> rtp_sender_video_; |
}; |
TEST_P(RtpSenderTestWithoutPacer, AllocatePacketSetCsrc) { |
@@ -861,9 +882,9 @@ TEST_P(RtpSenderTestWithoutPacer, SendGenericVideo) { |
uint8_t payload[] = {47, 11, 32, 93, 89}; |
// Send keyframe |
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234, |
- 4321, payload, sizeof(payload), |
- nullptr, nullptr, nullptr)); |
+ ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
+ kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
auto sent_payload = transport_.last_sent_packet().payload(); |
uint8_t generic_header = sent_payload[0]; |
@@ -878,7 +899,7 @@ TEST_P(RtpSenderTestWithoutPacer, SendGenericVideo) { |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload), |
- nullptr, nullptr, nullptr)); |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
sent_payload = transport_.last_sent_packet().payload(); |
generic_header = sent_payload[0]; |
@@ -998,7 +1019,8 @@ TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) { |
video_header.video_timing.flags = TimingFrameFlags::kTriggeredByTimer; |
EXPECT_TRUE(rtp_sender_->SendOutgoingData( |
kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs, kPayloadData, |
- sizeof(kPayloadData), nullptr, &video_header, nullptr)); |
+ sizeof(kPayloadData), nullptr, &video_header, nullptr, |
+ kDefaultExpectedRetransmissionTimeMs)); |
EXPECT_CALL(mock_rtc_event_log_, |
LogRtpHeader(PacketDirection::kOutgoingPacket, _, _, _)) |
@@ -1023,7 +1045,8 @@ TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) { |
video_header.video_timing.flags = TimingFrameFlags::kInvalid; |
EXPECT_TRUE(rtp_sender_->SendOutgoingData( |
kVideoFrameKey, kPayloadType, kTimestamp + 1, kCaptureTimeMs + 1, |
- kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr)); |
+ kPayloadData, sizeof(kPayloadData), nullptr, &video_header, nullptr, |
+ kDefaultExpectedRetransmissionTimeMs)); |
EXPECT_CALL(mock_rtc_event_log_, |
LogRtpHeader(PacketDirection::kOutgoingPacket, _, _, _)) |
@@ -1168,9 +1191,9 @@ TEST_P(RtpSenderTest, FrameCountCallbacks) { |
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, _)) |
.Times(::testing::AtLeast(2)); |
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234, |
- 4321, payload, sizeof(payload), |
- nullptr, nullptr, nullptr)); |
+ ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
+ kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
EXPECT_EQ(1U, callback.num_calls_); |
EXPECT_EQ(ssrc, callback.ssrc_); |
@@ -1179,7 +1202,7 @@ TEST_P(RtpSenderTest, FrameCountCallbacks) { |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload), |
- nullptr, nullptr, nullptr)); |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
EXPECT_EQ(2U, callback.num_calls_); |
EXPECT_EQ(ssrc, callback.ssrc_); |
@@ -1245,7 +1268,7 @@ TEST_P(RtpSenderTest, BitrateCallbacks) { |
for (uint32_t i = 0; i < kNumPackets; ++i) { |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), |
- nullptr, nullptr, nullptr)); |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
fake_clock_.AdvanceTimeMilliseconds(kPacketInterval); |
} |
@@ -1327,8 +1350,8 @@ TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacks) { |
// Send a frame. |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
- kVideoFrameKey, payload_type, 1234, 4321, payload, |
- sizeof(payload), nullptr, nullptr, nullptr)); |
+ kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
StreamDataCounters expected; |
expected.transmitted.payload_bytes = 6; |
expected.transmitted.header_bytes = 12; |
@@ -1369,8 +1392,8 @@ TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacks) { |
fec_params.max_fec_frames = 1; |
rtp_sender_->SetFecParameters(fec_params, fec_params); |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
- kVideoFrameDelta, payload_type, 1234, 4321, payload, |
- sizeof(payload), nullptr, nullptr, nullptr)); |
+ kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload), |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
expected.transmitted.payload_bytes = 40; |
expected.transmitted.header_bytes = 60; |
expected.transmitted.packets = 5; |
@@ -1388,8 +1411,8 @@ TEST_P(RtpSenderAudioTest, SendAudio) { |
uint8_t payload[] = {47, 11, 32, 93, 89}; |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
- kAudioFrameCN, payload_type, 1234, 4321, payload, |
- sizeof(payload), nullptr, nullptr, nullptr)); |
+ kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload), |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
auto sent_payload = transport_.last_sent_packet().payload(); |
EXPECT_THAT(sent_payload, ElementsAreArray(payload)); |
@@ -1407,8 +1430,8 @@ TEST_P(RtpSenderAudioTest, SendAudioWithAudioLevelExtension) { |
uint8_t payload[] = {47, 11, 32, 93, 89}; |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
- kAudioFrameCN, payload_type, 1234, 4321, payload, |
- sizeof(payload), nullptr, nullptr, nullptr)); |
+ kAudioFrameCN, payload_type, 1234, 4321, payload, sizeof(payload), |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
auto sent_payload = transport_.last_sent_packet().payload(); |
EXPECT_THAT(sent_payload, ElementsAreArray(payload)); |
@@ -1445,22 +1468,22 @@ TEST_P(RtpSenderAudioTest, CheckMarkerBitForTelephoneEvents) { |
// During start, it takes the starting timestamp as last sent timestamp. |
// The duration is calculated as the difference of current and last sent |
// timestamp. So for first call it will skip since the duration is zero. |
- ASSERT_TRUE(rtp_sender_->SendOutgoingData(kEmptyFrame, kPayloadType, |
- capture_time_ms, 0, nullptr, 0, |
- nullptr, nullptr, nullptr)); |
+ ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
+ kEmptyFrame, kPayloadType, capture_time_ms, 0, nullptr, 0, nullptr, |
+ nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
// DTMF Sample Length is (Frequency/1000) * Duration. |
// So in this case, it is (8000/1000) * 500 = 4000. |
// Sending it as two packets. |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
- kEmptyFrame, kPayloadType, capture_time_ms + 2000, 0, |
- nullptr, 0, nullptr, nullptr, nullptr)); |
+ kEmptyFrame, kPayloadType, capture_time_ms + 2000, 0, nullptr, 0, nullptr, |
+ nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
// Marker Bit should be set to 1 for first packet. |
EXPECT_TRUE(transport_.last_sent_packet().Marker()); |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
- kEmptyFrame, kPayloadType, capture_time_ms + 4000, 0, |
- nullptr, 0, nullptr, nullptr, nullptr)); |
+ kEmptyFrame, kPayloadType, capture_time_ms + 4000, 0, nullptr, 0, nullptr, |
+ nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
// Marker Bit should be set to 0 for rest of the packets. |
EXPECT_FALSE(transport_.last_sent_packet().Marker()); |
} |
@@ -1478,8 +1501,8 @@ TEST_P(RtpSenderTestWithoutPacer, BytesReportedCorrectly) { |
uint8_t payload[] = {47, 11, 32, 93, 89}; |
ASSERT_TRUE(rtp_sender_->SendOutgoingData( |
- kVideoFrameKey, kPayloadType, 1234, 4321, payload, |
- sizeof(payload), nullptr, nullptr, nullptr)); |
+ kVideoFrameKey, kPayloadType, 1234, 4321, payload, sizeof(payload), |
+ nullptr, nullptr, nullptr, kDefaultExpectedRetransmissionTimeMs)); |
// Will send 2 full-size padding packets. |
rtp_sender_->TimeToSendPadding(1, PacedPacketInfo()); |
@@ -1553,7 +1576,7 @@ TEST_P(RtpSenderVideoTest, KeyFrameHasCVO) { |
hdr.rotation = kVideoRotation_0; |
rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload, |
kTimestamp, 0, kFrame, sizeof(kFrame), nullptr, |
- &hdr); |
+ &hdr, kDefaultExpectedRetransmissionTimeMs); |
VideoRotation rotation; |
EXPECT_TRUE( |
@@ -1579,7 +1602,8 @@ TEST_P(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) { |
fake_clock_.AdvanceTimeMilliseconds(kPacketizationTimeMs); |
rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload, |
kTimestamp, kCaptureTimestamp, kFrame, |
- sizeof(kFrame), nullptr, &hdr); |
+ sizeof(kFrame), nullptr, &hdr, |
+ kDefaultExpectedRetransmissionTimeMs); |
VideoSendTiming timing; |
EXPECT_TRUE(transport_.last_sent_packet().GetExtension<VideoTimingExtension>( |
&timing)); |
@@ -1595,14 +1619,14 @@ TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) { |
RTPVideoHeader hdr = {0}; |
hdr.rotation = kVideoRotation_90; |
- EXPECT_TRUE(rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, |
- kPayload, kTimestamp, 0, kFrame, |
- sizeof(kFrame), nullptr, &hdr)); |
+ EXPECT_TRUE(rtp_sender_video_->SendVideo( |
+ kRtpVideoGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, |
+ sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); |
hdr.rotation = kVideoRotation_0; |
- EXPECT_TRUE(rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameDelta, |
- kPayload, kTimestamp + 1, 0, kFrame, |
- sizeof(kFrame), nullptr, &hdr)); |
+ EXPECT_TRUE(rtp_sender_video_->SendVideo( |
+ kRtpVideoGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, |
+ sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); |
VideoRotation rotation; |
EXPECT_TRUE( |
@@ -1617,13 +1641,13 @@ TEST_P(RtpSenderVideoTest, DeltaFrameHasCVOWhenNonZero) { |
RTPVideoHeader hdr = {0}; |
hdr.rotation = kVideoRotation_90; |
- EXPECT_TRUE(rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, |
- kPayload, kTimestamp, 0, kFrame, |
- sizeof(kFrame), nullptr, &hdr)); |
+ EXPECT_TRUE(rtp_sender_video_->SendVideo( |
+ kRtpVideoGeneric, kVideoFrameKey, kPayload, kTimestamp, 0, kFrame, |
+ sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); |
- EXPECT_TRUE(rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameDelta, |
- kPayload, kTimestamp + 1, 0, kFrame, |
- sizeof(kFrame), nullptr, &hdr)); |
+ EXPECT_TRUE(rtp_sender_video_->SendVideo( |
+ kRtpVideoGeneric, kVideoFrameDelta, kPayload, kTimestamp + 1, 0, kFrame, |
+ sizeof(kFrame), nullptr, &hdr, kDefaultExpectedRetransmissionTimeMs)); |
VideoRotation rotation; |
EXPECT_TRUE( |
@@ -1652,6 +1676,224 @@ TEST_P(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) { |
ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3)); |
} |
+TEST_P(RtpSenderVideoTest, RetransmissionTypesGeneric) { |
+ RTPVideoHeader header; |
+ header.codec = kRtpVideoGeneric; |
+ |
+ EXPECT_EQ(kDontRetransmit, |
+ rtp_sender_video_->GetStorageType( |
+ header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType( |
+ header, kConditionallyRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitAllPackets, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+} |
+ |
+TEST_P(RtpSenderVideoTest, RetransmissionTypesH264) { |
+ RTPVideoHeader header; |
+ header.codec = kRtpVideoH264; |
+ header.codecHeader.H264.packetization_mode = |
+ H264PacketizationMode::NonInterleaved; |
+ |
+ EXPECT_EQ(kDontRetransmit, |
+ rtp_sender_video_->GetStorageType( |
+ header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType( |
+ header, kConditionallyRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitAllPackets, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+} |
+ |
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8BaseLayer) { |
+ RTPVideoHeader header; |
+ header.codec = kRtpVideoVp8; |
+ header.codecHeader.VP8.temporalIdx = 0; |
+ |
+ EXPECT_EQ(kDontRetransmit, |
+ rtp_sender_video_->GetStorageType( |
+ header, kRetransmitOff, kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers | kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( |
+ header, kConditionallyRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ( |
+ kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType( |
+ header, kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitAllPackets, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+} |
+ |
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP8HigherLayers) { |
+ RTPVideoHeader header; |
+ header.codec = kRtpVideoVp8; |
+ |
+ for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) { |
+ header.codecHeader.VP8.temporalIdx = tid; |
+ |
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitOff, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers | kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitAllPackets, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ } |
+} |
+ |
+TEST_P(RtpSenderVideoTest, RetransmissionTypesVP9) { |
+ RTPVideoHeader header; |
+ header.codec = kRtpVideoVp9; |
+ |
+ for (int tid = 1; tid <= kMaxTemporalStreams; ++tid) { |
+ header.codecHeader.VP9.temporal_idx = tid; |
+ |
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitOff, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kDontRetransmit, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType( |
+ header, kRetransmitHigherLayers | kRetransmitBaseLayer, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ EXPECT_EQ(kAllowRetransmission, rtp_sender_video_->GetStorageType( |
+ header, kRetransmitAllPackets, |
+ kDefaultExpectedRetransmissionTimeMs)); |
+ } |
+} |
+ |
+TEST_P(RtpSenderVideoTest, ConditionalRetransmit) { |
+ const int64_t kFrameIntervalMs = 33; |
+ const int64_t kRttMs = (kFrameIntervalMs * 3) / 2; |
+ const uint8_t kSettings = |
+ kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers; |
+ |
+ // Insert VP8 frames for all temporal layers, but stop before the final index. |
+ RTPVideoHeader header; |
+ header.codec = kRtpVideoVp8; |
+ |
+ // Fill averaging window to prevent rounding errors. |
+ constexpr int kNumRepetitions = |
+ (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) / |
+ kFrameIntervalMs; |
+ constexpr int kPattern[] = {0, 2, 1, 2}; |
+ for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) { |
+ header.codecHeader.VP8.temporalIdx = kPattern[i % arraysize(kPattern)]; |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs); |
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); |
+ } |
+ |
+ // Since we're at the start of the pattern, the next expected frame in TL0 is |
+ // right now. We will wait at most one expected retransmission time before |
+ // acknowledging that it did not arrive, which means this frame and the next |
+ // will not be retransmitted. |
+ header.codecHeader.VP8.temporalIdx = 1; |
+ EXPECT_EQ(StorageType::kDontRetransmit, |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); |
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); |
+ EXPECT_EQ(StorageType::kDontRetransmit, |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); |
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); |
+ |
+ // The TL0 frame did not arrive. So allow retransmission. |
+ EXPECT_EQ(StorageType::kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); |
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); |
+ |
+ // Insert a frame for TL2. We just had frame in TL1, so the next one there is |
+ // in three frames away. TL0 is still too far in the past. So, allow |
+ // retransmission. |
+ header.codecHeader.VP8.temporalIdx = 2; |
+ EXPECT_EQ(StorageType::kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); |
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); |
+ |
+ // Another TL2, next in TL1 is two frames away. Allow again. |
+ EXPECT_EQ(StorageType::kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); |
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); |
+ |
+ // Yet another TL2, next in TL1 is now only one frame away, so don't store |
+ // for retransmission. |
+ EXPECT_EQ(StorageType::kDontRetransmit, |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); |
+} |
+ |
+TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) { |
+ const int64_t kFrameIntervalMs = 200; |
+ const int64_t kRttMs = (kFrameIntervalMs * 3) / 2; |
+ const int32_t kSettings = |
+ kRetransmitBaseLayer | kConditionallyRetransmitHigherLayers; |
+ |
+ // Insert VP8 frames for all temporal layers, but stop before the final index. |
+ RTPVideoHeader header; |
+ header.codec = kRtpVideoVp8; |
+ |
+ // Fill averaging window to prevent rounding errors. |
+ constexpr int kNumRepetitions = |
+ (RTPSenderVideo::kTLRateWindowSizeMs + (kFrameIntervalMs / 2)) / |
+ kFrameIntervalMs; |
+ constexpr int kPattern[] = {0, 2, 2, 2}; |
+ for (size_t i = 0; i < arraysize(kPattern) * kNumRepetitions; ++i) { |
+ header.codecHeader.VP8.temporalIdx = kPattern[i % arraysize(kPattern)]; |
+ |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs); |
+ fake_clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); |
+ } |
+ |
+ // Since we're at the start of the pattern, the next expected frame will be |
+ // right now in TL0. Put it in TL1 instead. Regular rules would dictate that |
+ // we don't store for retransmission because we expect a frame in a lower |
+ // layer, but that last frame in TL1 was a long time ago in absolute terms, |
+ // so allow retransmission anyway. |
+ header.codecHeader.VP8.temporalIdx = 1; |
+ EXPECT_EQ(StorageType::kAllowRetransmission, |
+ rtp_sender_video_->GetStorageType(header, kSettings, kRttMs)); |
+} |
+ |
TEST_P(RtpSenderTest, OnOverheadChanged) { |
MockOverheadObserver mock_overhead_observer; |
rtp_sender_.reset( |