Calculate RTT using ExtendedReports in RtcpTransceiver

Bug: webrtc:8239
Change-Id: Iec3d21d6297c53388bbae88611e147fe91027c83
Reviewed-on: https://webrtc-review.googlesource.com/22800
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20953}
This commit is contained in:
Danil Chapovalov 2017-11-30 14:56:52 +01:00 committed by Commit Bot
parent 5b86f0a24b
commit 319a675318
5 changed files with 167 additions and 14 deletions

View File

@ -67,6 +67,10 @@ bool RtcpTransceiverConfig::Validate() const {
RTC_LOG(LS_ERROR) << debug_id << "unsupported rtcp mode";
return false;
}
if (non_sender_rtt_measurement && !rtt_observer)
RTC_LOG(LS_WARNING) << debug_id
<< "Enabled special feature to calculate rtt, but no "
"rtt observer is provided.";
// TODO(danilchap): Remove or update the warning when RtcpTransceiver supports
// send-only sessions.
if (receive_statistics == nullptr)

View File

@ -52,6 +52,10 @@ struct RtcpTransceiverConfig {
// Rtcp report block generator for outgoing receiver reports.
ReceiveStatisticsProvider* receive_statistics = nullptr;
// Callback to pass result of rtt calculation. Should outlive RtcpTransceiver.
// Callbacks will be invoked on the task_queue.
RtcpRttStats* rtt_observer = nullptr;
// Configures if sending should
// enforce compound packets: https://tools.ietf.org/html/rfc4585#section-3.1
// or allow reduced size packets: https://tools.ietf.org/html/rfc5506
@ -70,6 +74,9 @@ struct RtcpTransceiverConfig {
// Flags for features and experiments.
//
bool schedule_periodic_compound_packets = true;
// Estimate RTT as non-sender as described in
// https://tools.ietf.org/html/rfc3611#section-4.4 and #section-4.5
bool non_sender_rtt_measurement = false;
};
} // namespace webrtc

View File

@ -17,6 +17,7 @@
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtcp_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
@ -163,17 +164,47 @@ void RtcpTransceiverImpl::HandleReceivedPacket(
const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us) {
switch (rtcp_packet_header.type()) {
case rtcp::SenderReport::kPacketType: {
rtcp::SenderReport sender_report;
if (!sender_report.Parse(rtcp_packet_header))
return;
rtc::Optional<SenderReportTimes>& last =
remote_senders_[sender_report.sender_ssrc()]
.last_received_sender_report;
last.emplace();
last->local_received_time_us = now_us;
last->remote_sent_time = sender_report.ntp();
case rtcp::SenderReport::kPacketType:
HandleSenderReport(rtcp_packet_header, now_us);
break;
case rtcp::ExtendedReports::kPacketType:
HandleExtendedReports(rtcp_packet_header, now_us);
break;
}
}
void RtcpTransceiverImpl::HandleSenderReport(
const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us) {
rtcp::SenderReport sender_report;
if (!sender_report.Parse(rtcp_packet_header))
return;
rtc::Optional<SenderReportTimes>& last =
remote_senders_[sender_report.sender_ssrc()].last_received_sender_report;
last.emplace();
last->local_received_time_us = now_us;
last->remote_sent_time = sender_report.ntp();
}
void RtcpTransceiverImpl::HandleExtendedReports(
const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us) {
rtcp::ExtendedReports extended_reports;
if (!extended_reports.Parse(rtcp_packet_header))
return;
if (extended_reports.dlrr() && config_.non_sender_rtt_measurement &&
config_.rtt_observer) {
// Delay and last_rr are transferred using 32bit compact ntp resolution.
// Convert packet arrival time to same format through 64bit ntp format.
uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
for (const rtcp::ReceiveTimeInfo& rti :
extended_reports.dlrr().sub_blocks()) {
if (rti.ssrc != config_.feedback_ssrc)
continue;
uint32_t rtt_ntp =
receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
config_.rtt_observer->OnRttUpdate(rtt_ms);
}
}
}
@ -220,9 +251,10 @@ void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
RTC_DCHECK(sender->IsEmpty());
const uint32_t sender_ssrc = config_.feedback_ssrc;
int64_t now_us = rtc::TimeMicros();
rtcp::ReceiverReport receiver_report;
receiver_report.SetSenderSsrc(sender_ssrc);
receiver_report.SetReportBlocks(CreateReportBlocks());
receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
sender->AppendPacket(receiver_report);
if (!config_.cname.empty()) {
@ -236,6 +268,19 @@ void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
remb_->SetSenderSsrc(sender_ssrc);
sender->AppendPacket(*remb_);
}
// TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
// SenderReport instead of ReceiverReport
// when RtcpTransceiver supports rtp senders.
if (config_.non_sender_rtt_measurement) {
rtcp::ExtendedReports xr;
rtcp::Rrtr rrtr;
rrtr.SetNtp(TimeMicrosToNtp(now_us));
xr.SetRrtr(rrtr);
xr.SetSenderSsrc(sender_ssrc);
sender->AppendPacket(xr);
}
}
void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
@ -260,7 +305,8 @@ void RtcpTransceiverImpl::SendImmediateFeedback(
ReschedulePeriodicCompoundPackets();
}
std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks() {
std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
int64_t now_us) {
if (!config_.receive_statistics)
return {};
// TODO(danilchap): Support sending more than
@ -276,7 +322,7 @@ std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks() {
*it->second.last_received_sender_report;
report_block.SetLastSr(CompactNtp(last_sender_report.remote_sent_time));
report_block.SetDelayLastSr(SaturatedUsToCompactNtp(
rtc::TimeMicros() - last_sender_report.local_received_time_us));
now_us - last_sender_report.local_received_time_us));
}
return report_blocks;
}

View File

@ -54,6 +54,10 @@ class RtcpTransceiverImpl {
void HandleReceivedPacket(const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us);
void HandleSenderReport(const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us);
void HandleExtendedReports(const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us);
void ReschedulePeriodicCompoundPackets();
void SchedulePeriodicCompoundPackets(int64_t delay_ms);
@ -64,7 +68,7 @@ class RtcpTransceiverImpl {
void SendPeriodicCompoundPacket();
void SendImmediateFeedback(const rtcp::RtcpPacket& rtcp_packet);
// Generate Report Blocks to be send in Sender or Receiver Report.
std::vector<rtcp::ReportBlock> CreateReportBlocks();
std::vector<rtcp::ReportBlock> CreateReportBlocks(int64_t now_us);
const RtcpTransceiverConfig config_;

View File

@ -13,6 +13,7 @@
#include <vector>
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h"
#include "modules/rtp_rtcp/source/time_util.h"
#include "rtc_base/event.h"
#include "rtc_base/fakeclock.h"
@ -32,10 +33,13 @@ using ::testing::Return;
using ::testing::SizeIs;
using ::webrtc::CompactNtp;
using ::webrtc::CompactNtpRttToMs;
using ::webrtc::MockRtcpRttStats;
using ::webrtc::MockTransport;
using ::webrtc::NtpTime;
using ::webrtc::RtcpTransceiverConfig;
using ::webrtc::RtcpTransceiverImpl;
using ::webrtc::SaturatedUsToCompactNtp;
using ::webrtc::TimeMicrosToNtp;
using ::webrtc::rtcp::ReportBlock;
using ::webrtc::rtcp::SenderReport;
using ::webrtc::test::RtcpPacketParser;
@ -580,4 +584,92 @@ TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesReducedSizePacket) {
EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 0);
}
TEST(RtcpTransceiverImplTest, SendsXrRrtrWhenEnabled) {
const uint32_t kSenderSsrc = 4321;
rtc::ScopedFakeClock clock;
RtcpTransceiverConfig config;
config.feedback_ssrc = kSenderSsrc;
config.schedule_periodic_compound_packets = false;
RtcpPacketParser rtcp_parser;
RtcpParserTransport transport(&rtcp_parser);
config.outgoing_transport = &transport;
config.non_sender_rtt_measurement = true;
RtcpTransceiverImpl rtcp_transceiver(config);
rtcp_transceiver.SendCompoundPacket();
NtpTime ntp_time_now = TimeMicrosToNtp(rtc::TimeMicros());
EXPECT_EQ(rtcp_parser.xr()->num_packets(), 1);
EXPECT_EQ(rtcp_parser.xr()->sender_ssrc(), kSenderSsrc);
ASSERT_TRUE(rtcp_parser.xr()->rrtr());
EXPECT_EQ(rtcp_parser.xr()->rrtr()->ntp(), ntp_time_now);
}
TEST(RtcpTransceiverImplTest, SendsNoXrRrtrWhenDisabled) {
RtcpTransceiverConfig config;
config.schedule_periodic_compound_packets = false;
RtcpPacketParser rtcp_parser;
RtcpParserTransport transport(&rtcp_parser);
config.outgoing_transport = &transport;
config.non_sender_rtt_measurement = false;
RtcpTransceiverImpl rtcp_transceiver(config);
rtcp_transceiver.SendCompoundPacket();
EXPECT_EQ(transport.num_packets(), 1);
// Extended reports rtcp packet might be included for another reason,
// but it shouldn't contain rrtr block.
EXPECT_FALSE(rtcp_parser.xr()->rrtr());
}
TEST(RtcpTransceiverImplTest, CalculatesRoundTripTimeOnDlrr) {
const uint32_t kSenderSsrc = 4321;
MockRtcpRttStats rtt_observer;
MockTransport null_transport;
RtcpTransceiverConfig config;
config.feedback_ssrc = kSenderSsrc;
config.schedule_periodic_compound_packets = false;
config.outgoing_transport = &null_transport;
config.non_sender_rtt_measurement = true;
config.rtt_observer = &rtt_observer;
RtcpTransceiverImpl rtcp_transceiver(config);
int64_t time_us = 12345678;
webrtc::rtcp::ReceiveTimeInfo rti;
rti.ssrc = kSenderSsrc;
rti.last_rr = CompactNtp(TimeMicrosToNtp(time_us));
rti.delay_since_last_rr = SaturatedUsToCompactNtp(10 * 1000);
webrtc::rtcp::ExtendedReports xr;
xr.AddDlrrItem(rti);
auto raw_packet = xr.Build();
EXPECT_CALL(rtt_observer, OnRttUpdate(100 /* rtt_ms */));
rtcp_transceiver.ReceivePacket(raw_packet, time_us + 110 * 1000);
}
TEST(RtcpTransceiverImplTest, IgnoresUnknownSsrcInDlrr) {
const uint32_t kSenderSsrc = 4321;
const uint32_t kUnknownSsrc = 4322;
MockRtcpRttStats rtt_observer;
MockTransport null_transport;
RtcpTransceiverConfig config;
config.feedback_ssrc = kSenderSsrc;
config.schedule_periodic_compound_packets = false;
config.outgoing_transport = &null_transport;
config.non_sender_rtt_measurement = true;
config.rtt_observer = &rtt_observer;
RtcpTransceiverImpl rtcp_transceiver(config);
int64_t time_us = 12345678;
webrtc::rtcp::ReceiveTimeInfo rti;
rti.ssrc = kUnknownSsrc;
rti.last_rr = CompactNtp(TimeMicrosToNtp(time_us));
webrtc::rtcp::ExtendedReports xr;
xr.AddDlrrItem(rti);
auto raw_packet = xr.Build();
EXPECT_CALL(rtt_observer, OnRttUpdate(_)).Times(0);
rtcp_transceiver.ReceivePacket(raw_packet, time_us + 100000);
}
} // namespace