| Index: media/cast/video_receiver/video_receiver_unittest.cc
|
| diff --git a/media/cast/video_receiver/video_receiver_unittest.cc b/media/cast/video_receiver/video_receiver_unittest.cc
|
| index 7bea5013201821f60e934d4451c6f3bd11a214c9..4fe834ce889fb4d7b7f875c12422995dfcb86094 100644
|
| --- a/media/cast/video_receiver/video_receiver_unittest.cc
|
| +++ b/media/cast/video_receiver/video_receiver_unittest.cc
|
| @@ -2,8 +2,6 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include <stdint.h>
|
| -
|
| #include "base/bind.h"
|
| #include "base/memory/ref_counted.h"
|
| #include "base/memory/scoped_ptr.h"
|
| @@ -16,45 +14,47 @@
|
| #include "media/cast/video_receiver/video_receiver.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
|
|
| -static const int kPacketSize = 1500;
|
| -static const int64 kStartMillisecond = INT64_C(12345678900000);
|
| -
|
| namespace media {
|
| namespace cast {
|
|
|
| -using testing::_;
|
| +using ::testing::_;
|
|
|
| namespace {
|
| -// Was thread counted thread safe.
|
| -class TestVideoReceiverCallback
|
| - : public base::RefCountedThreadSafe<TestVideoReceiverCallback> {
|
| +
|
| +const int kPacketSize = 1500;
|
| +const int64 kStartMillisecond = INT64_C(12345678900000);
|
| +const uint32 kFirstFrameId = 1234;
|
| +
|
| +class FakeVideoClient {
|
| public:
|
| - TestVideoReceiverCallback() : num_called_(0) {}
|
| + FakeVideoClient() : num_called_(0) {}
|
| + virtual ~FakeVideoClient() {}
|
|
|
| - // TODO(mikhal): Set and check expectations.
|
| - void DecodeComplete(const scoped_refptr<media::VideoFrame>& video_frame,
|
| - const base::TimeTicks& render_time) {
|
| - ++num_called_;
|
| + void SetNextExpectedResult(uint32 expected_frame_id,
|
| + const base::TimeTicks& expected_playout_time) {
|
| + expected_frame_id_ = expected_frame_id;
|
| + expected_playout_time_ = expected_playout_time;
|
| }
|
|
|
| - void FrameToDecode(scoped_ptr<transport::EncodedVideoFrame> video_frame,
|
| - const base::TimeTicks& render_time) {
|
| - EXPECT_TRUE(video_frame->key_frame);
|
| + void DeliverEncodedVideoFrame(
|
| + scoped_ptr<transport::EncodedVideoFrame> video_frame,
|
| + const base::TimeTicks& playout_time) {
|
| + ASSERT_FALSE(!video_frame)
|
| + << "If at shutdown: There were unsatisfied requests enqueued.";
|
| + EXPECT_EQ(expected_frame_id_, video_frame->frame_id);
|
| EXPECT_EQ(transport::kVp8, video_frame->codec);
|
| + EXPECT_EQ(expected_playout_time_, playout_time);
|
| ++num_called_;
|
| }
|
|
|
| int number_times_called() const { return num_called_; }
|
|
|
| - protected:
|
| - virtual ~TestVideoReceiverCallback() {}
|
| -
|
| private:
|
| - friend class base::RefCountedThreadSafe<TestVideoReceiverCallback>;
|
| -
|
| int num_called_;
|
| + uint32 expected_frame_id_;
|
| + base::TimeTicks expected_playout_time_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(TestVideoReceiverCallback);
|
| + DISALLOW_COPY_AND_ASSIGN(FakeVideoClient);
|
| };
|
| } // namespace
|
|
|
| @@ -62,88 +62,85 @@ class VideoReceiverTest : public ::testing::Test {
|
| protected:
|
| VideoReceiverTest() {
|
| // Configure to use vp8 software implementation.
|
| - config_.codec = transport::kVp8;
|
| + config_.rtp_max_delay_ms = 100;
|
| config_.use_external_decoder = false;
|
| + // Note: Frame rate must divide 1000 without remainder so the test code
|
| + // doesn't have to account for rounding errors.
|
| + config_.max_frame_rate = 25;
|
| + config_.codec = transport::kVp8;
|
| testing_clock_ = new base::SimpleTestTickClock();
|
| + testing_clock_->Advance(
|
| + base::TimeDelta::FromMilliseconds(kStartMillisecond));
|
| task_runner_ = new test::FakeSingleThreadTaskRunner(testing_clock_);
|
| +
|
| cast_environment_ =
|
| new CastEnvironment(scoped_ptr<base::TickClock>(testing_clock_).Pass(),
|
| task_runner_,
|
| task_runner_,
|
| task_runner_);
|
| +
|
| receiver_.reset(new VideoReceiver(
|
| - cast_environment_, config_, &mock_transport_, target_delay_cb_));
|
| - testing_clock_->Advance(
|
| - base::TimeDelta::FromMilliseconds(kStartMillisecond));
|
| - video_receiver_callback_ = new TestVideoReceiverCallback();
|
| + cast_environment_, config_, &mock_transport_));
|
| + }
|
|
|
| + virtual ~VideoReceiverTest() {}
|
| +
|
| + virtual void SetUp() {
|
| payload_.assign(kPacketSize, 0);
|
|
|
| // Always start with a key frame.
|
| rtp_header_.is_key_frame = true;
|
| - rtp_header_.frame_id = 1234;
|
| + rtp_header_.frame_id = kFirstFrameId;
|
| rtp_header_.packet_id = 0;
|
| rtp_header_.max_packet_id = 0;
|
| rtp_header_.is_reference = false;
|
| rtp_header_.reference_frame_id = 0;
|
| - rtp_header_.webrtc.header.timestamp = 9000;
|
| + rtp_header_.webrtc.header.timestamp = 0;
|
| }
|
|
|
| - virtual ~VideoReceiverTest() {}
|
| + void FeedOneFrameIntoReceiver() {
|
| + receiver_->OnReceivedPayloadData(
|
| + payload_.data(), payload_.size(), rtp_header_);
|
| + }
|
|
|
| - transport::MockPacedPacketSender mock_transport_;
|
| VideoReceiverConfig config_;
|
| - scoped_ptr<VideoReceiver> receiver_;
|
| std::vector<uint8> payload_;
|
| RtpCastHeader rtp_header_;
|
| base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment.
|
| -
|
| + transport::MockPacedPacketSender mock_transport_;
|
| scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
|
| scoped_refptr<CastEnvironment> cast_environment_;
|
| - scoped_refptr<TestVideoReceiverCallback> video_receiver_callback_;
|
| - SetTargetDelayCallback target_delay_cb_;
|
| + FakeVideoClient fake_video_client_;
|
| +
|
| + // Important for the VideoReceiver to be declared last, since its dependencies
|
| + // must remain alive until after its destruction.
|
| + scoped_ptr<VideoReceiver> receiver_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(VideoReceiverTest);
|
| };
|
|
|
| -TEST_F(VideoReceiverTest, GetOnePacketEncodedframe) {
|
| - EXPECT_CALL(mock_transport_, SendRtcpPacket(_))
|
| - .WillRepeatedly(testing::Return(true));
|
| - receiver_->OnReceivedPayloadData(
|
| - payload_.data(), payload_.size(), rtp_header_);
|
| -
|
| - VideoFrameEncodedCallback frame_to_decode_callback = base::Bind(
|
| - &TestVideoReceiverCallback::FrameToDecode, video_receiver_callback_);
|
| -
|
| - receiver_->GetEncodedVideoFrame(frame_to_decode_callback);
|
| - task_runner_->RunTasks();
|
| - EXPECT_EQ(video_receiver_callback_->number_times_called(), 1);
|
| -}
|
| -
|
| -TEST_F(VideoReceiverTest, MultiplePackets) {
|
| +TEST_F(VideoReceiverTest, GetOnePacketEncodedFrame) {
|
| SimpleEventSubscriber event_subscriber;
|
| cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber);
|
|
|
| EXPECT_CALL(mock_transport_, SendRtcpPacket(_))
|
| .WillRepeatedly(testing::Return(true));
|
| - rtp_header_.max_packet_id = 2;
|
| - receiver_->OnReceivedPayloadData(
|
| - payload_.data(), payload_.size(), rtp_header_);
|
| - ++rtp_header_.packet_id;
|
| - ++rtp_header_.webrtc.header.sequenceNumber;
|
| - receiver_->OnReceivedPayloadData(
|
| - payload_.data(), payload_.size(), rtp_header_);
|
| - ++rtp_header_.packet_id;
|
| - receiver_->OnReceivedPayloadData(
|
| - payload_.data(), payload_.size(), rtp_header_);
|
| -
|
| - VideoFrameEncodedCallback frame_to_decode_callback = base::Bind(
|
| - &TestVideoReceiverCallback::FrameToDecode, video_receiver_callback_);
|
| -
|
| - receiver_->GetEncodedVideoFrame(frame_to_decode_callback);
|
|
|
| + // Enqueue a request for a video frame.
|
| + receiver_->GetEncodedVideoFrame(
|
| + base::Bind(&FakeVideoClient::DeliverEncodedVideoFrame,
|
| + base::Unretained(&fake_video_client_)));
|
| +
|
| + // The request should not be satisfied since no packets have been received.
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(0, fake_video_client_.number_times_called());
|
| +
|
| + // Deliver one video frame to the receiver and expect to get one frame back.
|
| + fake_video_client_.SetNextExpectedResult(kFirstFrameId,
|
| + testing_clock_->NowTicks());
|
| + FeedOneFrameIntoReceiver();
|
| task_runner_->RunTasks();
|
| - EXPECT_EQ(video_receiver_callback_->number_times_called(), 1);
|
| + EXPECT_EQ(1, fake_video_client_.number_times_called());
|
|
|
| std::vector<FrameEvent> frame_events;
|
| event_subscriber.GetFrameEventsAndReset(&frame_events);
|
| @@ -153,23 +150,89 @@ TEST_F(VideoReceiverTest, MultiplePackets) {
|
| EXPECT_EQ(rtp_header_.frame_id, frame_events.begin()->frame_id);
|
| EXPECT_EQ(rtp_header_.webrtc.header.timestamp,
|
| frame_events.begin()->rtp_timestamp);
|
| +
|
| cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber);
|
| }
|
|
|
| -TEST_F(VideoReceiverTest, GetOnePacketRawframe) {
|
| +TEST_F(VideoReceiverTest, MultiplePendingGetCalls) {
|
| EXPECT_CALL(mock_transport_, SendRtcpPacket(_))
|
| .WillRepeatedly(testing::Return(true));
|
| - receiver_->OnReceivedPayloadData(
|
| - payload_.data(), payload_.size(), rtp_header_);
|
| - // Decode error - requires legal input.
|
| - VideoFrameDecodedCallback frame_decoded_callback = base::Bind(
|
| - &TestVideoReceiverCallback::DecodeComplete, video_receiver_callback_);
|
| - receiver_->GetRawVideoFrame(frame_decoded_callback);
|
| +
|
| + // Enqueue a request for an video frame.
|
| + const VideoFrameEncodedCallback frame_encoded_callback =
|
| + base::Bind(&FakeVideoClient::DeliverEncodedVideoFrame,
|
| + base::Unretained(&fake_video_client_));
|
| + receiver_->GetEncodedVideoFrame(frame_encoded_callback);
|
| task_runner_->RunTasks();
|
| - EXPECT_EQ(video_receiver_callback_->number_times_called(), 0);
|
| -}
|
| + EXPECT_EQ(0, fake_video_client_.number_times_called());
|
|
|
| -// TODO(pwestin): add encoded frames.
|
| + // Receive one video frame and expect to see the first request satisfied.
|
| + fake_video_client_.SetNextExpectedResult(kFirstFrameId,
|
| + testing_clock_->NowTicks());
|
| + const base::TimeTicks time_at_first_frame_feed = testing_clock_->NowTicks();
|
| + FeedOneFrameIntoReceiver();
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(1, fake_video_client_.number_times_called());
|
| +
|
| + testing_clock_->Advance(
|
| + base::TimeDelta::FromSeconds(1) / config_.max_frame_rate);
|
| +
|
| + // Enqueue a second request for an video frame, but it should not be
|
| + // fulfilled yet.
|
| + receiver_->GetEncodedVideoFrame(frame_encoded_callback);
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(1, fake_video_client_.number_times_called());
|
| +
|
| + // Receive one video frame out-of-order: Make sure that we are not continuous
|
| + // and that the RTP timestamp represents a time in the future.
|
| + rtp_header_.is_key_frame = false;
|
| + rtp_header_.frame_id = kFirstFrameId + 2;
|
| + rtp_header_.is_reference = true;
|
| + rtp_header_.reference_frame_id = 0;
|
| + rtp_header_.webrtc.header.timestamp +=
|
| + config_.rtp_max_delay_ms * kVideoFrequency / 1000;
|
| + fake_video_client_.SetNextExpectedResult(
|
| + kFirstFrameId + 2,
|
| + time_at_first_frame_feed +
|
| + base::TimeDelta::FromMilliseconds(config_.rtp_max_delay_ms));
|
| + FeedOneFrameIntoReceiver();
|
| +
|
| + // Frame 2 should not come out at this point in time.
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(1, fake_video_client_.number_times_called());
|
| +
|
| + // Enqueue a third request for an video frame.
|
| + receiver_->GetEncodedVideoFrame(frame_encoded_callback);
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(1, fake_video_client_.number_times_called());
|
| +
|
| + // After |rtp_max_delay_ms| has elapsed, Frame 2 is emitted (to satisfy the
|
| + // second request) because a decision was made to skip over the no-show Frame
|
| + // 1.
|
| + testing_clock_->Advance(
|
| + base::TimeDelta::FromMilliseconds(config_.rtp_max_delay_ms));
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(2, fake_video_client_.number_times_called());
|
| +
|
| + // Receive Frame 3 and expect it to fulfill the third request immediately.
|
| + rtp_header_.frame_id = kFirstFrameId + 3;
|
| + rtp_header_.is_reference = false;
|
| + rtp_header_.reference_frame_id = 0;
|
| + rtp_header_.webrtc.header.timestamp +=
|
| + kVideoFrequency / config_.max_frame_rate;
|
| + fake_video_client_.SetNextExpectedResult(kFirstFrameId + 3,
|
| + testing_clock_->NowTicks());
|
| + FeedOneFrameIntoReceiver();
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(3, fake_video_client_.number_times_called());
|
| +
|
| + // Move forward another |rtp_max_delay_ms| and run any pending tasks (there
|
| + // should be none). Expect no additional frames where emitted.
|
| + testing_clock_->Advance(
|
| + base::TimeDelta::FromMilliseconds(config_.rtp_max_delay_ms));
|
| + task_runner_->RunTasks();
|
| + EXPECT_EQ(3, fake_video_client_.number_times_called());
|
| +}
|
|
|
| } // namespace cast
|
| } // namespace media
|
|
|