Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1112)

Unified Diff: media/cast/test/end2end_unittest.cc

Issue 280993002: [Cast] Repair receiver playout time calculations and frame skip logic. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/cast/rtcp/rtcp_unittest.cc ('k') | media/cast/test/receiver.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/cast/test/end2end_unittest.cc
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index f46d5262f7198edb0147c934bc2287417e00c9a0..ae55fae76c5ac647b05e4c435cceece35006b3a0 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -63,16 +63,11 @@ static const double kVideoAcceptedPSNR = 38.0;
// The tests are commonly implemented with |kFrameTimerMs| RunTask function;
// a normal video is 30 fps hence the 33 ms between frames.
+//
+// TODO(miu): The errors in timing will add up significantly. Find an
+// alternative approach that eliminates use of this constant.
static const int kFrameTimerMs = 33;
-// The packets pass through the pacer which can delay the beginning of the
-// frame by 10 ms if there is packets belonging to the previous frame being
-// retransmitted.
-// In addition, audio packets are sent in 10mS intervals in audio_encoder.cc,
-// although we send an audio frame every 33mS, which adds an extra delay.
-// A TODO was added in the code to resolve this.
-static const int kTimerErrorMs = 20;
-
// Start the video synthetic start value to medium range value, to avoid edge
// effects cause by encoding and quantization.
static const int kVideoStart = 100;
@@ -81,6 +76,14 @@ static const int kVideoStart = 100;
// chunks of this size.
static const int kAudioFrameDurationMs = 10;
+// The amount of time between frame capture on the sender and playout on the
+// receiver.
+static const int kTargetPlayoutDelayMs = 100;
+
+// The maximum amount of deviation expected in the playout times emitted by the
+// receiver.
+static const int kMaxAllowedPlayoutErrorMs = 30;
+
std::string ConvertFromBase16String(const std::string base_16) {
std::string compressed;
DCHECK_EQ(base_16.size() % 2, 0u) << "Must be a multiple of 2";
@@ -244,7 +247,7 @@ class TestReceiverAudioCallback
public:
struct ExpectedAudioFrame {
scoped_ptr<AudioBus> audio_bus;
- base::TimeTicks record_time;
+ base::TimeTicks playout_time;
};
TestReceiverAudioCallback() : num_called_(0) {}
@@ -254,13 +257,13 @@ class TestReceiverAudioCallback
}
void AddExpectedResult(const AudioBus& audio_bus,
- const base::TimeTicks& record_time) {
+ const base::TimeTicks& playout_time) {
scoped_ptr<ExpectedAudioFrame> expected_audio_frame(
new ExpectedAudioFrame());
expected_audio_frame->audio_bus =
AudioBus::Create(audio_bus.channels(), audio_bus.frames()).Pass();
audio_bus.CopyTo(expected_audio_frame->audio_bus.get());
- expected_audio_frame->record_time = record_time;
+ expected_audio_frame->playout_time = playout_time;
expected_frames_.push_back(expected_audio_frame.release());
}
@@ -292,15 +295,14 @@ class TestReceiverAudioCallback
1);
}
- // TODO(miu): This is a "fuzzy" way to check the timestamps. We should be
- // able to compute exact offsets with "omnipotent" knowledge of the system.
- const base::TimeTicks upper_bound =
- expected_audio_frame->record_time +
- base::TimeDelta::FromMilliseconds(kDefaultRtpMaxDelayMs +
- kTimerErrorMs);
- EXPECT_GE(upper_bound, playout_time)
- << "playout_time - upper_bound == "
- << (playout_time - upper_bound).InMicroseconds() << " usec";
+ EXPECT_NEAR(
+ (playout_time - expected_audio_frame->playout_time).InMillisecondsF(),
+ 0.0,
+ kMaxAllowedPlayoutErrorMs);
+ VLOG_IF(1, !last_playout_time_.is_null())
+ << "Audio frame playout time delta (compared to last frame) is "
+ << (playout_time - last_playout_time_).InMicroseconds() << " usec.";
+ last_playout_time_ = playout_time;
EXPECT_TRUE(is_continuous);
}
@@ -345,6 +347,7 @@ class TestReceiverAudioCallback
int num_called_;
int expected_sampling_frequency_;
std::list<ExpectedAudioFrame*> expected_frames_;
+ base::TimeTicks last_playout_time_;
};
// Class that verifies the video frames coming out of the receiver.
@@ -355,7 +358,7 @@ class TestReceiverVideoCallback
int start_value;
int width;
int height;
- base::TimeTicks capture_time;
+ base::TimeTicks playout_time;
bool should_be_continuous;
};
@@ -364,19 +367,19 @@ class TestReceiverVideoCallback
void AddExpectedResult(int start_value,
int width,
int height,
- const base::TimeTicks& capture_time,
+ const base::TimeTicks& playout_time,
bool should_be_continuous) {
ExpectedVideoFrame expected_video_frame;
expected_video_frame.start_value = start_value;
expected_video_frame.width = width;
expected_video_frame.height = height;
- expected_video_frame.capture_time = capture_time;
+ expected_video_frame.playout_time = playout_time;
expected_video_frame.should_be_continuous = should_be_continuous;
expected_frame_.push_back(expected_video_frame);
}
void CheckVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
- const base::TimeTicks& render_time,
+ const base::TimeTicks& playout_time,
bool is_continuous) {
++num_called_;
@@ -385,21 +388,6 @@ class TestReceiverVideoCallback
ExpectedVideoFrame expected_video_frame = expected_frame_.front();
expected_frame_.pop_front();
- base::TimeDelta time_since_capture =
- render_time - expected_video_frame.capture_time;
- const base::TimeDelta upper_bound = base::TimeDelta::FromMilliseconds(
- kDefaultRtpMaxDelayMs + kTimerErrorMs);
-
- // TODO(miu): This is a "fuzzy" way to check the timestamps. We should be
- // able to compute exact offsets with "omnipotent" knowledge of the system.
- EXPECT_GE(upper_bound, time_since_capture)
- << "time_since_capture - upper_bound == "
- << (time_since_capture - upper_bound).InMicroseconds() << " usec";
- // TODO(miu): I broke the concept of 100 ms target delay timing on the
- // receiver side, but the logic for computing playout time really isn't any
- // more broken than it was. This only affects the receiver, and is to be
- // rectified in an soon-upcoming change. http://crbug.com/356942
- // EXPECT_LE(expected_video_frame.capture_time, render_time);
EXPECT_EQ(expected_video_frame.width, video_frame->visible_rect().width());
EXPECT_EQ(expected_video_frame.height,
video_frame->visible_rect().height());
@@ -412,6 +400,15 @@ class TestReceiverVideoCallback
EXPECT_GE(I420PSNR(expected_I420_frame, video_frame), kVideoAcceptedPSNR);
+ EXPECT_NEAR(
+ (playout_time - expected_video_frame.playout_time).InMillisecondsF(),
+ 0.0,
+ kMaxAllowedPlayoutErrorMs);
+ VLOG_IF(1, !last_playout_time_.is_null())
+ << "Video frame playout time delta (compared to last frame) is "
+ << (playout_time - last_playout_time_).InMicroseconds() << " usec.";
+ last_playout_time_ = playout_time;
+
EXPECT_EQ(expected_video_frame.should_be_continuous, is_continuous);
}
@@ -425,6 +422,7 @@ class TestReceiverVideoCallback
int num_called_;
std::list<ExpectedVideoFrame> expected_frame_;
+ base::TimeTicks last_playout_time_;
};
// The actual test class, generate synthetic data for both audio and video and
@@ -466,6 +464,7 @@ class End2EndTest : public ::testing::Test {
bool external_audio_decoder,
int max_number_of_video_buffers_used) {
audio_sender_config_.rtp_config.ssrc = 1;
+ audio_sender_config_.rtp_config.max_delay_ms = kTargetPlayoutDelayMs;
audio_sender_config_.incoming_feedback_ssrc = 2;
audio_sender_config_.rtp_config.payload_type = 96;
audio_sender_config_.use_external_encoder = false;
@@ -477,6 +476,7 @@ class End2EndTest : public ::testing::Test {
audio_receiver_config_.feedback_ssrc =
audio_sender_config_.incoming_feedback_ssrc;
audio_receiver_config_.incoming_ssrc = audio_sender_config_.rtp_config.ssrc;
+ audio_receiver_config_.rtp_max_delay_ms = kTargetPlayoutDelayMs;
audio_receiver_config_.rtp_payload_type =
audio_sender_config_.rtp_config.payload_type;
audio_receiver_config_.use_external_decoder = external_audio_decoder;
@@ -488,6 +488,7 @@ class End2EndTest : public ::testing::Test {
audio_receiver_config_.frequency);
video_sender_config_.rtp_config.ssrc = 3;
+ video_sender_config_.rtp_config.max_delay_ms = kTargetPlayoutDelayMs;
video_sender_config_.incoming_feedback_ssrc = 4;
video_sender_config_.rtp_config.payload_type = 97;
video_sender_config_.use_external_encoder = false;
@@ -506,32 +507,43 @@ class End2EndTest : public ::testing::Test {
video_receiver_config_.feedback_ssrc =
video_sender_config_.incoming_feedback_ssrc;
video_receiver_config_.incoming_ssrc = video_sender_config_.rtp_config.ssrc;
+ video_receiver_config_.rtp_max_delay_ms = kTargetPlayoutDelayMs;
video_receiver_config_.rtp_payload_type =
video_sender_config_.rtp_config.payload_type;
video_receiver_config_.use_external_decoder = false;
video_receiver_config_.codec = video_sender_config_.codec;
}
- void SetSenderSkew(double skew, base::TimeDelta offset) {
- testing_clock_sender_->SetSkew(skew, offset);
- task_runner_sender_->SetSkew(1.0 / skew);
- }
-
void SetReceiverSkew(double skew, base::TimeDelta offset) {
testing_clock_receiver_->SetSkew(skew, offset);
task_runner_receiver_->SetSkew(1.0 / skew);
}
+ // Specify the minimum/maximum difference in playout times between two
+ // consecutive frames. Also, specify the maximum absolute rate of change over
+ // each three consecutive frames.
+ void SetExpectedVideoPlayoutSmoothness(base::TimeDelta min_delta,
+ base::TimeDelta max_delta,
+ base::TimeDelta max_curvature) {
+ min_video_playout_delta_ = min_delta;
+ max_video_playout_delta_ = max_delta;
+ max_video_playout_curvature_ = max_curvature;
+ }
+
void FeedAudioFrames(int count, bool will_be_checked) {
for (int i = 0; i < count; ++i) {
scoped_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus(
base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs)));
- const base::TimeTicks send_time =
+ const base::TimeTicks capture_time =
testing_clock_sender_->NowTicks() +
i * base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs);
- if (will_be_checked)
- test_receiver_audio_callback_->AddExpectedResult(*audio_bus, send_time);
- audio_frame_input_->InsertAudio(audio_bus.Pass(), send_time);
+ if (will_be_checked) {
+ test_receiver_audio_callback_->AddExpectedResult(
+ *audio_bus,
+ capture_time +
+ base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs));
+ }
+ audio_frame_input_->InsertAudio(audio_bus.Pass(), capture_time);
}
}
@@ -540,12 +552,14 @@ class End2EndTest : public ::testing::Test {
for (int i = 0; i < count; ++i) {
scoped_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus(
base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs)));
- const base::TimeTicks send_time =
+ const base::TimeTicks capture_time =
testing_clock_sender_->NowTicks() +
i * base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs);
- test_receiver_audio_callback_->AddExpectedResult(*audio_bus,
- send_time + delay);
- audio_frame_input_->InsertAudio(audio_bus.Pass(), send_time);
+ test_receiver_audio_callback_->AddExpectedResult(
+ *audio_bus,
+ capture_time + delay +
+ base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs));
+ audio_frame_input_->InsertAudio(audio_bus.Pass(), capture_time);
}
}
@@ -563,6 +577,7 @@ class End2EndTest : public ::testing::Test {
audio_receiver_config_,
video_receiver_config_,
&receiver_to_sender_);
+
net::IPEndPoint dummy_endpoint;
transport_sender_.reset(new transport::CastTransportSenderImpl(
NULL,
@@ -640,10 +655,34 @@ class End2EndTest : public ::testing::Test {
void BasicPlayerGotVideoFrame(
const scoped_refptr<media::VideoFrame>& video_frame,
- const base::TimeTicks& render_time, bool continuous) {
+ const base::TimeTicks& playout_time, bool continuous) {
+ // The following tests that the sender and receiver clocks can be
+ // out-of-sync, drift, and jitter with respect to one another; and depsite
+ // this, the receiver will produce smoothly-progressing playout times.
+ // Both first-order and second-order effects are tested.
+ if (!last_video_playout_time_.is_null() &&
+ min_video_playout_delta_ > base::TimeDelta()) {
+ const base::TimeDelta delta = playout_time - last_video_playout_time_;
+ VLOG(1) << "Video frame playout time delta (compared to last frame) is "
+ << delta.InMicroseconds() << " usec.";
+ EXPECT_LE(min_video_playout_delta_.InMicroseconds(),
+ delta.InMicroseconds());
+ EXPECT_GE(max_video_playout_delta_.InMicroseconds(),
+ delta.InMicroseconds());
+ if (last_video_playout_delta_ > base::TimeDelta()) {
+ base::TimeDelta abs_curvature = delta - last_video_playout_delta_;
+ if (abs_curvature < base::TimeDelta())
+ abs_curvature = -abs_curvature;
+ EXPECT_GE(max_video_playout_curvature_.InMicroseconds(),
+ abs_curvature.InMicroseconds());
+ }
+ last_video_playout_delta_ = delta;
+ }
+ last_video_playout_time_ = playout_time;
+
video_ticks_.push_back(std::make_pair(
testing_clock_receiver_->NowTicks(),
- render_time));
+ playout_time));
frame_receiver_->GetRawVideoFrame(
base::Bind(&End2EndTest::BasicPlayerGotVideoFrame,
base::Unretained(this)));
@@ -652,6 +691,12 @@ class End2EndTest : public ::testing::Test {
void BasicPlayerGotAudioFrame(scoped_ptr<AudioBus> audio_bus,
const base::TimeTicks& playout_time,
bool is_continuous) {
+ VLOG_IF(1, !last_audio_playout_time_.is_null())
+ << "Audio frame playout time delta (compared to last frame) is "
+ << (playout_time - last_audio_playout_time_).InMicroseconds()
+ << " usec.";
+ last_audio_playout_time_ = playout_time;
+
audio_ticks_.push_back(std::make_pair(
testing_clock_receiver_->NowTicks(),
playout_time));
@@ -704,6 +749,12 @@ class End2EndTest : public ::testing::Test {
// These run on the receiver timeline.
test::SkewedTickClock* testing_clock_receiver_;
scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
+ base::TimeDelta min_video_playout_delta_;
+ base::TimeDelta max_video_playout_delta_;
+ base::TimeDelta max_video_playout_curvature_;
+ base::TimeTicks last_video_playout_time_;
+ base::TimeDelta last_video_playout_delta_;
+ base::TimeTicks last_audio_playout_time_;
scoped_refptr<CastEnvironment> cast_environment_sender_;
scoped_refptr<CastEnvironment> cast_environment_receiver_;
@@ -755,7 +806,8 @@ TEST_F(End2EndTest, LoopNoLossPcm16) {
video_start,
video_sender_config_.width,
video_sender_config_.height,
- testing_clock_sender_->NowTicks(),
+ testing_clock_sender_->NowTicks() +
+ base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
true);
SendVideoFrame(video_start, testing_clock_sender_->NowTicks());
@@ -860,7 +912,8 @@ TEST_F(End2EndTest, DISABLED_StartSenderBeforeReceiver) {
video_start,
video_sender_config_.width,
video_sender_config_.height,
- initial_send_time + expected_delay,
+ initial_send_time + expected_delay +
+ base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
true);
SendVideoFrame(video_start, testing_clock_sender_->NowTicks());
@@ -889,7 +942,8 @@ TEST_F(End2EndTest, DISABLED_StartSenderBeforeReceiver) {
video_start,
video_sender_config_.width,
video_sender_config_.height,
- testing_clock_sender_->NowTicks(),
+ testing_clock_sender_->NowTicks() +
+ base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
true);
SendVideoFrame(video_start, testing_clock_sender_->NowTicks());
@@ -925,18 +979,18 @@ TEST_F(End2EndTest, DISABLED_GlitchWith3Buffers) {
Create();
int video_start = kVideoStart;
- base::TimeTicks send_time;
+ base::TimeTicks capture_time;
// Frames will rendered on completion until the render time stabilizes, i.e.
// we got enough data.
const int frames_before_glitch = 20;
for (int i = 0; i < frames_before_glitch; ++i) {
- send_time = testing_clock_sender_->NowTicks();
- SendVideoFrame(video_start, send_time);
+ capture_time = testing_clock_sender_->NowTicks();
+ SendVideoFrame(video_start, capture_time);
test_receiver_video_callback_->AddExpectedResult(
video_start,
video_sender_config_.width,
video_sender_config_.height,
- send_time,
+ capture_time + base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
true);
frame_receiver_->GetRawVideoFrame(
base::Bind(&TestReceiverVideoCallback::CheckVideoFrame,
@@ -948,27 +1002,28 @@ TEST_F(End2EndTest, DISABLED_GlitchWith3Buffers) {
// Introduce a glitch lasting for 10 frames.
sender_to_receiver_.SetSendPackets(false);
for (int i = 0; i < 10; ++i) {
- send_time = testing_clock_sender_->NowTicks();
+ capture_time = testing_clock_sender_->NowTicks();
// First 3 will be sent and lost.
- SendVideoFrame(video_start, send_time);
+ SendVideoFrame(video_start, capture_time);
RunTasks(kFrameTimerMs);
video_start++;
}
sender_to_receiver_.SetSendPackets(true);
RunTasks(100);
- send_time = testing_clock_sender_->NowTicks();
+ capture_time = testing_clock_sender_->NowTicks();
// Frame 1 should be acked by now and we should have an opening to send 4.
- SendVideoFrame(video_start, send_time);
+ SendVideoFrame(video_start, capture_time);
RunTasks(kFrameTimerMs);
// Frames 1-3 are old frames by now, and therefore should be decoded, but
// not rendered. The next frame we expect to render is frame #4.
- test_receiver_video_callback_->AddExpectedResult(video_start,
- video_sender_config_.width,
- video_sender_config_.height,
- send_time,
- true);
+ test_receiver_video_callback_->AddExpectedResult(
+ video_start,
+ video_sender_config_.width,
+ video_sender_config_.height,
+ capture_time + base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
+ true);
frame_receiver_->GetRawVideoFrame(
base::Bind(&TestReceiverVideoCallback::CheckVideoFrame,
@@ -989,19 +1044,20 @@ TEST_F(End2EndTest, DISABLED_DropEveryOtherFrame3Buffers) {
sender_to_receiver_.DropAllPacketsBelongingToOddFrames();
int video_start = kVideoStart;
- base::TimeTicks send_time;
+ base::TimeTicks capture_time;
int i = 0;
for (; i < 20; ++i) {
- send_time = testing_clock_sender_->NowTicks();
- SendVideoFrame(video_start, send_time);
+ capture_time = testing_clock_sender_->NowTicks();
+ SendVideoFrame(video_start, capture_time);
if (i % 2 == 0) {
test_receiver_video_callback_->AddExpectedResult(
video_start,
video_sender_config_.width,
video_sender_config_.height,
- send_time,
+ capture_time +
+ base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
i == 0);
// GetRawVideoFrame will not return the frame until we are close in
@@ -1035,14 +1091,14 @@ TEST_F(End2EndTest, CryptoVideo) {
int frames_counter = 0;
for (; frames_counter < 3; ++frames_counter) {
- const base::TimeTicks send_time = testing_clock_sender_->NowTicks();
- SendVideoFrame(frames_counter, send_time);
+ const base::TimeTicks capture_time = testing_clock_sender_->NowTicks();
+ SendVideoFrame(frames_counter, capture_time);
test_receiver_video_callback_->AddExpectedResult(
frames_counter,
video_sender_config_.width,
video_sender_config_.height,
- send_time,
+ capture_time + base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
true);
RunTasks(kFrameTimerMs);
@@ -1092,15 +1148,15 @@ TEST_F(End2EndTest, VideoLogging) {
int video_start = kVideoStart;
const int num_frames = 5;
for (int i = 0; i < num_frames; ++i) {
- base::TimeTicks send_time = testing_clock_sender_->NowTicks();
+ base::TimeTicks capture_time = testing_clock_sender_->NowTicks();
test_receiver_video_callback_->AddExpectedResult(
video_start,
video_sender_config_.width,
video_sender_config_.height,
- send_time,
+ capture_time + base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
true);
- SendVideoFrame(video_start, send_time);
+ SendVideoFrame(video_start, capture_time);
RunTasks(kFrameTimerMs);
frame_receiver_->GetRawVideoFrame(
@@ -1291,6 +1347,13 @@ TEST_F(End2EndTest, BasicFakeSoftwareVideo) {
Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1);
Create();
StartBasicPlayer();
+ SetReceiverSkew(1.0, base::TimeDelta::FromMilliseconds(1));
+
+ // Expect very smooth playout when there is no clock skew.
+ SetExpectedVideoPlayoutSmoothness(
+ base::TimeDelta::FromMilliseconds(kFrameTimerMs) * 99 / 100,
+ base::TimeDelta::FromMilliseconds(kFrameTimerMs) * 101 / 100,
+ base::TimeDelta::FromMilliseconds(kFrameTimerMs) / 100);
int frames_counter = 0;
for (; frames_counter < 1000; ++frames_counter) {
@@ -1305,7 +1368,7 @@ TEST_F(End2EndTest, ReceiverClockFast) {
Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1);
Create();
StartBasicPlayer();
- SetReceiverSkew(2.0, base::TimeDelta());
+ SetReceiverSkew(2.0, base::TimeDelta::FromMicroseconds(1234567));
int frames_counter = 0;
for (; frames_counter < 10000; ++frames_counter) {
@@ -1320,7 +1383,28 @@ TEST_F(End2EndTest, ReceiverClockSlow) {
Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1);
Create();
StartBasicPlayer();
- SetReceiverSkew(0.5, base::TimeDelta());
+ SetReceiverSkew(0.5, base::TimeDelta::FromMicroseconds(-765432));
+
+ int frames_counter = 0;
+ for (; frames_counter < 10000; ++frames_counter) {
+ SendFakeVideoFrame(testing_clock_sender_->NowTicks());
+ RunTasks(kFrameTimerMs);
+ }
+ RunTasks(2 * kFrameTimerMs + 1); // Empty the pipeline.
+ EXPECT_EQ(10000ul, video_ticks_.size());
+}
+
+TEST_F(End2EndTest, SmoothPlayoutWithFivePercentClockRateSkew) {
+ Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1);
+ Create();
+ StartBasicPlayer();
+ SetReceiverSkew(1.05, base::TimeDelta::FromMilliseconds(-42));
+
+ // Expect smooth playout when there is 5% skew.
+ SetExpectedVideoPlayoutSmoothness(
+ base::TimeDelta::FromMilliseconds(kFrameTimerMs) * 90 / 100,
+ base::TimeDelta::FromMilliseconds(kFrameTimerMs) * 110 / 100,
+ base::TimeDelta::FromMilliseconds(kFrameTimerMs) / 10);
int frames_counter = 0;
for (; frames_counter < 10000; ++frames_counter) {
« no previous file with comments | « media/cast/rtcp/rtcp_unittest.cc ('k') | media/cast/test/receiver.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698