diff options
author | hubbe@chromium.org <hubbe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-19 20:49:43 +0000 |
---|---|---|
committer | hubbe@chromium.org <hubbe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-19 20:49:43 +0000 |
commit | 634afa4fa9b0fbafa5c2ea4dd9ae580f0efdc9e3 (patch) | |
tree | bda404543e96affbba3a9310ea407da2508604fd /media | |
parent | d84f3af70792890d95b96bb5a753951685fabd35 (diff) | |
download | chromium_src-634afa4fa9b0fbafa5c2ea4dd9ae580f0efdc9e3.zip chromium_src-634afa4fa9b0fbafa5c2ea4dd9ae580f0efdc9e3.tar.gz chromium_src-634afa4fa9b0fbafa5c2ea4dd9ae580f0efdc9e3.tar.bz2 |
Cast: Add tests for clocks being slow/fast
Fix the clock framework in end2end test to allow properly different clocks for sender and receiver.
Make the fake video codec behave more like our other codecs. (Instead of acting like 3-buffer mode)
Review URL: https://codereview.chromium.org/289083002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271475 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/cast/cast_testing.gypi | 4 | ||||
-rw-r--r-- | media/cast/test/end2end_unittest.cc | 172 | ||||
-rw-r--r-- | media/cast/test/fake_single_thread_task_runner.cc | 40 | ||||
-rw-r--r-- | media/cast/test/fake_single_thread_task_runner.h | 4 | ||||
-rw-r--r-- | media/cast/test/skewed_single_thread_task_runner.cc | 53 | ||||
-rw-r--r-- | media/cast/test/skewed_single_thread_task_runner.h | 58 | ||||
-rw-r--r-- | media/cast/test/skewed_tick_clock.cc | 38 | ||||
-rw-r--r-- | media/cast/test/skewed_tick_clock.h | 44 | ||||
-rw-r--r-- | media/cast/test/utility/udp_proxy.cc | 26 | ||||
-rw-r--r-- | media/cast/test/utility/udp_proxy.h | 8 | ||||
-rw-r--r-- | media/cast/video_sender/fake_software_video_encoder.cc | 2 |
11 files changed, 400 insertions, 49 deletions
diff --git a/media/cast/cast_testing.gypi b/media/cast/cast_testing.gypi index 8c6e35bd..666b582 100644 --- a/media/cast/cast_testing.gypi +++ b/media/cast/cast_testing.gypi @@ -20,6 +20,10 @@ 'sources': [ 'test/fake_single_thread_task_runner.cc', 'test/fake_single_thread_task_runner.h', + 'test/skewed_single_thread_task_runner.cc', + 'test/skewed_single_thread_task_runner.h', + 'test/skewed_tick_clock.cc', + 'test/skewed_tick_clock.h', 'test/utility/audio_utility.cc', 'test/utility/audio_utility.h', 'test/utility/barcode.cc', diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc index 6ee722e..e668ed6 100644 --- a/media/cast/test/end2end_unittest.cc +++ b/media/cast/test/end2end_unittest.cc @@ -31,6 +31,8 @@ #include "media/cast/cast_sender.h" #include "media/cast/logging/simple_event_subscriber.h" #include "media/cast/test/fake_single_thread_task_runner.h" +#include "media/cast/test/skewed_single_thread_task_runner.h" +#include "media/cast/test/skewed_tick_clock.h" #include "media/cast/test/utility/audio_utility.h" #include "media/cast/test/utility/default_config.h" #include "media/cast/test/utility/udp_proxy.h" @@ -158,14 +160,10 @@ std::map<uint16, LoggingEventCounts> GetEventCountForPacketEvents( return event_counter_for_packet; } -void CountVideoFrame(int* counter, - const scoped_refptr<media::VideoFrame>& video_frame, - const base::TimeTicks& render_time, bool continuous) { - ++*counter; -} - } // namespace +// Shim that turns forwards packets from a test::PacketPipe to a +// PacketReceiverCallback. class LoopBackPacketPipe : public test::PacketPipe { public: LoopBackPacketPipe(const transport::PacketReceiverCallback& packet_receiver) @@ -192,7 +190,9 @@ class LoopBackTransport : public transport::PacketSender { cast_environment_(cast_environment) {} void SetPacketReceiver( - const transport::PacketReceiverCallback& packet_receiver) { + const transport::PacketReceiverCallback& packet_receiver, + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + base::TickClock* clock) { scoped_ptr<test::PacketPipe> loopback_pipe( new LoopBackPacketPipe(packet_receiver)); if (packet_pipe_) { @@ -200,6 +200,7 @@ class LoopBackTransport : public transport::PacketSender { } else { packet_pipe_ = loopback_pipe.Pass(); } + packet_pipe_->InitOnIOThread(task_runner, clock); } virtual bool SendPacket(transport::PacketRef packet, @@ -435,27 +436,28 @@ class End2EndTest : public ::testing::Test { protected: End2EndTest() : start_time_(), - testing_clock_sender_(new base::SimpleTestTickClock()), - testing_clock_receiver_(new base::SimpleTestTickClock()), - task_runner_( - new test::FakeSingleThreadTaskRunner(testing_clock_sender_)), + task_runner_(new test::FakeSingleThreadTaskRunner(&testing_clock_)), + testing_clock_sender_(new test::SkewedTickClock(&testing_clock_)), + task_runner_sender_( + new test::SkewedSingleThreadTaskRunner(task_runner_)), + testing_clock_receiver_(new test::SkewedTickClock(&testing_clock_)), + task_runner_receiver_( + new test::SkewedSingleThreadTaskRunner(task_runner_)), cast_environment_sender_(new CastEnvironment( scoped_ptr<base::TickClock>(testing_clock_sender_).Pass(), - task_runner_, - task_runner_, - task_runner_)), + task_runner_sender_, + task_runner_sender_, + task_runner_sender_)), cast_environment_receiver_(new CastEnvironment( scoped_ptr<base::TickClock>(testing_clock_receiver_).Pass(), - task_runner_, - task_runner_, - task_runner_)), + task_runner_receiver_, + task_runner_receiver_, + task_runner_receiver_)), receiver_to_sender_(cast_environment_receiver_), sender_to_receiver_(cast_environment_sender_), test_receiver_audio_callback_(new TestReceiverAudioCallback()), test_receiver_video_callback_(new TestReceiverVideoCallback()) { - testing_clock_sender_->Advance( - base::TimeDelta::FromMilliseconds(kStartMillisecond)); - testing_clock_receiver_->Advance( + testing_clock_.Advance( base::TimeDelta::FromMilliseconds(kStartMillisecond)); cast_environment_sender_->Logging()->AddRawEventSubscriber( &event_subscriber_sender_); @@ -513,6 +515,16 @@ class End2EndTest : public ::testing::Test { 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); + } + void FeedAudioFrames(int count, bool will_be_checked) { for (int i = 0; i < count; ++i) { scoped_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus( @@ -562,7 +574,7 @@ class End2EndTest : public ::testing::Test { base::Bind(&UpdateCastTransportStatus), base::Bind(&End2EndTest::LogRawEvents, base::Unretained(this)), base::TimeDelta::FromSeconds(1), - task_runner_, + task_runner_sender_, &sender_to_receiver_)); cast_sender_ = @@ -576,8 +588,12 @@ class End2EndTest : public ::testing::Test { CreateDefaultVideoEncodeAcceleratorCallback(), CreateDefaultVideoEncodeMemoryCallback()); - receiver_to_sender_.SetPacketReceiver(cast_sender_->packet_receiver()); - sender_to_receiver_.SetPacketReceiver(cast_receiver_->packet_receiver()); + receiver_to_sender_.SetPacketReceiver(cast_sender_->packet_receiver(), + task_runner_, + &testing_clock_); + sender_to_receiver_.SetPacketReceiver(cast_receiver_->packet_receiver(), + task_runner_, + &testing_clock_); audio_frame_input_ = cast_sender_->audio_frame_input(); video_frame_input_ = cast_sender_->video_frame_input(); @@ -621,13 +637,39 @@ class End2EndTest : public ::testing::Test { media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)), capture_time); } - void RunTasks(int during_ms) { - for (int i = 0; i < during_ms; ++i) { - // Call process the timers every 1 ms. - testing_clock_sender_->Advance(base::TimeDelta::FromMilliseconds(1)); - testing_clock_receiver_->Advance(base::TimeDelta::FromMilliseconds(1)); - task_runner_->RunTasks(); - } + void RunTasks(int ms) { + task_runner_->Sleep(base::TimeDelta::FromMilliseconds(ms)); + } + + void BasicPlayerGotVideoFrame( + const scoped_refptr<media::VideoFrame>& video_frame, + const base::TimeTicks& render_time, bool continuous) { + video_ticks_.push_back(std::make_pair( + testing_clock_receiver_->NowTicks(), + render_time)); + frame_receiver_->GetRawVideoFrame( + base::Bind(&End2EndTest::BasicPlayerGotVideoFrame, + base::Unretained(this))); + } + + void BasicPlayerGotAudioFrame(scoped_ptr<AudioBus> audio_bus, + const base::TimeTicks& playout_time, + bool is_continuous) { + audio_ticks_.push_back(std::make_pair( + testing_clock_receiver_->NowTicks(), + playout_time)); + frame_receiver_->GetRawAudioFrame( + base::Bind(&End2EndTest::BasicPlayerGotAudioFrame, + base::Unretained(this))); + } + + void StartBasicPlayer() { + frame_receiver_->GetRawVideoFrame( + base::Bind(&End2EndTest::BasicPlayerGotVideoFrame, + base::Unretained(this))); + frame_receiver_->GetRawAudioFrame( + base::Bind(&End2EndTest::BasicPlayerGotAudioFrame, + base::Unretained(this))); } void LogRawEvents(const std::vector<PacketEvent>& packet_events) { @@ -653,9 +695,19 @@ class End2EndTest : public ::testing::Test { VideoSenderConfig video_sender_config_; base::TimeTicks start_time_; - base::SimpleTestTickClock* testing_clock_sender_; - base::SimpleTestTickClock* testing_clock_receiver_; + + // These run in "test time" + base::SimpleTestTickClock testing_clock_; scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; + + // These run on the sender timeline. + test::SkewedTickClock* testing_clock_sender_; + scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_; + + // These run on the receiver timeline. + test::SkewedTickClock* testing_clock_receiver_; + scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_; + scoped_refptr<CastEnvironment> cast_environment_sender_; scoped_refptr<CastEnvironment> cast_environment_receiver_; @@ -677,6 +729,8 @@ class End2EndTest : public ::testing::Test { SimpleEventSubscriber event_subscriber_sender_; std::vector<FrameEvent> frame_events_; std::vector<PacketEvent> packet_events_; + std::vector<std::pair<base::TimeTicks, base::TimeTicks> > audio_ticks_; + std::vector<std::pair<base::TimeTicks, base::TimeTicks> > video_ticks_; // |transport_sender_| has a RepeatingTimer which needs a MessageLoop. base::MessageLoop message_loop_; }; @@ -1239,17 +1293,63 @@ TEST_F(End2EndTest, AudioLogging) { TEST_F(End2EndTest, BasicFakeSoftwareVideo) { Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1); Create(); + StartBasicPlayer(); int frames_counter = 0; - int received_counter = 0; for (; frames_counter < 1000; ++frames_counter) { SendFakeVideoFrame(testing_clock_sender_->NowTicks()); - frame_receiver_->GetRawVideoFrame( - base::Bind(&CountVideoFrame, &received_counter)); RunTasks(kFrameTimerMs); } RunTasks(2 * kFrameTimerMs + 1); // Empty the pipeline. - EXPECT_EQ(1000, received_counter); + EXPECT_EQ(1000ul, video_ticks_.size()); +} + +TEST_F(End2EndTest, ReceiverClockFast) { + Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1); + Create(); + StartBasicPlayer(); + SetReceiverSkew(2.0, base::TimeDelta()); + + 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, ReceiverClockSlow) { + Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1); + Create(); + StartBasicPlayer(); + SetReceiverSkew(0.5, base::TimeDelta()); + + 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, EvilNetwork) { + Configure(transport::kFakeSoftwareVideo, transport::kPcm16, 32000, false, 1); + receiver_to_sender_.SetPacketPipe(test::EvilNetwork().Pass()); + sender_to_receiver_.SetPacketPipe(test::EvilNetwork().Pass()); + Create(); + StartBasicPlayer(); + + int frames_counter = 0; + for (; frames_counter < 10000; ++frames_counter) { + SendFakeVideoFrame(testing_clock_sender_->NowTicks()); + RunTasks(kFrameTimerMs); + } + base::TimeTicks test_end = testing_clock_receiver_->NowTicks(); + RunTasks(100 * kFrameTimerMs + 1); // Empty the pipeline. + EXPECT_GT(video_ticks_.size(), 100ul); + EXPECT_LT((video_ticks_.back().second - test_end).InMilliseconds(), 1000); } // TODO(pwestin): Add repeatable packet loss test. diff --git a/media/cast/test/fake_single_thread_task_runner.cc b/media/cast/test/fake_single_thread_task_runner.cc index d2950fd..b60a1b1 100644 --- a/media/cast/test/fake_single_thread_task_runner.cc +++ b/media/cast/test/fake_single_thread_task_runner.cc @@ -14,7 +14,8 @@ namespace test { FakeSingleThreadTaskRunner::FakeSingleThreadTaskRunner( base::SimpleTestTickClock* clock) - : clock_(clock) {} + : clock_(clock), + fail_on_next_task_(false) {} FakeSingleThreadTaskRunner::~FakeSingleThreadTaskRunner() {} @@ -22,6 +23,9 @@ bool FakeSingleThreadTaskRunner::PostDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, base::TimeDelta delay) { + if (fail_on_next_task_) { + LOG(FATAL) << "Infinite task-add loop detected."; + } EXPECT_GE(delay, base::TimeDelta()); PostedTask posed_task(from_here, task, @@ -38,7 +42,7 @@ bool FakeSingleThreadTaskRunner::RunsTasksOnCurrentThread() const { } void FakeSingleThreadTaskRunner::RunTasks() { - while(true) { + while (true) { // Run all tasks equal or older than current time. std::multimap<base::TimeTicks, PostedTask>::iterator it = tasks_.begin(); if (it == tasks_.end()) @@ -53,6 +57,38 @@ void FakeSingleThreadTaskRunner::RunTasks() { } } +void FakeSingleThreadTaskRunner::Sleep(base::TimeDelta t) { + base::TimeTicks run_until = clock_->NowTicks() + t; + while (1) { + // If we run more than 100000 iterations, we've probably + // hit some sort of case where a new task is posted every + // time that we invoke a task, and we can't make progress + // anymore. If that happens, set fail_on_next_task_ to true + // and throw an error when the next task is posted. + for (int i = 0; i < 100000; i++) { + // Run all tasks equal or older than current time. + std::multimap<base::TimeTicks, PostedTask>::iterator it = tasks_.begin(); + if (it == tasks_.end()) { + clock_->Advance(run_until - clock_->NowTicks()); + return; + } + + PostedTask task = it->second; + if (run_until < task.GetTimeToRun()) { + clock_->Advance(run_until - clock_->NowTicks()); + return; + } + + clock_->Advance(task.GetTimeToRun() - clock_->NowTicks()); + tasks_.erase(it); + task.task.Run(); + } + // Instead of failing immediately, we fail when the next task is + // added so that the backtrace will include the task that was added. + fail_on_next_task_ = true; + } +} + bool FakeSingleThreadTaskRunner::PostNonNestableDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, diff --git a/media/cast/test/fake_single_thread_task_runner.h b/media/cast/test/fake_single_thread_task_runner.h index 7101385..779a897 100644 --- a/media/cast/test/fake_single_thread_task_runner.h +++ b/media/cast/test/fake_single_thread_task_runner.h @@ -24,6 +24,9 @@ class FakeSingleThreadTaskRunner : public base::SingleThreadTaskRunner { void RunTasks(); + // Note: Advances |clock_|. + void Sleep(base::TimeDelta t); + // base::SingleThreadTaskRunner implementation. virtual bool PostDelayedTask(const tracked_objects::Location& from_here, const base::Closure& task, @@ -43,6 +46,7 @@ class FakeSingleThreadTaskRunner : public base::SingleThreadTaskRunner { private: base::SimpleTestTickClock* const clock_; std::multimap<base::TimeTicks, PostedTask> tasks_; + bool fail_on_next_task_; DISALLOW_COPY_AND_ASSIGN(FakeSingleThreadTaskRunner); }; diff --git a/media/cast/test/skewed_single_thread_task_runner.cc b/media/cast/test/skewed_single_thread_task_runner.cc new file mode 100644 index 0000000..fda7dfb --- /dev/null +++ b/media/cast/test/skewed_single_thread_task_runner.cc @@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/test/skewed_single_thread_task_runner.h" + +#include "base/logging.h" +#include "base/time/tick_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { +namespace cast { +namespace test { + +SkewedSingleThreadTaskRunner::SkewedSingleThreadTaskRunner( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) : + skew_(1.0), + task_runner_(task_runner) { +} + +SkewedSingleThreadTaskRunner::~SkewedSingleThreadTaskRunner() {} + +void SkewedSingleThreadTaskRunner::SetSkew(double skew) { + skew_ = skew; +} + +bool SkewedSingleThreadTaskRunner::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return task_runner_->PostDelayedTask( + from_here, + task, + base::TimeDelta::FromMicroseconds(delay.InMicroseconds() * skew_)); +} + +bool SkewedSingleThreadTaskRunner::RunsTasksOnCurrentThread() const { + return task_runner_->RunsTasksOnCurrentThread(); +} + +bool SkewedSingleThreadTaskRunner::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) { + return task_runner_->PostNonNestableDelayedTask( + from_here, + task, + base::TimeDelta::FromMicroseconds(delay.InMicroseconds() * skew_)); +} + +} // namespace test +} // namespace cast +} // namespace media diff --git a/media/cast/test/skewed_single_thread_task_runner.h b/media/cast/test/skewed_single_thread_task_runner.h new file mode 100644 index 0000000..5ad2f8d --- /dev/null +++ b/media/cast/test/skewed_single_thread_task_runner.h @@ -0,0 +1,58 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAST_TEST_SKEWED_TASK_RUNNER_H_ +#define MEDIA_CAST_TEST_SKEWED_TASK_RUNNER_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/single_thread_task_runner.h" +#include "base/test/simple_test_tick_clock.h" +#include "base/test/test_pending_task.h" + +namespace media { +namespace cast { +namespace test { + +// This class wraps a SingleThreadTaskRunner, and allows you to scale +// the delay for any posted task by a factor. The factor is changed by +// calling SetSkew(). A skew of 2.0 means that all delayed task will +// have to wait twice as long. +class SkewedSingleThreadTaskRunner : public base::SingleThreadTaskRunner { + public: + explicit SkewedSingleThreadTaskRunner( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + + // Set the delay multiplier to |skew|. + void SetSkew(double skew); + + // base::SingleThreadTaskRunner implementation. + virtual bool PostDelayedTask(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) OVERRIDE; + + virtual bool RunsTasksOnCurrentThread() const OVERRIDE; + + // This function is currently not used, and will return false. + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay) OVERRIDE; + + protected: + virtual ~SkewedSingleThreadTaskRunner(); + + private: + double skew_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + DISALLOW_COPY_AND_ASSIGN(SkewedSingleThreadTaskRunner); +}; + +} // namespace test +} // namespace cast +} // namespace media + +#endif // MEDIA_CAST_TEST_SKEWED_TASK_RUNNER_H_ diff --git a/media/cast/test/skewed_tick_clock.cc b/media/cast/test/skewed_tick_clock.cc new file mode 100644 index 0000000..fd3fb3c --- /dev/null +++ b/media/cast/test/skewed_tick_clock.cc @@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/test/skewed_tick_clock.h" + +#include "base/time/time.h" + +namespace media { +namespace cast { +namespace test { + +SkewedTickClock::SkewedTickClock(base::TickClock* clock) + : clock_(clock), + skew_(1.0), + last_skew_set_time_(clock_->NowTicks()), + skew_clock_at_last_set_(last_skew_set_time_) { +} + +base::TimeTicks SkewedTickClock::SkewTicks(base::TimeTicks now) { + return base::TimeDelta::FromMicroseconds( + (now - last_skew_set_time_).InMicroseconds() * skew_) + + skew_clock_at_last_set_; +} + +void SkewedTickClock::SetSkew(double skew, base::TimeDelta offset) { + base::TimeTicks now = clock_->NowTicks(); + last_skew_set_time_ = now; + skew_clock_at_last_set_ = SkewTicks(now) + offset; +} + +base::TimeTicks SkewedTickClock::NowTicks() { + return SkewTicks(clock_->NowTicks()); +} + +} // namespace test +} // namespace cast +} // namespace media diff --git a/media/cast/test/skewed_tick_clock.h b/media/cast/test/skewed_tick_clock.h new file mode 100644 index 0000000..dcb5384 --- /dev/null +++ b/media/cast/test/skewed_tick_clock.h @@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CAST_MEDIA_TEST_SKEWED_TICK_CLOCK_H +#define CAST_MEDIA_TEST_SKEWED_TICK_CLOCK_H + +#include "base/time/tick_clock.h" +#include "base/time/time.h" + +namespace media { +namespace cast { +namespace test { + +// Wraps a base::TickClock, and lets you change the speed and offset +// of time compared to the wrapped clock. See SetSkew for how usage. +class SkewedTickClock : public base::TickClock { + public: + // Does not take ownership of |clock_|. + explicit SkewedTickClock(base::TickClock* clock_); + // |skew| > 1.0 means clock runs faster. + // |offset| > 0 means clock returns times from the future. + // Note, |offset| is cumulative. + // Also note that changing the skew will never make the clock + // jump forwards or backwards, only changing the offset will + // do that. + void SetSkew(double skew, base::TimeDelta offset); + virtual base::TimeTicks NowTicks() OVERRIDE; + + private: + base::TimeTicks SkewTicks(base::TimeTicks now); + base::TickClock* clock_; // Not owned. + double skew_; + base::TimeTicks last_skew_set_time_; + base::TimeTicks skew_clock_at_last_set_; + + DISALLOW_COPY_AND_ASSIGN(SkewedTickClock); +}; + +} // namespace test +} // namespace cast +} // namespace media + +#endif // CAST_MEDIA_TEST_SKEWED_TICK_CLOCK_H diff --git a/media/cast/test/utility/udp_proxy.cc b/media/cast/test/utility/udp_proxy.cc index f0bb4f6..99baec2 100644 --- a/media/cast/test/utility/udp_proxy.cc +++ b/media/cast/test/utility/udp_proxy.cc @@ -9,6 +9,7 @@ #include "base/rand_util.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" +#include "base/time/default_tick_clock.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/udp/udp_socket.h" @@ -22,10 +23,12 @@ const size_t kMaxPacketSize = 65536; PacketPipe::PacketPipe() {} PacketPipe::~PacketPipe() {} void PacketPipe::InitOnIOThread( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + base::TickClock* clock) { task_runner_ = task_runner; + clock_ = clock; if (pipe_) { - pipe_->InitOnIOThread(task_runner); + pipe_->InitOnIOThread(task_runner, clock); } } void PacketPipe::AppendToPipe(scoped_ptr<PacketPipe> pipe) { @@ -183,8 +186,9 @@ class RandomSortedDelay : public PacketPipe { } } virtual void InitOnIOThread( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) OVERRIDE { - PacketPipe::InitOnIOThread(task_runner); + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + base::TickClock* clock) OVERRIDE { + PacketPipe::InitOnIOThread(task_runner, clock); // As we start the stream, assume that we are in a random // place between two extra delays, thus multiplier = 1.0; ScheduleExtraDelay(1.0); @@ -202,7 +206,7 @@ class RandomSortedDelay : public PacketPipe { } void CauseExtraDelay() { - block_until_ = base::TimeTicks::Now() + + block_until_ = clock_->NowTicks() + base::TimeDelta::FromMicroseconds( static_cast<int64>(extra_delay_ * 1E6)); // An extra delay just happened, wait up to seconds_between_extra_delay_*2 @@ -264,8 +268,9 @@ class NetworkGlitchPipe : public PacketPipe { weak_factory_(this) {} virtual void InitOnIOThread( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) OVERRIDE { - PacketPipe::InitOnIOThread(task_runner); + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + base::TickClock* clock) OVERRIDE { + PacketPipe::InitOnIOThread(task_runner, clock); Flip(); } @@ -466,8 +471,10 @@ class UDPProxyImpl : public UDPProxy { BuildPipe(&to_dest_pipe_, new PacketSender(socket_.get(), &destination_)); BuildPipe(&from_dest_pipe_, new PacketSender(socket_.get(), &return_address_)); - to_dest_pipe_->InitOnIOThread(base::MessageLoopProxy::current()); - from_dest_pipe_->InitOnIOThread(base::MessageLoopProxy::current()); + to_dest_pipe_->InitOnIOThread(base::MessageLoopProxy::current(), + &tick_clock_); + from_dest_pipe_->InitOnIOThread(base::MessageLoopProxy::current(), + &tick_clock_); VLOG(0) << "From:" << local_port_.ToString(); VLOG(0) << "To:" << destination_.ToString(); @@ -531,6 +538,7 @@ class UDPProxyImpl : public UDPProxy { } + base::DefaultTickClock tick_clock_; net::IPEndPoint local_port_; net::IPEndPoint destination_; bool destination_is_mutable_; diff --git a/media/cast/test/utility/udp_proxy.h b/media/cast/test/utility/udp_proxy.h index 6d2f70c..b102573 100644 --- a/media/cast/test/utility/udp_proxy.h +++ b/media/cast/test/utility/udp_proxy.h @@ -18,6 +18,10 @@ namespace net { class NetLog; }; +namespace base { +class TickClock; +}; + namespace media { namespace cast { namespace test { @@ -29,12 +33,14 @@ class PacketPipe { virtual void Send(scoped_ptr<transport::Packet> packet) = 0; // Allows injection of fake test runner for testing. virtual void InitOnIOThread( - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + base::TickClock* clock); virtual void AppendToPipe(scoped_ptr<PacketPipe> pipe); protected: scoped_ptr<PacketPipe> pipe_; // Allows injection of fake task runner for testing. scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + base::TickClock* clock_; }; // A UDPProxy will set up a UDP socket and bind to |local_port|. diff --git a/media/cast/video_sender/fake_software_video_encoder.cc b/media/cast/video_sender/fake_software_video_encoder.cc index 0df0d6e..3afd858 100644 --- a/media/cast/video_sender/fake_software_video_encoder.cc +++ b/media/cast/video_sender/fake_software_video_encoder.cc @@ -30,7 +30,7 @@ bool FakeSoftwareVideoEncoder::Encode( encoded_image->key_frame = next_frame_is_key_; next_frame_is_key_ = false; encoded_image->frame_id = frame_id_++; - encoded_image->last_referenced_frame_id = frame_id_to_reference_; + encoded_image->last_referenced_frame_id = encoded_image->frame_id - 1; base::DictionaryValue values; values.Set("key", base::Value::CreateBooleanValue(encoded_image->key_frame)); |