Commit d89ef69a authored by miu's avatar miu Committed by Commit bot

[Cast] RTT clean-up to the max!

Executing some very badly needed clean-up of code that handles passing
around round trip time measurements and managing stats.  This change
removes a lot of dead code, addresses TODOs for minor things that were
dependent on this clean-up, and enhances RTCP unit testing.

BUG=404813

Review URL: https://codereview.chromium.org/532373003

Cr-Commit-Position: refs/heads/master@{#293887}
parent a92250eb
......@@ -61,16 +61,8 @@ void CastTransportHostFilter::SendRawEvents(
void CastTransportHostFilter::SendRtt(int32 channel_id,
uint32 ssrc,
base::TimeDelta rtt,
base::TimeDelta avg_rtt,
base::TimeDelta min_rtt,
base::TimeDelta max_rtt) {
media::cast::RtcpRttReport report;
report.rtt = rtt;
report.avg_rtt = avg_rtt;
report.min_rtt = min_rtt;
report.max_rtt = max_rtt;
Send(new CastMsg_Rtt(channel_id, ssrc, report));
base::TimeDelta rtt) {
Send(new CastMsg_Rtt(channel_id, ssrc, rtt));
}
void CastTransportHostFilter::SendCastMessage(
......
......@@ -34,12 +34,7 @@ class CastTransportHostFilter : public content::BrowserMessageFilter {
int32 channel_id,
const std::vector<media::cast::PacketEvent>& packet_events,
const std::vector<media::cast::FrameEvent>& frame_events);
void SendRtt(int32 channel_id,
uint32 ssrc,
base::TimeDelta rtt,
base::TimeDelta avg_rtt,
base::TimeDelta min_rtt,
base::TimeDelta max_rtt);
void SendRtt(int32 channel_id, uint32 ssrc, base::TimeDelta rtt);
void SendCastMessage(int32 channel_id,
uint32 ssrc,
const media::cast::RtcpCastMessage& cast_message);
......
......@@ -82,19 +82,12 @@ IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpCastMessage)
IPC_STRUCT_TRAITS_MEMBER(missing_frames_and_packets)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpRttReport)
IPC_STRUCT_TRAITS_MEMBER(rtt)
IPC_STRUCT_TRAITS_MEMBER(avg_rtt)
IPC_STRUCT_TRAITS_MEMBER(min_rtt)
IPC_STRUCT_TRAITS_MEMBER(max_rtt)
IPC_STRUCT_TRAITS_END()
// Cast messages sent from the browser to the renderer.
IPC_MESSAGE_CONTROL3(CastMsg_Rtt,
int32 /* channel_id */,
uint32 /* ssrc */,
media::cast::RtcpRttReport /* rtt_report */)
base::TimeDelta /* rtt */)
IPC_MESSAGE_CONTROL3(CastMsg_RtcpCastMessage,
int32 /* channel_id */,
......
......@@ -102,10 +102,10 @@ void CastIPCDispatcher::OnRawEvents(
void CastIPCDispatcher::OnRtt(int32 channel_id,
uint32 ssrc,
const media::cast::RtcpRttReport& rtt_report) {
base::TimeDelta rtt) {
CastTransportSenderIPC* sender = id_map_.Lookup(channel_id);
if (sender) {
sender->OnRtt(ssrc, rtt_report);
sender->OnRtt(ssrc, rtt);
} else {
DVLOG(1) << "CastIPCDispatcher::OnRtt on non-existing channel.";
}
......
......@@ -49,9 +49,7 @@ class CastIPCDispatcher : public IPC::MessageFilter {
void OnRawEvents(int32 channel_id,
const std::vector<media::cast::PacketEvent>& packet_events,
const std::vector<media::cast::FrameEvent>& frame_events);
void OnRtt(int32 channel_id,
uint32 ssrc,
const media::cast::RtcpRttReport& rtt_report);
void OnRtt(int32 channel_id, uint32 ssrc, base::TimeDelta rtt);
void OnRtcpCastMessage(int32 channel_id,
uint32 ssrc,
const media::cast::RtcpCastMessage& cast_message);
......
......@@ -90,21 +90,14 @@ void CastTransportSenderIPC::OnRawEvents(
raw_events_callback_.Run(packet_events, frame_events);
}
void CastTransportSenderIPC::OnRtt(
uint32 ssrc,
const media::cast::RtcpRttReport& rtt_report) {
void CastTransportSenderIPC::OnRtt(uint32 ssrc, base::TimeDelta rtt) {
ClientMap::iterator it = clients_.find(ssrc);
if (it == clients_.end()) {
LOG(ERROR) << "Received RTT report from for unknown SSRC: " << ssrc;
return;
}
if (it->second.rtt_cb.is_null())
return;
it->second.rtt_cb.Run(
rtt_report.rtt,
rtt_report.avg_rtt,
rtt_report.min_rtt,
rtt_report.max_rtt);
if (!it->second.rtt_cb.is_null())
it->second.rtt_cb.Run(rtt);
}
void CastTransportSenderIPC::OnRtcpCastMessage(
......
......@@ -51,7 +51,7 @@ class CastTransportSenderIPC
media::cast::CastTransportStatus status);
void OnRawEvents(const std::vector<media::cast::PacketEvent>& packet_events,
const std::vector<media::cast::FrameEvent>& frame_events);
void OnRtt(uint32 ssrc, const media::cast::RtcpRttReport& rtt_report);
void OnRtt(uint32 ssrc, base::TimeDelta rtt);
void OnRtcpCastMessage(uint32 ssrc,
const media::cast::RtcpCastMessage& cast_message);
......
......@@ -32,7 +32,6 @@ const uint32 kStartFrameId = UINT32_C(0xffffffff);
// can handle wrap around and compare two frame IDs.
const int kMaxUnackedFrames = 120;
const int kStartRttMs = 20;
const int64 kCastMessageUpdateIntervalMs = 33;
const int64 kNackRepeatIntervalMs = 30;
......
......@@ -222,12 +222,14 @@ void CastTransportSenderImpl::ResendFrameForKickstart(uint32 ssrc,
uint32 frame_id) {
if (audio_sender_ && ssrc == audio_sender_->ssrc()) {
DCHECK(audio_rtcp_session_);
audio_sender_->ResendFrameForKickstart(frame_id,
audio_rtcp_session_->rtt());
audio_sender_->ResendFrameForKickstart(
frame_id,
audio_rtcp_session_->current_round_trip_time());
} else if (video_sender_ && ssrc == video_sender_->ssrc()) {
DCHECK(video_rtcp_session_);
video_sender_->ResendFrameForKickstart(frame_id,
video_rtcp_session_->rtt());
video_sender_->ResendFrameForKickstart(
frame_id,
video_rtcp_session_->current_round_trip_time());
} else {
NOTREACHED() << "Invalid request for kickstart.";
}
......@@ -338,7 +340,7 @@ void CastTransportSenderImpl::OnReceivedCastMessage(
last_byte_acked_for_audio_ =
std::max(acked_bytes, last_byte_acked_for_audio_);
} else if (video_sender_ && video_sender_->ssrc() == ssrc) {
dedup_info.resend_interval = video_rtcp_session_->rtt();
dedup_info.resend_interval = video_rtcp_session_->current_round_trip_time();
// Only use audio stream to dedup if there is one.
if (audio_sender_) {
......
......@@ -18,7 +18,7 @@ using base::TimeDelta;
namespace media {
namespace cast {
static const int32 kMaxRttMs = 10000; // 10 seconds.
static const int32 kStatsHistoryWindowMs = 10000; // 10 seconds.
// Reject packets that are older than 0.5 seconds older than
// the newest packet we've seen so far. This protect internal
// states from crazy routers. (Based on RRTR)
......@@ -72,9 +72,7 @@ Rtcp::Rtcp(const RtcpCastMessageCallback& cast_callback,
last_report_truncated_ntp_(0),
local_clock_ahead_by_(ClockDriftSmoother::GetDefaultTimeConstant()),
lip_sync_rtp_timestamp_(0),
lip_sync_ntp_timestamp_(0),
min_rtt_(TimeDelta::FromMilliseconds(kMaxRttMs)),
number_of_rtt_in_avg_(0) {
lip_sync_ntp_timestamp_(0) {
}
Rtcp::~Rtcp() {}
......@@ -211,11 +209,9 @@ void Rtcp::SendRtcpFromRtpReceiver(
if (rtp_receiver_statistics) {
report_block.remote_ssrc = 0; // Not needed to set send side.
report_block.media_ssrc = remote_ssrc_; // SSRC of the RTP packet sender.
if (rtp_receiver_statistics) {
rtp_receiver_statistics->GetStatistics(
&report_block.fraction_lost, &report_block.cumulative_lost,
&report_block.extended_high_sequence_number, &report_block.jitter);
}
rtp_receiver_statistics->GetStatistics(
&report_block.fraction_lost, &report_block.cumulative_lost,
&report_block.extended_high_sequence_number, &report_block.jitter);
report_block.last_sr = last_report_truncated_ntp_;
if (!time_last_report_received_.is_null()) {
......@@ -271,8 +267,9 @@ void Rtcp::OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction) {
// TODO(miu): This clock offset calculation does not account for packet
// transit time over the network. End2EndTest.EvilNetwork confirms that this
// contributes a very significant source of error here. Fix this along with
// the RTT clean-up.
// contributes a very significant source of error here. Determine whether
// RTT should be factored-in, and how that changes the rest of the
// calculation.
const base::TimeDelta measured_offset =
now - ConvertNtpToTimeTicks(ntp_seconds, ntp_fraction);
local_clock_ahead_by_.Update(now, measured_offset);
......@@ -326,8 +323,20 @@ void Rtcp::OnReceivedDelaySinceLastReport(uint32 last_report,
return; // Feedback on another report.
}
base::TimeDelta sender_delay = clock_->NowTicks() - it->second;
UpdateRtt(sender_delay, ConvertFromNtpDiff(delay_since_last_report));
const base::TimeDelta sender_delay = clock_->NowTicks() - it->second;
const base::TimeDelta receiver_delay =
ConvertFromNtpDiff(delay_since_last_report);
current_round_trip_time_ = sender_delay - receiver_delay;
// If the round trip time was computed as less than 1 ms, assume clock
// imprecision by one or both peers caused a bad value to be calculated.
// While plenty of networks do easily achieve less than 1 ms round trip time,
// such a level of precision cannot be measured with our approach; and 1 ms is
// good enough to represent "under 1 ms" for our use cases.
current_round_trip_time_ =
std::max(current_round_trip_time_, base::TimeDelta::FromMilliseconds(1));
if (!rtt_callback_.is_null())
rtt_callback_.Run(current_round_trip_time_);
}
void Rtcp::OnReceivedCastFeedback(const RtcpCastMessage& cast_message) {
......@@ -348,7 +357,8 @@ void Rtcp::SaveLastSentNtpTime(const base::TimeTicks& now,
last_reports_sent_map_[last_report] = now;
last_reports_sent_queue_.push(std::make_pair(last_report, now));
base::TimeTicks timeout = now - TimeDelta::FromMilliseconds(kMaxRttMs);
const base::TimeTicks timeout =
now - TimeDelta::FromMilliseconds(kStatsHistoryWindowMs);
// Cleanup old statistics older than |timeout|.
while (!last_reports_sent_queue_.empty()) {
......@@ -362,48 +372,6 @@ void Rtcp::SaveLastSentNtpTime(const base::TimeTicks& now,
}
}
void Rtcp::UpdateRtt(const base::TimeDelta& sender_delay,
const base::TimeDelta& receiver_delay) {
base::TimeDelta rtt = sender_delay - receiver_delay;
// TODO(miu): Find out why this must be >= 1 ms, and remove the fudge if it's
// bogus.
rtt = std::max(rtt, base::TimeDelta::FromMilliseconds(1));
rtt_ = rtt;
min_rtt_ = std::min(min_rtt_, rtt);
max_rtt_ = std::max(max_rtt_, rtt);
// TODO(miu): Replace "average for all time" with an EWMA, or suitable
// "average over recent past" mechanism.
if (number_of_rtt_in_avg_ != 0) {
// Integer math equivalent of (ac/(ac+1.0))*avg_rtt_ + (1.0/(ac+1.0))*rtt).
// (TimeDelta only supports math with other TimeDeltas and int64s.)
avg_rtt_ = (avg_rtt_ * number_of_rtt_in_avg_ + rtt) /
(number_of_rtt_in_avg_ + 1);
} else {
avg_rtt_ = rtt;
}
number_of_rtt_in_avg_++;
if (!rtt_callback_.is_null())
rtt_callback_.Run(rtt, avg_rtt_, min_rtt_, max_rtt_);
}
bool Rtcp::Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt,
base::TimeDelta* min_rtt, base::TimeDelta* max_rtt) const {
DCHECK(rtt) << "Invalid argument";
DCHECK(avg_rtt) << "Invalid argument";
DCHECK(min_rtt) << "Invalid argument";
DCHECK(max_rtt) << "Invalid argument";
if (number_of_rtt_in_avg_ == 0) return false;
*rtt = rtt_;
*avg_rtt = avg_rtt_;
*min_rtt = min_rtt_;
*max_rtt = max_rtt_;
return true;
}
void Rtcp::OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log) {
if (log_callback_.is_null())
return;
......
......@@ -89,15 +89,6 @@ class Rtcp {
// this session, e.g. SSRC doesn't match.
bool IncomingRtcpPacket(const uint8* data, size_t length);
// TODO(miu): Clean up this method and downstream code: Only VideoSender uses
// this (for congestion control), and only the |rtt| and |avg_rtt| values, and
// it's not clear that any of the downstream code is doing the right thing
// with this data.
bool Rtt(base::TimeDelta* rtt,
base::TimeDelta* avg_rtt,
base::TimeDelta* min_rtt,
base::TimeDelta* max_rtt) const;
// If available, returns true and sets the output arguments to the latest
// lip-sync timestamps gleaned from the sender reports. While the sender
// provides reference NTP times relative to its own wall clock, the
......@@ -108,9 +99,13 @@ class Rtcp {
void OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log);
// If greater than zero, this is the last measured network round trip time.
base::TimeDelta current_round_trip_time() const {
return current_round_trip_time_;
}
static bool IsRtcpPacket(const uint8* packet, size_t length);
static uint32 GetSsrcOfSender(const uint8* rtcp_buffer, size_t length);
const base::TimeDelta& rtt() const { return rtt_; }
protected:
void OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction);
......@@ -124,9 +119,6 @@ class Rtcp {
void OnReceivedCastFeedback(const RtcpCastMessage& cast_message);
void UpdateRtt(const base::TimeDelta& sender_delay,
const base::TimeDelta& receiver_delay);
void SaveLastSentNtpTime(const base::TimeTicks& now,
uint32 last_ntp_seconds,
uint32 last_ntp_fraction);
......@@ -167,11 +159,10 @@ class Rtcp {
uint32 lip_sync_rtp_timestamp_;
uint64 lip_sync_ntp_timestamp_;
base::TimeDelta rtt_;
base::TimeDelta min_rtt_;
base::TimeDelta max_rtt_;
int number_of_rtt_in_avg_;
base::TimeDelta avg_rtt_;
// The last measured network round trip time. This is updated with each
// sender report --> receiver report round trip. If this is zero, then the
// round trip time has not been measured yet.
base::TimeDelta current_round_trip_time_;
base::TimeTicks largest_seen_timestamp_;
......
......@@ -33,8 +33,5 @@ RtcpReceiverReferenceTimeReport::~RtcpReceiverReferenceTimeReport() {}
RtcpEvent::RtcpEvent() : type(UNKNOWN), packet_id(0u) {}
RtcpEvent::~RtcpEvent() {}
RtcpRttReport::RtcpRttReport() {}
RtcpRttReport::~RtcpRttReport() {}
} // namespace cast
} // namespace media
......@@ -104,21 +104,8 @@ struct RtcpEvent {
uint16 packet_id;
};
struct RtcpRttReport {
RtcpRttReport();
~RtcpRttReport();
base::TimeDelta rtt;
base::TimeDelta avg_rtt;
base::TimeDelta min_rtt;
base::TimeDelta max_rtt;
};
typedef base::Callback<void(const RtcpCastMessage&)> RtcpCastMessageCallback;
typedef base::Callback<void(base::TimeDelta,
base::TimeDelta,
base::TimeDelta,
base::TimeDelta)> RtcpRttCallback;
typedef base::Callback<void(base::TimeDelta)> RtcpRttCallback;
typedef
base::Callback<void(const RtcpReceiverLogMessage&)> RtcpLogMessageCallback;
......
......@@ -7,11 +7,9 @@
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/cast_defines.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_sender_impl.h"
#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/rtcp.h"
#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "media/cast/test/skewed_tick_clock.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
......@@ -21,79 +19,26 @@ using testing::_;
static const uint32 kSenderSsrc = 0x10203;
static const uint32 kReceiverSsrc = 0x40506;
static const int64 kAddedDelay = 123;
static const int64 kAddedShortDelay = 100;
static const int kInitialReceiverClockOffsetSeconds = -5;
class RtcpTestPacketSender : public PacketSender {
class FakeRtcpTransport : public PacedPacketSender {
public:
explicit RtcpTestPacketSender(base::SimpleTestTickClock* testing_clock)
: drop_packets_(false),
short_delay_(false),
rtcp_receiver_(NULL),
testing_clock_(testing_clock) {}
virtual ~RtcpTestPacketSender() {}
// Packet lists imply a RTP packet.
void set_rtcp_receiver(Rtcp* rtcp) { rtcp_receiver_ = rtcp; }
void set_short_delay() { short_delay_ = true; }
void set_drop_packets(bool drop_packets) { drop_packets_ = drop_packets; }
// A singular packet implies a RTCP packet.
virtual bool SendPacket(PacketRef packet,
const base::Closure& cb) OVERRIDE {
if (short_delay_) {
testing_clock_->Advance(
base::TimeDelta::FromMilliseconds(kAddedShortDelay));
} else {
testing_clock_->Advance(base::TimeDelta::FromMilliseconds(kAddedDelay));
}
if (drop_packets_)
return true;
rtcp_receiver_->IncomingRtcpPacket(&packet->data[0], packet->data.size());
return true;
}
private:
bool drop_packets_;
bool short_delay_;
Rtcp* rtcp_receiver_;
base::SimpleTestTickClock* testing_clock_; // Not owned.
explicit FakeRtcpTransport(base::SimpleTestTickClock* clock)
: clock_(clock),
packet_delay_(base::TimeDelta::FromMilliseconds(42)) {}
DISALLOW_COPY_AND_ASSIGN(RtcpTestPacketSender);
};
class LocalRtcpTransport : public PacedPacketSender {
public:
explicit LocalRtcpTransport(base::SimpleTestTickClock* testing_clock)
: drop_packets_(false),
short_delay_(false),
testing_clock_(testing_clock) {}
void set_rtcp_destination(Rtcp* rtcp) { rtcp_ = rtcp; }
void set_rtcp_receiver(Rtcp* rtcp) { rtcp_ = rtcp; }
void set_short_delay() { short_delay_ = true; }
void set_drop_packets(bool drop_packets) { drop_packets_ = drop_packets; }
virtual bool SendRtcpPacket(uint32 ssrc,
PacketRef packet) OVERRIDE {
if (short_delay_) {
testing_clock_->Advance(
base::TimeDelta::FromMilliseconds(kAddedShortDelay));
} else {
testing_clock_->Advance(base::TimeDelta::FromMilliseconds(kAddedDelay));
}
if (drop_packets_)
return true;
base::TimeDelta packet_delay() const { return packet_delay_; }
void set_packet_delay(base::TimeDelta delay) { packet_delay_ = delay; }
virtual bool SendRtcpPacket(uint32 ssrc, PacketRef packet) OVERRIDE {
clock_->Advance(packet_delay_);
rtcp_->IncomingRtcpPacket(&packet->data[0], packet->data.size());
return true;
}
virtual bool SendPackets(
const SendPacketVector& packets) OVERRIDE {
virtual bool SendPackets(const SendPacketVector& packets) OVERRIDE {
return false;
}
......@@ -102,23 +47,21 @@ class LocalRtcpTransport : public PacedPacketSender {
return false;
}
virtual void CancelSendingPacket(
const PacketKey& packet_key) OVERRIDE {
virtual void CancelSendingPacket(const PacketKey& packet_key) OVERRIDE {
}
private:
bool drop_packets_;
bool short_delay_;
base::SimpleTestTickClock* const clock_;
base::TimeDelta packet_delay_;
Rtcp* rtcp_;
base::SimpleTestTickClock* testing_clock_; // Not owned.
DISALLOW_COPY_AND_ASSIGN(LocalRtcpTransport);
DISALLOW_COPY_AND_ASSIGN(FakeRtcpTransport);
};
class MockReceiverStats : public RtpReceiverStatistics {
class FakeReceiverStats : public RtpReceiverStatistics {
public:
MockReceiverStats() {}
virtual ~MockReceiverStats() {}
FakeReceiverStats() {}
virtual ~FakeReceiverStats() {}
virtual void GetStatistics(uint8* fraction_lost,
uint32* cumulative_lost,
......@@ -131,7 +74,7 @@ class MockReceiverStats : public RtpReceiverStatistics {
}
private:
DISALLOW_COPY_AND_ASSIGN(MockReceiverStats);
DISALLOW_COPY_AND_ASSIGN(FakeReceiverStats);
};
class MockFrameSender {
......@@ -141,11 +84,8 @@ class MockFrameSender {
MOCK_METHOD1(OnReceivedCastFeedback,
void(const RtcpCastMessage& cast_message));
MOCK_METHOD4(OnReceivedRtt,
void(base::TimeDelta rtt,
base::TimeDelta avg_rtt,
base::TimeDelta min_rtt,
base::TimeDelta max_rtt));
MOCK_METHOD1(OnMeasuredRoundTripTime, void(base::TimeDelta rtt));
private:
DISALLOW_COPY_AND_ASSIGN(MockFrameSender);
};
......@@ -153,251 +93,134 @@ class MockFrameSender {
class RtcpTest : public ::testing::Test {
protected:
RtcpTest()
: testing_clock_(new base::SimpleTestTickClock()),
task_runner_(
new test::FakeSingleThreadTaskRunner(testing_clock_.get())),
sender_to_receiver_(testing_clock_.get()),
receiver_to_sender_(testing_clock_.get()) {
testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
: sender_clock_(new base::SimpleTestTickClock()),
receiver_clock_(new test::SkewedTickClock(sender_clock_.get())),
sender_to_receiver_(sender_clock_.get()),
receiver_to_sender_(sender_clock_.get()),
rtcp_for_sender_(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnMeasuredRoundTripTime,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
sender_clock_.get(),
&sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc),
rtcp_for_receiver_(RtcpCastMessageCallback(),
RtcpRttCallback(),
RtcpLogMessageCallback(),
receiver_clock_.get(),
&receiver_to_sender_,
kReceiverSsrc,
kSenderSsrc) {
sender_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
receiver_clock_->SetSkew(
1.0, // No skew.
base::TimeDelta::FromSeconds(kInitialReceiverClockOffsetSeconds));
sender_to_receiver_.set_rtcp_destination(&rtcp_for_receiver_);
receiver_to_sender_.set_rtcp_destination(&rtcp_for_sender_);
}
virtual ~RtcpTest() {}
static void UpdateCastTransportStatus(CastTransportStatus status) {
bool result = (status == TRANSPORT_AUDIO_INITIALIZED ||
status == TRANSPORT_VIDEO_INITIALIZED);
EXPECT_TRUE(result);
}
void RunTasks(int during_ms) {
for (int i = 0; i < during_ms; ++i) {
// Call process the timers every 1 ms.
testing_clock_->Advance(base::TimeDelta::FromMilliseconds(1));
task_runner_->RunTasks();
}
}
scoped_ptr<base::SimpleTestTickClock> testing_clock_;
scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
LocalRtcpTransport sender_to_receiver_;
LocalRtcpTransport receiver_to_sender_;
scoped_ptr<base::SimpleTestTickClock> sender_clock_;
scoped_ptr<test::SkewedTickClock> receiver_clock_;
FakeRtcpTransport sender_to_receiver_;
FakeRtcpTransport receiver_to_sender_;
MockFrameSender mock_frame_sender_;
MockReceiverStats stats_;
Rtcp rtcp_for_sender_;
Rtcp rtcp_for_receiver_;
FakeReceiverStats stats_;
DISALLOW_COPY_AND_ASSIGN(RtcpTest);
};
TEST_F(RtcpTest, BasicSenderReport) {
Rtcp rtcp(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnReceivedRtt,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
testing_clock_.get(),
&sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc);
sender_to_receiver_.set_rtcp_receiver(&rtcp);
rtcp.SendRtcpFromRtpSender(base::TimeTicks(), 0, 1, 1);
}
TEST_F(RtcpTest, BasicReceiverReport) {
Rtcp rtcp(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnReceivedRtt,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
testing_clock_.get(),
&receiver_to_sender_,
kSenderSsrc,
kReceiverSsrc);
receiver_to_sender_.set_rtcp_receiver(&rtcp);
rtcp.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
}
TEST_F(RtcpTest, BasicCast) {
EXPECT_CALL(mock_frame_sender_, OnReceivedCastFeedback(_)).Times(1);
// Media sender.
Rtcp rtcp(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnReceivedRtt,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
testing_clock_.get(),
&receiver_to_sender_,
kSenderSsrc,
kSenderSsrc);
receiver_to_sender_.set_rtcp_receiver(&rtcp);
RtcpCastMessage cast_message(kSenderSsrc);
cast_message.ack_frame_id = kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets[kLostFrameId] = missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message.missing_frames_and_packets[kFrameIdWithLostPackets] =
missing_packets;
rtcp.SendRtcpFromRtpReceiver(&cast_message, base::TimeDelta(), NULL, NULL);
TEST_F(RtcpTest, LipSyncGleanedFromSenderReport) {
// Initially, expect no lip-sync info receiver-side without having first
// received a RTCP packet.
base::TimeTicks reference_time;
uint32 rtp_timestamp;
ASSERT_FALSE(rtcp_for_receiver_.GetLatestLipSyncTimes(&rtp_timestamp,
&reference_time));
// Send a Sender Report to the receiver.
const base::TimeTicks reference_time_sent = sender_clock_->NowTicks();
const uint32 rtp_timestamp_sent = 0xbee5;
rtcp_for_sender_.SendRtcpFromRtpSender(
reference_time_sent, rtp_timestamp_sent, 1, 1);
// Now the receiver should have lip-sync info. Confirm that the lip-sync
// reference time is the same as that sent.
EXPECT_TRUE(rtcp_for_receiver_.GetLatestLipSyncTimes(&rtp_timestamp,
&reference_time));
const base::TimeTicks rolled_back_time =
(reference_time -
// Roll-back relative clock offset:
base::TimeDelta::FromSeconds(kInitialReceiverClockOffsetSeconds) -
// Roll-back packet transmission time (because RTT is not yet known):
sender_to_receiver_.packet_delay());
EXPECT_NEAR(0, (reference_time_sent - rolled_back_time).InMicroseconds(), 5);
EXPECT_EQ(rtp_timestamp_sent, rtp_timestamp);
}
TEST_F(RtcpTest, RttReducedSizeRtcp) {
// Media receiver.
Rtcp rtcp_receiver(RtcpCastMessageCallback(),
RtcpRttCallback(),
RtcpLogMessageCallback(),
testing_clock_.get(),
&receiver_to_sender_,
kReceiverSsrc,
kSenderSsrc);
// Media sender.
Rtcp rtcp_sender(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnReceivedRtt,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
testing_clock_.get(),
&sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc);
sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver);
receiver_to_sender_.set_rtcp_receiver(&rtcp_sender);
base::TimeDelta rtt;
base::TimeDelta avg_rtt;
base::TimeDelta min_rtt;
base::TimeDelta max_rtt;
EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1, 1, 1);
RunTasks(33);
rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 2, 1, 1);
RunTasks(33);
}
TEST_F(RtcpTest, Rtt) {
// Media receiver.
Rtcp rtcp_receiver(RtcpCastMessageCallback(),
RtcpRttCallback(),
RtcpLogMessageCallback(),
testing_clock_.get(),
&receiver_to_sender_,
kReceiverSsrc,
kSenderSsrc);
// Media sender.
Rtcp rtcp_sender(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnReceivedRtt,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
testing_clock_.get(),
&sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc);
receiver_to_sender_.set_rtcp_receiver(&rtcp_sender);
sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver);
base::TimeDelta rtt;
base::TimeDelta avg_rtt;
base::TimeDelta min_rtt;
base::TimeDelta max_rtt;
EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1, 1, 1);
RunTasks(33);
rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
RunTasks(33);
RunTasks(33);
EXPECT_NEAR(2 * kAddedDelay, rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, avg_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, min_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2);
rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 2, 1, 1);
RunTasks(33);
receiver_to_sender_.set_short_delay();
sender_to_receiver_.set_short_delay();
rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
EXPECT_NEAR(kAddedDelay + kAddedShortDelay, rtt.InMilliseconds(), 2);
EXPECT_NEAR(
(kAddedShortDelay + 3 * kAddedDelay) / 2, avg_rtt.InMilliseconds(), 2);
EXPECT_NEAR(kAddedDelay + kAddedShortDelay, min_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2);
rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 3, 1, 1);
RunTasks(33);
rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2);
rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
EXPECT_TRUE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
EXPECT_NEAR(2 * kAddedShortDelay, rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedShortDelay, min_rtt.InMilliseconds(), 2);
EXPECT_NEAR(2 * kAddedDelay, max_rtt.InMilliseconds(), 2);
}
TEST_F(RtcpTest, RttWithPacketLoss) {
// Media receiver.
Rtcp rtcp_receiver(RtcpCastMessageCallback(),
RtcpRttCallback(),
RtcpLogMessageCallback(),
testing_clock_.get(),
&receiver_to_sender_,
kReceiverSsrc,
kSenderSsrc);
// Media sender.
Rtcp rtcp_sender(base::Bind(&MockFrameSender::OnReceivedCastFeedback,
base::Unretained(&mock_frame_sender_)),
base::Bind(&MockFrameSender::OnReceivedRtt,
base::Unretained(&mock_frame_sender_)),
RtcpLogMessageCallback(),
testing_clock_.get(),
&sender_to_receiver_,
kSenderSsrc,
kReceiverSsrc);
receiver_to_sender_.set_rtcp_receiver(&rtcp_sender);
sender_to_receiver_.set_rtcp_receiver(&rtcp_receiver);
rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 0, 1, 1);
RunTasks(33);
base::TimeDelta rtt;
base::TimeDelta avg_rtt;
base::TimeDelta min_rtt;
base::TimeDelta max_rtt;
EXPECT_FALSE(rtcp_sender.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt));
receiver_to_sender_.set_short_delay();
sender_to_receiver_.set_short_delay();
receiver_to_sender_.set_drop_packets(true);
rtcp_receiver.SendRtcpFromRtpReceiver(NULL, base::TimeDelta(), NULL, &stats_);
rtcp_sender.SendRtcpFromRtpSender(testing_clock_->NowTicks(), 1, 1, 1);
RunTasks(33);
// TODO(miu): There were a few tests here that didn't actually test anything
// except that the code wouldn't crash and a callback method was invoked. We
// need to fill-in more testing of RTCP now that much of the refactoring work
// has been completed.
TEST_F(RtcpTest, RoundTripTimesDeterminedFromReportPingPong) {
const int iterations = 12;
EXPECT_CALL(mock_frame_sender_, OnMeasuredRoundTripTime(_))
.Times(iterations);
// Initially, neither side knows the round trip time.
ASSERT_EQ(base::TimeDelta(), rtcp_for_sender_.current_round_trip_time());
ASSERT_EQ(base::TimeDelta(), rtcp_for_receiver_.current_round_trip_time());
// Do a number of ping-pongs, checking how the round trip times are measured
// by the sender and receiver.
base::TimeDelta expected_rtt_according_to_sender;
base::TimeDelta expected_rtt_according_to_receiver;
for (int i = 0; i < iterations; ++i) {
const base::TimeDelta one_way_trip_time =
base::TimeDelta::FromMilliseconds(1 << i);
sender_to_receiver_.set_packet_delay(one_way_trip_time);
receiver_to_sender_.set_packet_delay(one_way_trip_time);
// Sender --> Receiver
base::TimeTicks reference_time_sent = sender_clock_->NowTicks();
uint32 rtp_timestamp_sent = 0xbee5 + i;
rtcp_for_sender_.SendRtcpFromRtpSender(
reference_time_sent, rtp_timestamp_sent, 1, 1);
EXPECT_EQ(expected_rtt_according_to_sender,
rtcp_for_sender_.current_round_trip_time());
#ifdef SENDER_PROVIDES_REPORT_BLOCK
EXPECT_EQ(expected_rtt_according_to_receiver,
rtcp_for_receiver_.current_round_trip_time());
#endif
// Receiver --> Sender
rtcp_for_receiver_.SendRtcpFromRtpReceiver(
NULL, base::TimeDelta(), NULL, &stats_);
expected_rtt_according_to_sender = one_way_trip_time * 2;
EXPECT_EQ(expected_rtt_according_to_sender,
rtcp_for_sender_.current_round_trip_time());
#ifdef SENDER_PROVIDES_REPORT_BLOCK
EXPECT_EQ(expected_rtt_according_to_receiver,
rtcp_for_receiver_.current_round_trip_time();
#endif
// In the next iteration of this loop, after the receiver gets the sender
// report, it will be measuring a round trip time consisting of two
// different one-way trip times.
expected_rtt_according_to_receiver =
(one_way_trip_time + one_way_trip_time * 2) / 2;
}
}
TEST_F(RtcpTest, NtpAndTime) {
// TODO(miu): Find a better home for this test.
TEST(MisplacedCastTest, NtpAndTime) {
const int64 kSecondsbetweenYear1900and2010 = INT64_C(40176 * 24 * 60 * 60);
const int64 kSecondsbetweenYear1900and2030 = INT64_C(47481 * 24 * 60 * 60);
......
......@@ -71,7 +71,8 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
transport_config,
base::Bind(&AudioSender::OnReceivedCastFeedback,
weak_factory_.GetWeakPtr()),
base::Bind(&AudioSender::OnReceivedRtt, weak_factory_.GetWeakPtr()));
base::Bind(&AudioSender::OnMeasuredRoundTripTime,
weak_factory_.GetWeakPtr()));
}
AudioSender::~AudioSender() {}
......
......@@ -27,7 +27,6 @@ FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment,
: cast_environment_(cast_environment),
transport_sender_(transport_sender),
ssrc_(ssrc),
rtt_available_(false),
rtcp_interval_(rtcp_interval),
max_frame_rate_(max_frame_rate),
frames_in_encoder_(0),
......@@ -39,7 +38,9 @@ FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment,
congestion_control_(congestion_control),
is_audio_(is_audio),
weak_factory_(this) {
DCHECK(transport_sender_);
DCHECK_GT(rtp_timebase_, 0);
DCHECK(congestion_control_);
SetTargetPlayoutDelay(playout_delay);
send_target_playout_delay_ = false;
memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_));
......@@ -88,15 +89,9 @@ void FrameSender::SendRtcpReport(bool schedule_future_reports) {
ScheduleNextRtcpReport();
}
void FrameSender::OnReceivedRtt(base::TimeDelta rtt,
base::TimeDelta avg_rtt,
base::TimeDelta min_rtt,
base::TimeDelta max_rtt) {
rtt_available_ = true;
rtt_ = rtt;
avg_rtt_ = avg_rtt;
min_rtt_ = min_rtt;
max_rtt_ = max_rtt;
void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) {
DCHECK(rtt > base::TimeDelta());
current_round_trip_time_ = rtt;
}
void FrameSender::SetTargetPlayoutDelay(
......@@ -241,22 +236,11 @@ void FrameSender::SendEncodedFrame(
void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
base::TimeDelta rtt;
base::TimeDelta avg_rtt;
base::TimeDelta min_rtt;
base::TimeDelta max_rtt;
if (is_rtt_available()) {
rtt = rtt_;
avg_rtt = avg_rtt_;
min_rtt = min_rtt_;
max_rtt = max_rtt_;
const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta();
if (have_valid_rtt) {
congestion_control_->UpdateRtt(current_round_trip_time_);
congestion_control_->UpdateRtt(rtt);
// Don't use a RTT lower than our average.
rtt = std::max(rtt, avg_rtt);
// Having the RTT values implies the receiver sent back a receiver report
// Having the RTT value implies the receiver sent back a receiver report
// based on it having received a report from here. Therefore, ensure this
// sender stops aggressively sending reports.
if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
......@@ -265,9 +249,6 @@ void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart;
ScheduleNextRtcpReport();
}
} else {
// We have no measured value use default.
rtt = base::TimeDelta::FromMilliseconds(kStartRttMs);
}
if (last_send_time_.is_null())
......
......@@ -50,12 +50,7 @@ class FrameSender {
void ScheduleNextRtcpReport();
void SendRtcpReport(bool schedule_future_reports);
void OnReceivedRtt(base::TimeDelta rtt,
base::TimeDelta avg_rtt,
base::TimeDelta min_rtt,
base::TimeDelta max_rtt);
bool is_rtt_available() const { return rtt_available_; }
void OnMeasuredRoundTripTime(base::TimeDelta rtt);
const scoped_refptr<CastEnvironment> cast_environment_;
......@@ -68,13 +63,6 @@ class FrameSender {
const uint32 ssrc_;
// RTT information from RTCP.
bool rtt_available_;
base::TimeDelta rtt_;
base::TimeDelta avg_rtt_;
base::TimeDelta min_rtt_;
base::TimeDelta max_rtt_;
protected:
// Schedule and execute periodic checks for re-sending packets. If no
// acknowledgements have been received for "too long," AudioSender will
......@@ -175,6 +163,9 @@ class FrameSender {
base::TimeTicks frame_reference_times_[256];
RtpTimestamp frame_rtp_timestamps_[256];
// The most recently measured round trip time.
base::TimeDelta current_round_trip_time_;
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<FrameSender> weak_factory_;
......
......@@ -77,7 +77,8 @@ VideoSender::VideoSender(
transport_config,
base::Bind(&VideoSender::OnReceivedCastFeedback,
weak_factory_.GetWeakPtr()),
base::Bind(&VideoSender::OnReceivedRtt, weak_factory_.GetWeakPtr()));
base::Bind(&VideoSender::OnMeasuredRoundTripTime,
weak_factory_.GetWeakPtr()));
}
VideoSender::~VideoSender() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment