diff options
author | Yuri Wiitala <miu@chromium.org> | 2016-03-01 12:24:34 -0800 |
---|---|---|
committer | Yuri Wiitala <miu@chromium.org> | 2016-03-01 20:26:44 +0000 |
commit | 9d4dc74a2a8e191dff252723222e9528e00eee24 (patch) | |
tree | 40163fd2b4ea9640a0ccd83a392a96a71008b130 /media | |
parent | ffcd12798aba12447e1983a3f69b8f74435d0fe5 (diff) | |
download | chromium_src-9d4dc74a2a8e191dff252723222e9528e00eee24.zip chromium_src-9d4dc74a2a8e191dff252723222e9528e00eee24.tar.gz chromium_src-9d4dc74a2a8e191dff252723222e9528e00eee24.tar.bz2 |
[Cast Streaming] Fix for never sending some packets in large frames.
Speculatively, this should resolve some recent issues where large frames
are causing a lengthy (sometimes unrecoverable) freeze in tab mirroring
video.
This change adds a "round robin" heuristic to the PacedSender which
allows it to send/re-send all the packets in one frame the same number
of times. Before this change, the PacedSender always blindly sent the
first N packets and then, when no frame ACK was received, re-sent the
same first N packets. However, the lack of frame ACK was being caused
by the fact that the PacedSender never attempted to send the packets at
the end of the frame.
Also, added some verbose-only logging to help debug issues with
canceled packets being re-sent when they should not be.
BUG=590314
Review URL: https://codereview.chromium.org/1742793002
Cr-Commit-Position: refs/heads/master@{#378030}
(cherry picked from commit de0bbb05ee9f87c7d0451d2354989ac7cefcf7c4)
Review URL: https://codereview.chromium.org/1752063002 .
Cr-Commit-Position: refs/branch-heads/2623@{#553}
Cr-Branched-From: 92d77538a86529ca35f9220bd3cd512cbea1f086-refs/heads/master@{#369907}
Diffstat (limited to 'media')
-rw-r--r-- | media/cast/net/pacing/paced_sender.cc | 114 | ||||
-rw-r--r-- | media/cast/net/pacing/paced_sender.h | 15 | ||||
-rw-r--r-- | media/cast/net/pacing/paced_sender_unittest.cc | 179 |
3 files changed, 239 insertions, 69 deletions
diff --git a/media/cast/net/pacing/paced_sender.cc b/media/cast/net/pacing/paced_sender.cc index 1084901..b5e5c0e 100644 --- a/media/cast/net/pacing/paced_sender.cc +++ b/media/cast/net/pacing/paced_sender.cc @@ -40,7 +40,7 @@ PacketKey PacedPacketSender::MakePacketKey(base::TimeTicks capture_time, } PacedSender::PacketSendRecord::PacketSendRecord() - : last_byte_sent(0), last_byte_sent_for_audio(0) {} + : last_byte_sent(0), last_byte_sent_for_audio(0), cancel_count(0) {} PacedSender::PacedSender( size_t target_burst_size, @@ -99,6 +99,19 @@ bool PacedSender::SendPackets(const SendPacketVector& packets) { } const bool high_priority = IsHighPriority(packets.begin()->first); for (size_t i = 0; i < packets.size(); i++) { + if (VLOG_IS_ON(2)) { + PacketSendHistory::const_iterator history_it = + send_history_.find(packets[i].first); + if (history_it != send_history_.end() && + history_it->second.cancel_count > 0) { + VLOG(2) << "PacedSender::SendPackets() called for packet CANCELED " + << history_it->second.cancel_count << " times: " + << "ssrc=" << packets[i].first.ssrc + << ", frame_id=" << packets[i].first.frame_id + << ", packet_id=" << packets[i].first.packet_id; + } + } + DCHECK(IsHighPriority(packets[i].first) == high_priority); if (high_priority) { priority_packet_list_[packets[i].first] = @@ -127,6 +140,9 @@ bool PacedSender::ShouldResend(const PacketKey& packet_key, // packet Y sent just before X. Reject retransmission of X if ACK for // Y has not been received. // Only do this for video packets. + // + // TODO(miu): This sounds wrong. Audio packets are always transmitted first + // (because they are put in |priority_packet_list_|, see PopNextPacket()). if (packet_key.ssrc == video_ssrc_) { if (dedup_info.last_byte_acked_for_audio && it->second.last_byte_sent_for_audio && @@ -149,6 +165,19 @@ bool PacedSender::ResendPackets(const SendPacketVector& packets, const bool high_priority = IsHighPriority(packets.begin()->first); const base::TimeTicks now = clock_->NowTicks(); for (size_t i = 0; i < packets.size(); i++) { + if (VLOG_IS_ON(2)) { + PacketSendHistory::const_iterator history_it = + send_history_.find(packets[i].first); + if (history_it != send_history_.end() && + history_it->second.cancel_count > 0) { + VLOG(2) << "PacedSender::ReendPackets() called for packet CANCELED " + << history_it->second.cancel_count << " times: " + << "ssrc=" << packets[i].first.ssrc + << ", frame_id=" << packets[i].first.frame_id + << ", packet_id=" << packets[i].first.packet_id; + } + } + if (!ShouldResend(packets[i].first, dedup_info, now)) { LogPacketEvent(packets[i].second->data, PACKET_RTX_REJECTED); continue; @@ -189,18 +218,67 @@ bool PacedSender::SendRtcpPacket(uint32_t ssrc, PacketRef packet) { void PacedSender::CancelSendingPacket(const PacketKey& packet_key) { packet_list_.erase(packet_key); priority_packet_list_.erase(packet_key); + + if (VLOG_IS_ON(2)) { + PacketSendHistory::iterator history_it = send_history_.find(packet_key); + if (history_it != send_history_.end()) + ++history_it->second.cancel_count; + } } PacketRef PacedSender::PopNextPacket(PacketType* packet_type, PacketKey* packet_key) { + // Always pop from the priority list first. PacketList* list = !priority_packet_list_.empty() ? &priority_packet_list_ : &packet_list_; DCHECK(!list->empty()); - PacketList::iterator i = list->begin(); - *packet_type = i->second.first; - *packet_key = i->first; - PacketRef ret = i->second.second; - list->erase(i); + + // Determine which packet in the frame should be popped by examining the + // |send_history_| for prior transmission attempts. Packets that have never + // been transmitted will be popped first. If all packets have transmitted + // before, pop the one that has not been re-attempted for the longest time. + PacketList::iterator it = list->begin(); + PacketKey last_key = it->first; + last_key.packet_id = UINT16_C(0xffff); + PacketSendHistory::const_iterator history_it = + send_history_.lower_bound(it->first); + base::TimeTicks earliest_send_time = + base::TimeTicks() + base::TimeDelta::Max(); + PacketList::iterator found_it = it; + while (true) { + if (history_it == send_history_.end() || it->first < history_it->first) { + // There is no send history for this packet, which means it has not been + // transmitted yet. + found_it = it; + break; + } + + DCHECK(it->first == history_it->first); + if (history_it->second.time < earliest_send_time) { + earliest_send_time = history_it->second.time; + found_it = it; + } + + // Advance to next packet for the current frame, or break if there are no + // more. + ++it; + if (it == list->end() || last_key < it->first) + break; + + // Advance to next history entry. Since there may be "holes" in the packet + // list (e.g., due to packets canceled for retransmission), it's possible + // |history_it| will have to be advanced more than once even though |it| was + // only advanced once. + do { + ++history_it; + } while (history_it != send_history_.end() && + history_it->first < it->first); + } + + *packet_type = found_it->second.first; + *packet_key = found_it->first; + PacketRef ret = found_it->second.second; + list->erase(found_it); return ret; } @@ -279,8 +357,16 @@ void PacedSender::SendStoredPackets() { PacketType packet_type; PacketKey packet_key; PacketRef packet = PopNextPacket(&packet_type, &packet_key); - PacketSendRecord send_record; - send_record.time = now; + PacketSendRecord* const send_record = &(send_history_[packet_key]); + send_record->time = now; + + if (send_record->cancel_count > 0 && packet_type != PacketType_RTCP) { + VLOG(2) << "PacedSender is sending a packet known to have been CANCELED " + << send_record->cancel_count << " times: " + << "ssrc=" << packet_key.ssrc + << ", frame_id=" << packet_key.frame_id + << ", packet_id=" << packet_key.packet_id; + } switch (packet_type) { case PacketType_Resend: @@ -296,11 +382,10 @@ void PacedSender::SendStoredPackets() { const bool socket_blocked = !transport_->SendPacket(packet, cb); // Save the send record. - send_record.last_byte_sent = transport_->GetBytesSent(); - send_record.last_byte_sent_for_audio = GetLastByteSentForSsrc(audio_ssrc_); - send_history_[packet_key] = send_record; - send_history_buffer_[packet_key] = send_record; - last_byte_sent_[packet_key.ssrc] = send_record.last_byte_sent; + send_record->last_byte_sent = transport_->GetBytesSent(); + send_record->last_byte_sent_for_audio = GetLastByteSentForSsrc(audio_ssrc_); + send_history_buffer_[packet_key] = *send_record; + last_byte_sent_[packet_key.ssrc] = send_record->last_byte_sent; if (socket_blocked) { state_ = State_TransportBlocked; @@ -310,6 +395,9 @@ void PacedSender::SendStoredPackets() { } // Keep ~0.5 seconds of data (1000 packets). + // + // TODO(miu): This has no relation to the actual size of the frames, and so + // there's no way to reason whether 1000 is enough or too much, or whatever. if (send_history_buffer_.size() >= max_burst_size_ * kMaxDedupeWindowMs / kPacingIntervalMs) { send_history_.swap(send_history_buffer_); diff --git a/media/cast/net/pacing/paced_sender.h b/media/cast/net/pacing/paced_sender.h index 714fe9d..41609e7 100644 --- a/media/cast/net/pacing/paced_sender.h +++ b/media/cast/net/pacing/paced_sender.h @@ -42,6 +42,11 @@ struct PacketKey { uint32_t frame_id; uint16_t packet_id; + bool operator==(const PacketKey& key) const { + return std::tie(capture_time, ssrc, frame_id, packet_id) == + std::tie(key.capture_time, key.ssrc, key.frame_id, key.packet_id); + } + bool operator<(const PacketKey& key) const { return std::tie(capture_time, ssrc, frame_id, packet_id) < std::tie(key.capture_time, key.ssrc, key.frame_id, key.packet_id); @@ -171,9 +176,12 @@ class PacedSender : public PacedPacketSender, bool empty() const; size_t size() const; - // Returns the next packet to send. RTCP packets have highest priority, - // resend packets have second highest priority and then comes everything - // else. + // Returns the next packet to send. RTCP packets have highest priority, then + // high-priority RTP packets, then normal-priority RTP packets. Packets + // within a frame are selected based on fairness to ensure all have an equal + // chance of being sent. Therefore, it is up to client code to ensure that + // packets acknowledged in NACK messages are removed from PacedSender (see + // CancelSendingPacket()), to avoid wasteful retransmission. PacketRef PopNextPacket(PacketType* packet_type, PacketKey* packet_key); @@ -203,6 +211,7 @@ class PacedSender : public PacedPacketSender, // packet was sent. int64_t last_byte_sent_for_audio; // Number of bytes sent to network from // audio stream just before this packet. + int cancel_count; // Number of times the packet was canceled (debugging). }; typedef std::map<PacketKey, PacketSendRecord> PacketSendHistory; PacketSendHistory send_history_; diff --git a/media/cast/net/pacing/paced_sender_unittest.cc b/media/cast/net/pacing/paced_sender_unittest.cc index fec5c5f..148b0fb 100644 --- a/media/cast/net/pacing/paced_sender_unittest.cc +++ b/media/cast/net/pacing/paced_sender_unittest.cc @@ -5,7 +5,8 @@ #include <stddef.h> #include <stdint.h> -#include <list> +#include <algorithm> +#include <deque> #include "base/big_endian.h" #include "base/macros.h" @@ -20,41 +21,65 @@ namespace media { namespace cast { namespace { -static const uint8_t kValue = 123; -static const size_t kSize1 = 101; -static const size_t kSize2 = 102; -static const size_t kSize3 = 103; -static const size_t kSize4 = 104; -static const size_t kNackSize = 105; -static const int64_t kStartMillisecond = INT64_C(12345678900000); -static const uint32_t kVideoSsrc = 0x1234; -static const uint32_t kAudioSsrc = 0x5678; -static const uint32_t kVideoFrameRtpTimestamp = 12345; -static const uint32_t kAudioFrameRtpTimestamp = 23456; +const uint8_t kValue = 123; +const size_t kSize1 = 101; +const size_t kSize2 = 102; +const size_t kSize3 = 103; +const size_t kSize4 = 104; +const size_t kNackSize = 105; +const int64_t kStartMillisecond = INT64_C(12345678900000); +const uint32_t kVideoSsrc = 0x1234; +const uint32_t kAudioSsrc = 0x5678; +const uint32_t kVideoFrameRtpTimestamp = 12345; +const uint32_t kAudioFrameRtpTimestamp = 23456; + +// RTCP packets don't really have a packet ID. However, the bytes where +// TestPacketSender checks for the ID should be set to 31611, so we'll just +// check that. +const uint16_t kRtcpPacketIdMagic = UINT16_C(31611); class TestPacketSender : public PacketSender { public: TestPacketSender() : bytes_sent_(0) {} bool SendPacket(PacketRef packet, const base::Closure& cb) final { - EXPECT_FALSE(expected_packet_size_.empty()); - size_t expected_packet_size = expected_packet_size_.front(); - expected_packet_size_.pop_front(); + EXPECT_FALSE(expected_packet_sizes_.empty()); + size_t expected_packet_size = expected_packet_sizes_.front(); + expected_packet_sizes_.pop_front(); EXPECT_EQ(expected_packet_size, packet->data.size()); bytes_sent_ += packet->data.size(); + + // Parse for the packet ID and confirm it is the next one we expect. + EXPECT_LE(kSize1, packet->data.size()); + base::BigEndianReader reader(reinterpret_cast<char*>(&packet->data[0]), + packet->data.size()); + bool success = reader.Skip(14); + uint16_t packet_id = 0xffff; + success &= reader.ReadU16(&packet_id); + EXPECT_TRUE(success); + const uint16_t expected_packet_id = expected_packet_ids_.front(); + expected_packet_ids_.pop_front(); + EXPECT_EQ(expected_packet_id, packet_id); + return true; } int64_t GetBytesSent() final { return bytes_sent_; } - void AddExpectedSize(int expected_packet_size, int repeat_count) { - for (int i = 0; i < repeat_count; ++i) { - expected_packet_size_.push_back(expected_packet_size); + void AddExpectedSizesAndPacketIds(int packet_size, + uint16_t first_packet_id, + int sequence_length) { + for (int i = 0; i < sequence_length; ++i) { + expected_packet_sizes_.push_back(packet_size); + expected_packet_ids_.push_back(first_packet_id++); } } - public: - std::list<int> expected_packet_size_; + bool expecting_nothing_else() const { return expected_packet_sizes_.empty(); } + + private: + std::deque<int> expected_packet_sizes_; + std::deque<uint16_t> expected_packet_ids_; int64_t bytes_sent_; DISALLOW_COPY_AND_ASSIGN(TestPacketSender); @@ -111,17 +136,29 @@ class PacedSenderTest : public ::testing::Test { return packets; } + void SendWithoutBursting(const SendPacketVector& packets) { + const size_t kBatchSize = 10; + for (size_t i = 0; i < packets.size(); i += kBatchSize) { + const SendPacketVector next_batch( + packets.begin() + i, + packets.begin() + i + std::min(packets.size() - i, kBatchSize)); + ASSERT_TRUE(paced_sender_->SendPackets(next_batch)); + testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10)); + task_runner_->RunTasks(); + } + } + // Use this function to drain the packet list in PacedSender without having // to test the pacing implementation details. bool RunUntilEmpty(int max_tries) { for (int i = 0; i < max_tries; i++) { testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10)); task_runner_->RunTasks(); - if (mock_transport_.expected_packet_size_.empty()) + if (mock_transport_.expecting_nothing_else()) return true; } - return mock_transport_.expected_packet_size_.empty(); + return mock_transport_.expecting_nothing_else(); } std::vector<PacketEvent> packet_events_; @@ -136,13 +173,14 @@ class PacedSenderTest : public ::testing::Test { } // namespace TEST_F(PacedSenderTest, PassThroughRtcp) { - mock_transport_.AddExpectedSize(kSize1, 2); SendPacketVector packets = CreateSendPacketVector(kSize1, 1, true); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); EXPECT_TRUE(paced_sender_->SendPackets(packets)); EXPECT_TRUE(paced_sender_->ResendPackets(packets, DedupInfo())); - mock_transport_.AddExpectedSize(kSize2, 1); + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, kRtcpPacketIdMagic, 1); Packet tmp(kSize2, kValue); EXPECT_TRUE(paced_sender_->SendRtcpPacket( 1, @@ -156,11 +194,11 @@ TEST_F(PacedSenderTest, BasicPace) { false); const base::TimeTicks earliest_event_timestamp = testing_clock_.NowTicks(); - mock_transport_.AddExpectedSize(kSize1, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 10); EXPECT_TRUE(paced_sender_->SendPackets(packets)); // Check that we get the next burst. - mock_transport_.AddExpectedSize(kSize1, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(10), 10); base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(10); testing_clock_.Advance(timeout); @@ -172,7 +210,7 @@ TEST_F(PacedSenderTest, BasicPace) { task_runner_->RunTasks(); // Check that we get the next burst. - mock_transport_.AddExpectedSize(kSize1, 7); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(20), 7); testing_clock_.Advance(timeout); task_runner_->RunTasks(); @@ -211,14 +249,14 @@ TEST_F(PacedSenderTest, PaceWithNack) { CreateSendPacketVector(kSize2, num_of_packets_in_frame, true); // Check that the first burst of the frame go out on the wire. - mock_transport_.AddExpectedSize(kSize1, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 10); EXPECT_TRUE(paced_sender_->SendPackets(first_frame_packets)); // Add first NACK request. EXPECT_TRUE(paced_sender_->ResendPackets(nack_packets, DedupInfo())); // Check that we get the first NACK burst. - mock_transport_.AddExpectedSize(kNackSize, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kNackSize, UINT16_C(0), 10); base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(10); testing_clock_.Advance(timeout); task_runner_->RunTasks(); @@ -227,24 +265,25 @@ TEST_F(PacedSenderTest, PaceWithNack) { EXPECT_TRUE(paced_sender_->ResendPackets(nack_packets, DedupInfo())); // Check that we get the next NACK burst. - mock_transport_.AddExpectedSize(kNackSize, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kNackSize, UINT16_C(10), 2); + mock_transport_.AddExpectedSizesAndPacketIds(kNackSize, UINT16_C(0), 8); testing_clock_.Advance(timeout); task_runner_->RunTasks(); // End of NACK plus two packets from the oldest frame. // Note that two of the NACKs have been de-duped. - mock_transport_.AddExpectedSize(kNackSize, 2); - mock_transport_.AddExpectedSize(kSize1, 2); + mock_transport_.AddExpectedSizesAndPacketIds(kNackSize, UINT16_C(8), 2); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(10), 2); testing_clock_.Advance(timeout); task_runner_->RunTasks(); // Add second frame. // Make sure we don't delay the second frame due to the previous packets. - mock_transport_.AddExpectedSize(kSize2, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, UINT16_C(0), 10); EXPECT_TRUE(paced_sender_->SendPackets(second_frame_packets)); // Last packets of frame 2. - mock_transport_.AddExpectedSize(kSize2, 2); + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, UINT16_C(10), 2); testing_clock_.Advance(timeout); task_runner_->RunTasks(); @@ -301,47 +340,47 @@ TEST_F(PacedSenderTest, PaceWith60fps) { base::TimeDelta timeout_10ms = base::TimeDelta::FromMilliseconds(10); // Check that the first burst of the frame go out on the wire. - mock_transport_.AddExpectedSize(kSize1, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 10); EXPECT_TRUE(paced_sender_->SendPackets(first_frame_packets)); - mock_transport_.AddExpectedSize(kSize1, 7); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(10), 7); testing_clock_.Advance(timeout_10ms); task_runner_->RunTasks(); testing_clock_.Advance(base::TimeDelta::FromMilliseconds(6)); // Add second frame, after 16 ms. - mock_transport_.AddExpectedSize(kSize2, 3); + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, UINT16_C(0), 3); EXPECT_TRUE(paced_sender_->SendPackets(second_frame_packets)); testing_clock_.Advance(base::TimeDelta::FromMilliseconds(4)); - mock_transport_.AddExpectedSize(kSize2, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, UINT16_C(3), 10); testing_clock_.Advance(timeout_10ms); task_runner_->RunTasks(); - mock_transport_.AddExpectedSize(kSize2, 4); + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, UINT16_C(13), 4); testing_clock_.Advance(timeout_10ms); task_runner_->RunTasks(); testing_clock_.Advance(base::TimeDelta::FromMilliseconds(3)); // Add third frame, after 33 ms. - mock_transport_.AddExpectedSize(kSize3, 6); + mock_transport_.AddExpectedSizesAndPacketIds(kSize3, UINT16_C(0), 6); EXPECT_TRUE(paced_sender_->SendPackets(third_frame_packets)); - mock_transport_.AddExpectedSize(kSize3, 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize3, UINT16_C(6), 10); testing_clock_.Advance(base::TimeDelta::FromMilliseconds(7)); task_runner_->RunTasks(); // Add fourth frame, after 50 ms. EXPECT_TRUE(paced_sender_->SendPackets(fourth_frame_packets)); - mock_transport_.AddExpectedSize(kSize3, 1); - mock_transport_.AddExpectedSize(kSize4, 9); + mock_transport_.AddExpectedSizesAndPacketIds(kSize3, UINT16_C(16), 1); + mock_transport_.AddExpectedSizesAndPacketIds(kSize4, UINT16_C(0), 9); testing_clock_.Advance(timeout_10ms); task_runner_->RunTasks(); - mock_transport_.AddExpectedSize(kSize4, 8); + mock_transport_.AddExpectedSizesAndPacketIds(kSize4, UINT16_C(9), 8); testing_clock_.Advance(timeout_10ms); task_runner_->RunTasks(); @@ -362,11 +401,11 @@ TEST_F(PacedSenderTest, SendPriority) { // 3. Audio packet x 1. // 4. Video retransmission packet x 10. // 5. Video packet x 10. - mock_transport_.AddExpectedSize(kSize2, 10); // Normal video packets. - mock_transport_.AddExpectedSize(kSize3, 1); // RTCP packet. - mock_transport_.AddExpectedSize(kSize1, 1); // Audio packet. - mock_transport_.AddExpectedSize(kSize4, 10); // Resend video packets. - mock_transport_.AddExpectedSize(kSize2, 10); // Normal video packets. + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, UINT16_C(0), 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize3, kRtcpPacketIdMagic, 1); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); + mock_transport_.AddExpectedSizesAndPacketIds(kSize4, UINT16_C(0), 10); + mock_transport_.AddExpectedSizesAndPacketIds(kSize2, UINT16_C(10), 10); paced_sender_->RegisterPrioritySsrc(kAudioSsrc); @@ -406,11 +445,10 @@ TEST_F(PacedSenderTest, SendPriority) { } TEST_F(PacedSenderTest, GetLastByteSent) { - mock_transport_.AddExpectedSize(kSize1, 4); - SendPacketVector packets1 = CreateSendPacketVector(kSize1, 1, true); SendPacketVector packets2 = CreateSendPacketVector(kSize1, 1, false); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); EXPECT_TRUE(paced_sender_->SendPackets(packets1)); EXPECT_EQ(static_cast<int64_t>(kSize1), paced_sender_->GetLastByteSentForPacket(packets1[0].first)); @@ -418,6 +456,7 @@ TEST_F(PacedSenderTest, GetLastByteSent) { paced_sender_->GetLastByteSentForSsrc(kAudioSsrc)); EXPECT_EQ(0, paced_sender_->GetLastByteSentForSsrc(kVideoSsrc)); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); EXPECT_TRUE(paced_sender_->SendPackets(packets2)); EXPECT_EQ(static_cast<int64_t>(2 * kSize1), paced_sender_->GetLastByteSentForPacket(packets2[0].first)); @@ -426,6 +465,7 @@ TEST_F(PacedSenderTest, GetLastByteSent) { EXPECT_EQ(static_cast<int64_t>(2 * kSize1), paced_sender_->GetLastByteSentForSsrc(kVideoSsrc)); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); EXPECT_TRUE(paced_sender_->ResendPackets(packets1, DedupInfo())); EXPECT_EQ(static_cast<int64_t>(3 * kSize1), paced_sender_->GetLastByteSentForPacket(packets1[0].first)); @@ -434,6 +474,7 @@ TEST_F(PacedSenderTest, GetLastByteSent) { EXPECT_EQ(static_cast<int64_t>(2 * kSize1), paced_sender_->GetLastByteSentForSsrc(kVideoSsrc)); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); EXPECT_TRUE(paced_sender_->ResendPackets(packets2, DedupInfo())); EXPECT_EQ(static_cast<int64_t>(4 * kSize1), paced_sender_->GetLastByteSentForPacket(packets2[0].first)); @@ -444,9 +485,8 @@ TEST_F(PacedSenderTest, GetLastByteSent) { } TEST_F(PacedSenderTest, DedupWithResendInterval) { - mock_transport_.AddExpectedSize(kSize1, 2); - SendPacketVector packets = CreateSendPacketVector(kSize1, 1, true); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); EXPECT_TRUE(paced_sender_->SendPackets(packets)); testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10)); @@ -458,9 +498,42 @@ TEST_F(PacedSenderTest, DedupWithResendInterval) { EXPECT_EQ(static_cast<int64_t>(kSize1), mock_transport_.GetBytesSent()); dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(5); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 1); EXPECT_TRUE(paced_sender_->ResendPackets(packets, dedup_info)); EXPECT_EQ(static_cast<int64_t>(2 * kSize1), mock_transport_.GetBytesSent()); } +TEST_F(PacedSenderTest, AllPacketsInSameFrameAreResentFairly) { + const int kNumPackets = 400; + SendPacketVector packets = CreateSendPacketVector(kSize1, kNumPackets, false); + + // Send a large frame (400 packets, yeah!). Confirm that the paced sender + // sends each packet in the frame exactly once. + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), + kNumPackets); + SendWithoutBursting(packets); + ASSERT_TRUE(mock_transport_.expecting_nothing_else()); + + // Resend packets 2 and 3. Confirm that the paced sender sends them. Then, + // resend all of the first 10 packets. The paced sender should send packets + // 0, 1, and 4 through 9 first, and then 2 and 3. + SendPacketVector couple_of_packets; + couple_of_packets.push_back(packets[2]); + couple_of_packets.push_back(packets[3]); + + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(2), 2); + SendWithoutBursting(couple_of_packets); + ASSERT_TRUE(mock_transport_.expecting_nothing_else()); + + SendPacketVector first_ten_packets; + for (size_t i = 0; i < 10; ++i) + first_ten_packets.push_back(packets[i]); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(0), 2); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(4), 6); + mock_transport_.AddExpectedSizesAndPacketIds(kSize1, UINT16_C(2), 2); + SendWithoutBursting(first_ten_packets); + ASSERT_TRUE(mock_transport_.expecting_nothing_else()); +} + } // namespace cast } // namespace media |