Add delay limit to ChokeFilter.
BUG= R=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/3079005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5058 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -464,7 +464,7 @@ class ReorderFilter : public PacketProcessorInterface {
|
|||||||
// Apply a bitrate choke with an infinite queue on the packet stream.
|
// Apply a bitrate choke with an infinite queue on the packet stream.
|
||||||
class ChokeFilter : public PacketProcessorInterface {
|
class ChokeFilter : public PacketProcessorInterface {
|
||||||
public:
|
public:
|
||||||
ChokeFilter() : kbps_(1200), last_send_time_us_(0) {}
|
ChokeFilter() : kbps_(1200), max_delay_us_(0), last_send_time_us_(0) {}
|
||||||
virtual ~ChokeFilter() {}
|
virtual ~ChokeFilter() {}
|
||||||
|
|
||||||
void SetCapacity(uint32_t kbps) {
|
void SetCapacity(uint32_t kbps) {
|
||||||
@ -473,18 +473,34 @@ class ChokeFilter : public PacketProcessorInterface {
|
|||||||
kbps_ = kbps;
|
kbps_ = kbps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetMaxDelay(int64_t max_delay_ms) {
|
||||||
|
BWE_TEST_LOGGING_ENABLE(false);
|
||||||
|
BWE_TEST_LOGGING_LOG1("Max Delay", "%d ms", static_cast<int>(max_delay_ms));
|
||||||
|
assert(max_delay_ms >= 0);
|
||||||
|
max_delay_us_ = max_delay_ms * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void RunFor(int64_t /*time_ms*/, Packets* in_out) {
|
virtual void RunFor(int64_t /*time_ms*/, Packets* in_out) {
|
||||||
assert(in_out);
|
assert(in_out);
|
||||||
for (PacketsIt it = in_out->begin(); it != in_out->end(); ++it) {
|
for (PacketsIt it = in_out->begin(); it != in_out->end(); ) {
|
||||||
int64_t earliest_send_time_us = last_send_time_us_ +
|
int64_t earliest_send_time_us = last_send_time_us_ +
|
||||||
(it->payload_size() * 8 * 1000 + kbps_ / 2) / kbps_;
|
(it->payload_size() * 8 * 1000 + kbps_ / 2) / kbps_;
|
||||||
last_send_time_us_ = std::max(it->send_time_us(), earliest_send_time_us);
|
int64_t new_send_time_us = std::max(it->send_time_us(),
|
||||||
it->set_send_time_us(last_send_time_us_);
|
earliest_send_time_us);
|
||||||
|
if (max_delay_us_ == 0 ||
|
||||||
|
max_delay_us_ >= (new_send_time_us - it->send_time_us())) {
|
||||||
|
it->set_send_time_us(new_send_time_us);
|
||||||
|
last_send_time_us_ = new_send_time_us;
|
||||||
|
++it;
|
||||||
|
} else {
|
||||||
|
it = in_out->erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t kbps_;
|
uint32_t kbps_;
|
||||||
|
int64_t max_delay_us_;
|
||||||
int64_t last_send_time_us_;
|
int64_t last_send_time_us_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ChokeFilter);
|
DISALLOW_COPY_AND_ASSIGN(ChokeFilter);
|
||||||
|
@ -727,13 +727,16 @@ class BweTestFramework_ChokeFilterTest : public ::testing::Test {
|
|||||||
: filter_(),
|
: filter_(),
|
||||||
now_ms_(0),
|
now_ms_(0),
|
||||||
sequence_number_(0),
|
sequence_number_(0),
|
||||||
output_packets_() {
|
output_packets_(),
|
||||||
|
send_times_us_() {
|
||||||
}
|
}
|
||||||
virtual ~BweTestFramework_ChokeFilterTest() {}
|
virtual ~BweTestFramework_ChokeFilterTest() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ChokeFilter filter_;
|
||||||
|
|
||||||
void TestChoke(int64_t run_for_ms, uint32_t packets_to_generate,
|
void TestChoke(int64_t run_for_ms, uint32_t packets_to_generate,
|
||||||
uint32_t choke_kbps, uint32_t expected_kbit_transmitted) {
|
uint32_t expected_kbit_transmitted) {
|
||||||
// Generate a bunch of packets, apply choke, verify output is ordered.
|
// Generate a bunch of packets, apply choke, verify output is ordered.
|
||||||
Packets packets;
|
Packets packets;
|
||||||
RTPHeader header = {0};
|
RTPHeader header = {0};
|
||||||
@ -742,9 +745,9 @@ class BweTestFramework_ChokeFilterTest : public ::testing::Test {
|
|||||||
header.sequenceNumber = sequence_number_++;
|
header.sequenceNumber = sequence_number_++;
|
||||||
// Payload is 1000 bits.
|
// Payload is 1000 bits.
|
||||||
packets.push_back(BwePacket(send_time_ms * 1000, 125, header));
|
packets.push_back(BwePacket(send_time_ms * 1000, 125, header));
|
||||||
|
send_times_us_.push_back(send_time_ms * 1000);
|
||||||
}
|
}
|
||||||
ASSERT_TRUE(IsTimeSorted(packets));
|
ASSERT_TRUE(IsTimeSorted(packets));
|
||||||
filter_.SetCapacity(choke_kbps);
|
|
||||||
filter_.RunFor(run_for_ms, &packets);
|
filter_.RunFor(run_for_ms, &packets);
|
||||||
now_ms_ += run_for_ms;
|
now_ms_ += run_for_ms;
|
||||||
output_packets_.splice(output_packets_.end(), packets);
|
output_packets_.splice(output_packets_.end(), packets);
|
||||||
@ -764,11 +767,21 @@ class BweTestFramework_ChokeFilterTest : public ::testing::Test {
|
|||||||
EXPECT_EQ(expected_kbit_transmitted, (bytes_transmitted * 8) / 1000);
|
EXPECT_EQ(expected_kbit_transmitted, (bytes_transmitted * 8) / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckMaxDelay(int64_t max_delay_ms) {
|
||||||
|
for (PacketsIt it = output_packets_.begin(); it != output_packets_.end();
|
||||||
|
++it) {
|
||||||
|
const BwePacket& packet = *it;
|
||||||
|
int64_t delay_us = packet.send_time_us() -
|
||||||
|
send_times_us_[packet.header().sequenceNumber];
|
||||||
|
EXPECT_GE(max_delay_ms * 1000, delay_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ChokeFilter filter_;
|
|
||||||
int64_t now_ms_;
|
int64_t now_ms_;
|
||||||
uint32_t sequence_number_;
|
uint32_t sequence_number_;
|
||||||
Packets output_packets_;
|
Packets output_packets_;
|
||||||
|
std::vector<int64_t> send_times_us_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(BweTestFramework_ChokeFilterTest);
|
DISALLOW_COPY_AND_ASSIGN(BweTestFramework_ChokeFilterTest);
|
||||||
};
|
};
|
||||||
@ -777,38 +790,69 @@ TEST_F(BweTestFramework_ChokeFilterTest, Short) {
|
|||||||
// 100ms, 100 packets, 10 kbps choke -> 1 kbit of data should have propagated.
|
// 100ms, 100 packets, 10 kbps choke -> 1 kbit of data should have propagated.
|
||||||
// That is actually just a single packet, since each packet has 1000 bits of
|
// That is actually just a single packet, since each packet has 1000 bits of
|
||||||
// payload.
|
// payload.
|
||||||
TestChoke(100, 100, 10, 1);
|
filter_.SetCapacity(10);
|
||||||
|
TestChoke(100, 100, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BweTestFramework_ChokeFilterTest, Medium) {
|
TEST_F(BweTestFramework_ChokeFilterTest, Medium) {
|
||||||
// 100ms, 10 packets, 10 kbps choke -> 1 packet through, or 1 kbit.
|
// 100ms, 10 packets, 10 kbps choke -> 1 packet through, or 1 kbit.
|
||||||
TestChoke(100, 10, 10, 1);
|
filter_.SetCapacity(10);
|
||||||
// 200ms, no new packets, same choke -> another packet through.
|
TestChoke(100, 10, 1);
|
||||||
TestChoke(100, 0, 10, 1);
|
// 200ms, no new packets -> another packet through.
|
||||||
// 1000ms, no new packets, same choke -> 8 more packets.
|
TestChoke(100, 0, 1);
|
||||||
TestChoke(800, 0, 10, 8);
|
// 1000ms, no new packets -> 8 more packets.
|
||||||
// 2000ms, no new packets, same choke -> queue is empty so no output.
|
TestChoke(800, 0, 8);
|
||||||
TestChoke(1000, 0, 10, 0);
|
// 2000ms, no new packets -> queue is empty so no output.
|
||||||
|
TestChoke(1000, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BweTestFramework_ChokeFilterTest, Long) {
|
TEST_F(BweTestFramework_ChokeFilterTest, Long) {
|
||||||
// 100ms, 100 packets in queue, 10 kbps choke -> 1 packet through, or 1 kbit.
|
// 100ms, 100 packets in queue, 10 kbps choke -> 1 packet through, or 1 kbit.
|
||||||
TestChoke(100, 100, 10, 1);
|
filter_.SetCapacity(10);
|
||||||
|
TestChoke(100, 100, 1);
|
||||||
// 200ms, no input, another packet through.
|
// 200ms, no input, another packet through.
|
||||||
TestChoke(100, 0, 10, 1);
|
TestChoke(100, 0, 1);
|
||||||
// 1000ms, no input, 8 packets through.
|
// 1000ms, no input, 8 packets through.
|
||||||
TestChoke(800, 0, 10, 8);
|
TestChoke(800, 0, 8);
|
||||||
// 10000ms, no input, raise choke to 100 kbps. Remaining 90 packets in queue
|
// 10000ms, no input, raise choke to 100 kbps. Remaining 90 packets in queue
|
||||||
// should be propagated, for a total of 90 kbps.
|
// should be propagated, for a total of 90 kbps.
|
||||||
TestChoke(9000, 0, 100, 90);
|
filter_.SetCapacity(100);
|
||||||
// 10100ms, 20 more packets, 100 kbps choke -> 10 packets or 10 kbit through.
|
TestChoke(9000, 0, 90);
|
||||||
TestChoke(100, 20, 100, 10);
|
// 10100ms, 20 more packets -> 10 packets or 10 kbit through.
|
||||||
// 10300ms, 10 more packets, same choke -> 20 packets out.
|
TestChoke(100, 20, 10);
|
||||||
TestChoke(200, 10, 100, 20);
|
// 10300ms, 10 more packets -> 20 packets out.
|
||||||
|
TestChoke(200, 10, 20);
|
||||||
// 11300ms, no input, queue should be empty.
|
// 11300ms, no input, queue should be empty.
|
||||||
TestChoke(1000, 0, 10, 0);
|
filter_.SetCapacity(10);
|
||||||
|
TestChoke(1000, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(BweTestFramework_ChokeFilterTest, MaxDelay) {
|
||||||
|
// 10 kbps choke, 500 ms delay cap
|
||||||
|
filter_.SetCapacity(10);
|
||||||
|
filter_.SetMaxDelay(500);
|
||||||
|
// 100ms, 100 packets in queue, 10 kbps choke -> 1 packet through, or 1 kbit.
|
||||||
|
TestChoke(100, 100, 1);
|
||||||
|
CheckMaxDelay(500);
|
||||||
|
// 500ms, no input, 4 more packets through.
|
||||||
|
TestChoke(400, 0, 4);
|
||||||
|
// 10000ms, no input, remaining packets should have been dropped.
|
||||||
|
TestChoke(9500, 0, 0);
|
||||||
|
|
||||||
|
// 100 ms delay cap
|
||||||
|
filter_.SetMaxDelay(100);
|
||||||
|
// 10100ms, 50 more packets -> 2 packets or 2 kbit through.
|
||||||
|
TestChoke(100, 50, 2);
|
||||||
|
CheckMaxDelay(100);
|
||||||
|
// 20000ms, no input, remaining packets in queue should have been dropped.
|
||||||
|
TestChoke(9900, 0, 0);
|
||||||
|
|
||||||
|
// Reset delay cap (0 is no cap) and verify no packets are dropped.
|
||||||
|
filter_.SetCapacity(10);
|
||||||
|
filter_.SetMaxDelay(0);
|
||||||
|
TestChoke(100, 100, 2);
|
||||||
|
TestChoke(9900, 0, 98);
|
||||||
|
}
|
||||||
} // namespace bwe
|
} // namespace bwe
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
Reference in New Issue
Block a user