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:
parent
5b86f0a24b
commit
319a675318
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user