blob: 1cdbecf5de6685ec1764f8af04f1c393c7d1278e [file] [log] [blame]
// 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 "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/time/tick_clock.h"
#include "media/cast/cast_environment.h"
#include "media/cast/logging/logging_defines.h"
#include "media/cast/logging/receiver_time_offset_estimator_impl.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace cast {
class ReceiverTimeOffsetEstimatorImplTest : public ::testing::Test {
protected:
ReceiverTimeOffsetEstimatorImplTest()
: sender_clock_(new base::SimpleTestTickClock()),
task_runner_(new test::FakeSingleThreadTaskRunner(sender_clock_)),
cast_environment_(new CastEnvironment(
scoped_ptr<base::TickClock>(sender_clock_).Pass(),
task_runner_,
task_runner_,
task_runner_)) {
cast_environment_->Logging()->AddRawEventSubscriber(&estimator_);
}
virtual ~ReceiverTimeOffsetEstimatorImplTest() {
cast_environment_->Logging()->RemoveRawEventSubscriber(&estimator_);
}
void AdvanceClocks(base::TimeDelta time) {
sender_clock_->Advance(time);
receiver_clock_.Advance(time);
}
base::SimpleTestTickClock* sender_clock_; // Owned by CastEnvironment.
scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
scoped_refptr<CastEnvironment> cast_environment_;
base::SimpleTestTickClock receiver_clock_;
ReceiverTimeOffsetEstimatorImpl estimator_;
};
// Suppose the true offset is 100ms.
// Event A occurred at sender time 20ms.
// Event B occurred at receiver time 130ms. (sender time 30ms)
// Event C occurred at sender time 60ms.
// Then the bound after all 3 events have arrived is [130-60=70, 130-20=110].
TEST_F(ReceiverTimeOffsetEstimatorImplTest, EstimateOffset) {
int64 true_offset_ms = 100;
receiver_clock_.Advance(base::TimeDelta::FromMilliseconds(true_offset_ms));
base::TimeDelta lower_bound;
base::TimeDelta upper_bound;
EXPECT_FALSE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
RtpTimestamp rtp_timestamp = 0;
uint32 frame_id = 0;
AdvanceClocks(base::TimeDelta::FromMilliseconds(20));
cast_environment_->Logging()->InsertEncodedFrameEvent(
sender_clock_->NowTicks(),
FRAME_ENCODED, VIDEO_EVENT,
rtp_timestamp,
frame_id,
1234,
true,
5678);
EXPECT_FALSE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
cast_environment_->Logging()->InsertFrameEvent(
receiver_clock_.NowTicks(), FRAME_ACK_SENT, VIDEO_EVENT,
rtp_timestamp, frame_id);
EXPECT_FALSE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
AdvanceClocks(base::TimeDelta::FromMilliseconds(30));
cast_environment_->Logging()->InsertFrameEvent(
sender_clock_->NowTicks(), FRAME_ACK_RECEIVED, VIDEO_EVENT,
rtp_timestamp, frame_id);
EXPECT_TRUE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
int64 lower_bound_ms = lower_bound.InMilliseconds();
int64 upper_bound_ms = upper_bound.InMilliseconds();
EXPECT_EQ(70, lower_bound_ms);
EXPECT_EQ(110, upper_bound_ms);
EXPECT_GE(true_offset_ms, lower_bound_ms);
EXPECT_LE(true_offset_ms, upper_bound_ms);
}
// Same scenario as above, but event C arrives before event B. It doens't mean
// event C occurred before event B.
TEST_F(ReceiverTimeOffsetEstimatorImplTest, EventCArrivesBeforeEventB) {
int64 true_offset_ms = 100;
receiver_clock_.Advance(base::TimeDelta::FromMilliseconds(true_offset_ms));
base::TimeDelta lower_bound;
base::TimeDelta upper_bound;
EXPECT_FALSE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
RtpTimestamp rtp_timestamp = 0;
uint32 frame_id = 0;
AdvanceClocks(base::TimeDelta::FromMilliseconds(20));
cast_environment_->Logging()->InsertEncodedFrameEvent(
sender_clock_->NowTicks(),
FRAME_ENCODED, VIDEO_EVENT,
rtp_timestamp,
frame_id,
1234,
true,
5678);
EXPECT_FALSE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
base::TimeTicks event_b_time = receiver_clock_.NowTicks();
AdvanceClocks(base::TimeDelta::FromMilliseconds(30));
base::TimeTicks event_c_time = sender_clock_->NowTicks();
cast_environment_->Logging()->InsertFrameEvent(
event_c_time, FRAME_ACK_RECEIVED, VIDEO_EVENT, rtp_timestamp, frame_id);
EXPECT_FALSE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
cast_environment_->Logging()->InsertFrameEvent(
event_b_time, FRAME_ACK_SENT, VIDEO_EVENT, rtp_timestamp, frame_id);
EXPECT_TRUE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
int64 lower_bound_ms = lower_bound.InMilliseconds();
int64 upper_bound_ms = upper_bound.InMilliseconds();
EXPECT_EQ(70, lower_bound_ms);
EXPECT_EQ(110, upper_bound_ms);
EXPECT_GE(true_offset_ms, lower_bound_ms);
EXPECT_LE(true_offset_ms, upper_bound_ms);
}
TEST_F(ReceiverTimeOffsetEstimatorImplTest, MultipleIterations) {
int64 true_offset_ms = 100;
receiver_clock_.Advance(base::TimeDelta::FromMilliseconds(true_offset_ms));
base::TimeDelta lower_bound;
base::TimeDelta upper_bound;
RtpTimestamp rtp_timestamp_a = 0;
int frame_id_a = 0;
RtpTimestamp rtp_timestamp_b = 90;
int frame_id_b = 1;
RtpTimestamp rtp_timestamp_c = 180;
int frame_id_c = 2;
// Frame 1 times: [20, 30+100, 60]
// Frame 2 times: [30, 50+100, 55]
// Frame 3 times: [77, 80+100, 110]
// Bound should end up at [95, 103]
// Events times in chronological order: 20, 30 x2, 50, 55, 60, 77, 80, 110
AdvanceClocks(base::TimeDelta::FromMilliseconds(20));
cast_environment_->Logging()->InsertEncodedFrameEvent(
sender_clock_->NowTicks(),
FRAME_ENCODED, VIDEO_EVENT,
rtp_timestamp_a,
frame_id_a,
1234,
true,
5678);
AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
cast_environment_->Logging()->InsertEncodedFrameEvent(
sender_clock_->NowTicks(),
FRAME_ENCODED, VIDEO_EVENT,
rtp_timestamp_b,
frame_id_b,
1234,
true,
5678);
cast_environment_->Logging()->InsertFrameEvent(
receiver_clock_.NowTicks(), FRAME_ACK_SENT, VIDEO_EVENT,
rtp_timestamp_a, frame_id_a);
AdvanceClocks(base::TimeDelta::FromMilliseconds(20));
cast_environment_->Logging()->InsertFrameEvent(
receiver_clock_.NowTicks(), FRAME_ACK_SENT, VIDEO_EVENT,
rtp_timestamp_b, frame_id_b);
AdvanceClocks(base::TimeDelta::FromMilliseconds(5));
cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
FRAME_ACK_RECEIVED,
VIDEO_EVENT,
rtp_timestamp_b,
frame_id_b);
AdvanceClocks(base::TimeDelta::FromMilliseconds(5));
cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
FRAME_ACK_RECEIVED,
VIDEO_EVENT,
rtp_timestamp_a,
frame_id_a);
AdvanceClocks(base::TimeDelta::FromMilliseconds(17));
cast_environment_->Logging()->InsertEncodedFrameEvent(
sender_clock_->NowTicks(),
FRAME_ENCODED, VIDEO_EVENT,
rtp_timestamp_c,
frame_id_c,
1234,
true,
5678);
AdvanceClocks(base::TimeDelta::FromMilliseconds(3));
cast_environment_->Logging()->InsertFrameEvent(
receiver_clock_.NowTicks(), FRAME_ACK_SENT, VIDEO_EVENT,
rtp_timestamp_c, frame_id_c);
AdvanceClocks(base::TimeDelta::FromMilliseconds(30));
cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
FRAME_ACK_RECEIVED,
VIDEO_EVENT,
rtp_timestamp_c,
frame_id_c);
EXPECT_TRUE(estimator_.GetReceiverOffsetBounds(&lower_bound, &upper_bound));
int64 lower_bound_ms = lower_bound.InMilliseconds();
int64 upper_bound_ms = upper_bound.InMilliseconds();
EXPECT_EQ(95, lower_bound_ms);
EXPECT_EQ(103, upper_bound_ms);
EXPECT_GE(true_offset_ms, lower_bound_ms);
EXPECT_LE(true_offset_ms, upper_bound_ms);
}
} // namespace cast
} // namespace media