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

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: Addressed hubbe's comments. 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
Index: media/cast/test/end2end_unittest.cc
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index 6ee722e3f859bbc4c715b4c72d583a2a9671a995..eb3821b89f3a52f9f2cc708bb00d83debeb51437 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -62,16 +62,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 approaches that eliminate 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;
@@ -80,6 +75,17 @@ 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.
+//
+// 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.
+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 +250,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 +260,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,16 +298,10 @@ 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);
EXPECT_TRUE(is_continuous);
}
@@ -357,7 +357,7 @@ class TestReceiverVideoCallback
int start_value;
int width;
int height;
- base::TimeTicks capture_time;
+ base::TimeTicks playout_time;
bool should_be_continuous;
};
@@ -366,19 +366,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_;
@@ -387,21 +387,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());
@@ -414,6 +399,11 @@ class TestReceiverVideoCallback
EXPECT_GE(I420PSNR(expected_I420_frame, video_frame), kVideoAcceptedPSNR);
+ EXPECT_NEAR(
+ (playout_time - expected_video_frame.playout_time).InMillisecondsF(),
+ 0.0,
+ kMaxAllowedPlayoutErrorMs);
+
EXPECT_EQ(expected_video_frame.should_be_continuous, is_continuous);
}
@@ -467,6 +457,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;
@@ -478,6 +469,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;
@@ -489,6 +481,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;
@@ -507,6 +500,7 @@ 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;
@@ -517,12 +511,16 @@ 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);
- 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);
}
}
@@ -531,12 +529,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);
}
}
@@ -554,6 +554,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,
@@ -704,7 +705,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());
@@ -809,7 +811,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());
@@ -838,7 +841,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());
@@ -874,18 +878,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,
@@ -897,27 +901,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,
@@ -938,19 +943,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
@@ -984,14 +990,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);
@@ -1041,15 +1047,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(

Powered by Google App Engine
This is Rietveld 408576698