summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorYuri Wiitala <miu@chromium.org>2016-03-01 12:24:34 -0800
committerYuri Wiitala <miu@chromium.org>2016-03-01 20:26:44 +0000
commit9d4dc74a2a8e191dff252723222e9528e00eee24 (patch)
tree40163fd2b4ea9640a0ccd83a392a96a71008b130 /media
parentffcd12798aba12447e1983a3f69b8f74435d0fe5 (diff)
downloadchromium_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.cc114
-rw-r--r--media/cast/net/pacing/paced_sender.h15
-rw-r--r--media/cast/net/pacing/paced_sender_unittest.cc179
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