Add remote-outbound stats for audio streams
Add missing members needed to surface `RTCRemoteOutboundRtpStreamStats` via `ChannelReceive::GetRTCPStatistics()` - i.e., audio streams. `GetSenderReportStats()` is added to both `ModuleRtpRtcpImpl` and `ModuleRtpRtcpImpl2` and used by `ChannelReceive::GetRTCPStatistics()`. Bug: webrtc:12529 Change-Id: Ia8f5dfe2e4cfc43e3ddd28f2f1149f5c00f9269d Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/211041 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org> Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33452}
This commit is contained in:
parent
c80f955114
commit
bc1c93dc6e
@ -695,8 +695,10 @@ void ChannelReceive::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
|
||||
uint32_t ntp_secs = 0;
|
||||
uint32_t ntp_frac = 0;
|
||||
uint32_t rtp_timestamp = 0;
|
||||
if (0 !=
|
||||
rtp_rtcp_->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL, &rtp_timestamp)) {
|
||||
if (rtp_rtcp_->RemoteNTP(&ntp_secs, &ntp_frac,
|
||||
/*rtcp_arrival_time_secs=*/nullptr,
|
||||
/*rtcp_arrival_time_frac=*/nullptr,
|
||||
&rtp_timestamp) != 0) {
|
||||
// Waiting for RTCP.
|
||||
return;
|
||||
}
|
||||
@ -753,11 +755,10 @@ void ChannelReceive::ResetReceiverCongestionControlObjects() {
|
||||
|
||||
CallReceiveStatistics ChannelReceive::GetRTCPStatistics() const {
|
||||
RTC_DCHECK(worker_thread_checker_.IsCurrent());
|
||||
// --- RtcpStatistics
|
||||
CallReceiveStatistics stats;
|
||||
|
||||
// The jitter statistics is updated for each received RTP packet and is
|
||||
// based on received packets.
|
||||
// The jitter statistics is updated for each received RTP packet and is based
|
||||
// on received packets.
|
||||
RtpReceiveStats rtp_stats;
|
||||
StreamStatistician* statistician =
|
||||
rtp_receive_statistics_->GetStatistician(remote_ssrc_);
|
||||
@ -768,10 +769,9 @@ CallReceiveStatistics ChannelReceive::GetRTCPStatistics() const {
|
||||
stats.cumulativeLost = rtp_stats.packets_lost;
|
||||
stats.jitterSamples = rtp_stats.jitter;
|
||||
|
||||
// --- RTT
|
||||
stats.rttMs = GetRTT();
|
||||
|
||||
// --- Data counters
|
||||
// Data counters.
|
||||
if (statistician) {
|
||||
stats.payload_bytes_rcvd = rtp_stats.packet_counter.payload_bytes;
|
||||
|
||||
@ -788,11 +788,24 @@ CallReceiveStatistics ChannelReceive::GetRTCPStatistics() const {
|
||||
stats.last_packet_received_timestamp_ms = absl::nullopt;
|
||||
}
|
||||
|
||||
// --- Timestamps
|
||||
// Timestamps.
|
||||
{
|
||||
MutexLock lock(&ts_stats_lock_);
|
||||
stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
|
||||
}
|
||||
|
||||
absl::optional<RtpRtcpInterface::SenderReportStats> rtcp_sr_stats =
|
||||
rtp_rtcp_->GetSenderReportStats();
|
||||
if (rtcp_sr_stats.has_value()) {
|
||||
stats.last_sender_report_timestamp_ms =
|
||||
rtcp_sr_stats->last_arrival_timestamp.ToMs();
|
||||
stats.last_sender_report_remote_timestamp_ms =
|
||||
rtcp_sr_stats->last_remote_timestamp.ToMs();
|
||||
stats.sender_reports_packets_sent = rtcp_sr_stats->packets_sent;
|
||||
stats.sender_reports_bytes_sent = rtcp_sr_stats->bytes_sent;
|
||||
stats.sender_reports_reports_count = rtcp_sr_stats->reports_count;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
@ -913,7 +926,9 @@ absl::optional<Syncable::Info> ChannelReceive::GetSyncInfo() const {
|
||||
RTC_DCHECK(module_process_thread_checker_.IsCurrent());
|
||||
Syncable::Info info;
|
||||
if (rtp_rtcp_->RemoteNTP(&info.capture_time_ntp_secs,
|
||||
&info.capture_time_ntp_frac, nullptr, nullptr,
|
||||
&info.capture_time_ntp_frac,
|
||||
/*rtcp_arrival_time_secs=*/nullptr,
|
||||
/*rtcp_arrival_time_frac=*/nullptr,
|
||||
&info.capture_time_source_clock) != 0) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
@ -65,6 +65,13 @@ struct CallReceiveStatistics {
|
||||
// local clock when it was received - not the RTP timestamp of that packet.
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-lastpacketreceivedtimestamp
|
||||
absl::optional<int64_t> last_packet_received_timestamp_ms;
|
||||
// Remote outbound stats derived by the received RTCP sender reports.
|
||||
// https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
|
||||
absl::optional<int64_t> last_sender_report_timestamp_ms;
|
||||
absl::optional<int64_t> last_sender_report_remote_timestamp_ms;
|
||||
uint32_t sender_reports_packets_sent = 0;
|
||||
uint64_t sender_reports_bytes_sent = 0;
|
||||
uint64_t sender_reports_reports_count = 0;
|
||||
};
|
||||
|
||||
namespace voe {
|
||||
|
||||
@ -338,6 +338,7 @@ rtc_source_set("rtp_rtcp_legacy") {
|
||||
"../../rtc_base:gtest_prod",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base/synchronization:mutex",
|
||||
"../../system_wrappers",
|
||||
"../remote_bitrate_estimator",
|
||||
]
|
||||
absl_deps = [
|
||||
|
||||
@ -149,6 +149,10 @@ class MockRtpRtcpInterface : public RtpRtcpInterface {
|
||||
GetLatestReportBlockData,
|
||||
(),
|
||||
(const, override));
|
||||
MOCK_METHOD(absl::optional<SenderReportStats>,
|
||||
GetSenderReportStats,
|
||||
(),
|
||||
(const, override));
|
||||
MOCK_METHOD(void,
|
||||
SetRemb,
|
||||
(int64_t bitrate, std::vector<uint32_t> ssrcs),
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/ntp_time.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// Disable warning C4355: 'this' : used in base member initializer list.
|
||||
@ -545,6 +546,26 @@ std::vector<ReportBlockData> ModuleRtpRtcpImpl::GetLatestReportBlockData()
|
||||
return rtcp_receiver_.GetLatestReportBlockData();
|
||||
}
|
||||
|
||||
absl::optional<RtpRtcpInterface::SenderReportStats>
|
||||
ModuleRtpRtcpImpl::GetSenderReportStats() const {
|
||||
SenderReportStats stats;
|
||||
uint32_t remote_timestamp_secs;
|
||||
uint32_t remote_timestamp_frac;
|
||||
uint32_t arrival_timestamp_secs;
|
||||
uint32_t arrival_timestamp_frac;
|
||||
if (rtcp_receiver_.NTP(&remote_timestamp_secs, &remote_timestamp_frac,
|
||||
&arrival_timestamp_secs, &arrival_timestamp_frac,
|
||||
/*rtcp_timestamp=*/nullptr, &stats.packets_sent,
|
||||
&stats.bytes_sent, &stats.reports_count)) {
|
||||
stats.last_remote_timestamp.Set(remote_timestamp_secs,
|
||||
remote_timestamp_frac);
|
||||
stats.last_arrival_timestamp.Set(arrival_timestamp_secs,
|
||||
arrival_timestamp_frac);
|
||||
return stats;
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// (REMB) Receiver Estimated Max Bitrate.
|
||||
void ModuleRtpRtcpImpl::SetRemb(int64_t bitrate_bps,
|
||||
std::vector<uint32_t> ssrcs) {
|
||||
|
||||
@ -196,6 +196,7 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp {
|
||||
// Within this list, the ReportBlockData::RTCPReportBlock::source_ssrc(),
|
||||
// which is the SSRC of the corresponding outbound RTP stream, is unique.
|
||||
std::vector<ReportBlockData> GetLatestReportBlockData() const override;
|
||||
absl::optional<SenderReportStats> GetSenderReportStats() const override;
|
||||
|
||||
// (REMB) Receiver Estimated Max Bitrate.
|
||||
void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) override;
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/ntp_time.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// Disable warning C4355: 'this' : used in base member initializer list.
|
||||
@ -510,6 +511,26 @@ std::vector<ReportBlockData> ModuleRtpRtcpImpl2::GetLatestReportBlockData()
|
||||
return rtcp_receiver_.GetLatestReportBlockData();
|
||||
}
|
||||
|
||||
absl::optional<RtpRtcpInterface::SenderReportStats>
|
||||
ModuleRtpRtcpImpl2::GetSenderReportStats() const {
|
||||
SenderReportStats stats;
|
||||
uint32_t remote_timestamp_secs;
|
||||
uint32_t remote_timestamp_frac;
|
||||
uint32_t arrival_timestamp_secs;
|
||||
uint32_t arrival_timestamp_frac;
|
||||
if (rtcp_receiver_.NTP(&remote_timestamp_secs, &remote_timestamp_frac,
|
||||
&arrival_timestamp_secs, &arrival_timestamp_frac,
|
||||
/*rtcp_timestamp=*/nullptr, &stats.packets_sent,
|
||||
&stats.bytes_sent, &stats.reports_count)) {
|
||||
stats.last_remote_timestamp.Set(remote_timestamp_secs,
|
||||
remote_timestamp_frac);
|
||||
stats.last_arrival_timestamp.Set(arrival_timestamp_secs,
|
||||
arrival_timestamp_frac);
|
||||
return stats;
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// (REMB) Receiver Estimated Max Bitrate.
|
||||
void ModuleRtpRtcpImpl2::SetRemb(int64_t bitrate_bps,
|
||||
std::vector<uint32_t> ssrcs) {
|
||||
|
||||
@ -208,6 +208,7 @@ class ModuleRtpRtcpImpl2 final : public RtpRtcpInterface,
|
||||
// Within this list, the ReportBlockData::RTCPReportBlock::source_ssrc(),
|
||||
// which is the SSRC of the corresponding outbound RTP stream, is unique.
|
||||
std::vector<ReportBlockData> GetLatestReportBlockData() const override;
|
||||
absl::optional<SenderReportStats> GetSenderReportStats() const override;
|
||||
|
||||
// (REMB) Receiver Estimated Max Bitrate.
|
||||
void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) override;
|
||||
|
||||
@ -14,11 +14,13 @@
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_rtcp_interface.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_sender_video.h"
|
||||
#include "rtc_base/rate_limiter.h"
|
||||
#include "test/gmock.h"
|
||||
@ -29,6 +31,11 @@
|
||||
#include "test/time_controller/simulated_time_controller.h"
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using ::testing::Field;
|
||||
using ::testing::Gt;
|
||||
using ::testing::Not;
|
||||
using ::testing::Optional;
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
@ -631,4 +638,102 @@ TEST_F(RtpRtcpImpl2Test, StoresPacketInfoForSentPackets) {
|
||||
/*is_last=*/1)));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats are not available if no RTCP SR was sent.
|
||||
TEST_F(RtpRtcpImpl2Test, SenderReportStatsNotAvailable) {
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(), Eq(absl::nullopt));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats are available if an RTCP SR was sent.
|
||||
TEST_F(RtpRtcpImpl2Test, SenderReportStatsAvailable) {
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
// Send an SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(), Not(Eq(absl::nullopt)));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats are not available if an RTCP SR with an
|
||||
// unexpected SSRC is received.
|
||||
TEST_F(RtpRtcpImpl2Test, SenderReportStatsNotUpdatedWithUnexpectedSsrc) {
|
||||
constexpr uint32_t kUnexpectedSenderSsrc = 0x87654321;
|
||||
static_assert(kUnexpectedSenderSsrc != kSenderSsrc, "");
|
||||
// Forge a sender report and pass it to the receiver as if an RTCP SR were
|
||||
// sent by an unexpected sender.
|
||||
rtcp::SenderReport sr;
|
||||
sr.SetSenderSsrc(kUnexpectedSenderSsrc);
|
||||
sr.SetNtp({/*seconds=*/1u, /*fractions=*/1u << 31});
|
||||
sr.SetPacketCount(123u);
|
||||
sr.SetOctetCount(456u);
|
||||
auto raw_packet = sr.Build();
|
||||
receiver_.impl_->IncomingRtcpPacket(raw_packet.data(), raw_packet.size());
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(), Eq(absl::nullopt));
|
||||
}
|
||||
|
||||
// Checks the stats derived from the last received RTCP SR are set correctly.
|
||||
TEST_F(RtpRtcpImpl2Test, SenderReportStatsCheckStatsFromLastReport) {
|
||||
using SenderReportStats = RtpRtcpInterface::SenderReportStats;
|
||||
const NtpTime ntp(/*seconds=*/1u, /*fractions=*/1u << 31);
|
||||
constexpr uint32_t kPacketCount = 123u;
|
||||
constexpr uint32_t kOctetCount = 456u;
|
||||
// Forge a sender report and pass it to the receiver as if an RTCP SR were
|
||||
// sent by the sender.
|
||||
rtcp::SenderReport sr;
|
||||
sr.SetSenderSsrc(kSenderSsrc);
|
||||
sr.SetNtp(ntp);
|
||||
sr.SetPacketCount(kPacketCount);
|
||||
sr.SetOctetCount(kOctetCount);
|
||||
auto raw_packet = sr.Build();
|
||||
receiver_.impl_->IncomingRtcpPacket(raw_packet.data(), raw_packet.size());
|
||||
|
||||
EXPECT_THAT(
|
||||
receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(AllOf(Field(&SenderReportStats::last_remote_timestamp, Eq(ntp)),
|
||||
Field(&SenderReportStats::packets_sent, Eq(kPacketCount)),
|
||||
Field(&SenderReportStats::bytes_sent, Eq(kOctetCount)))));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats count equals the number of sent RTCP SRs.
|
||||
TEST_F(RtpRtcpImpl2Test, SenderReportStatsCount) {
|
||||
using SenderReportStats = RtpRtcpInterface::SenderReportStats;
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
// Send the first SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(Field(&SenderReportStats::reports_count, Eq(1u))));
|
||||
// Send the second SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(Field(&SenderReportStats::reports_count, Eq(2u))));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats include a valid arrival time if an RTCP
|
||||
// SR was sent.
|
||||
TEST_F(RtpRtcpImpl2Test, SenderReportStatsArrivalTimestampSet) {
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
// Send an SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
auto stats = receiver_.impl_->GetSenderReportStats();
|
||||
ASSERT_THAT(stats, Not(Eq(absl::nullopt)));
|
||||
EXPECT_TRUE(stats->last_arrival_timestamp.Valid());
|
||||
}
|
||||
|
||||
// Checks that the packet and byte counters from an RTCP SR are not zero once
|
||||
// a frame is sent.
|
||||
TEST_F(RtpRtcpImpl2Test, SenderReportStatsPacketByteCounters) {
|
||||
using SenderReportStats = RtpRtcpInterface::SenderReportStats;
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
ASSERT_THAT(sender_.transport_.rtp_packets_sent_, Gt(0));
|
||||
// Advance time otherwise the RTCP SR report will not include any packets
|
||||
// generated by `SendFrame()`.
|
||||
AdvanceTimeMs(1);
|
||||
// Send an SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(AllOf(Field(&SenderReportStats::packets_sent, Gt(0u)),
|
||||
Field(&SenderReportStats::bytes_sent, Gt(0u)))));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -27,6 +27,11 @@
|
||||
#include "test/rtp_header_parser.h"
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using ::testing::Field;
|
||||
using ::testing::Gt;
|
||||
using ::testing::Not;
|
||||
using ::testing::Optional;
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
@ -616,4 +621,102 @@ TEST_F(RtpRtcpImplTest, StoresPacketInfoForSentPackets) {
|
||||
/*is_last=*/1)));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats are not available if no RTCP SR was sent.
|
||||
TEST_F(RtpRtcpImplTest, SenderReportStatsNotAvailable) {
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(), Eq(absl::nullopt));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats are available if an RTCP SR was sent.
|
||||
TEST_F(RtpRtcpImplTest, SenderReportStatsAvailable) {
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
// Send an SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(), Not(Eq(absl::nullopt)));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats are not available if an RTCP SR with an
|
||||
// unexpected SSRC is received.
|
||||
TEST_F(RtpRtcpImplTest, SenderReportStatsNotUpdatedWithUnexpectedSsrc) {
|
||||
constexpr uint32_t kUnexpectedSenderSsrc = 0x87654321;
|
||||
static_assert(kUnexpectedSenderSsrc != kSenderSsrc, "");
|
||||
// Forge a sender report and pass it to the receiver as if an RTCP SR were
|
||||
// sent by an unexpected sender.
|
||||
rtcp::SenderReport sr;
|
||||
sr.SetSenderSsrc(kUnexpectedSenderSsrc);
|
||||
sr.SetNtp({/*seconds=*/1u, /*fractions=*/1u << 31});
|
||||
sr.SetPacketCount(123u);
|
||||
sr.SetOctetCount(456u);
|
||||
auto raw_packet = sr.Build();
|
||||
receiver_.impl_->IncomingRtcpPacket(raw_packet.data(), raw_packet.size());
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(), Eq(absl::nullopt));
|
||||
}
|
||||
|
||||
// Checks the stats derived from the last received RTCP SR are set correctly.
|
||||
TEST_F(RtpRtcpImplTest, SenderReportStatsCheckStatsFromLastReport) {
|
||||
using SenderReportStats = RtpRtcpInterface::SenderReportStats;
|
||||
const NtpTime ntp(/*seconds=*/1u, /*fractions=*/1u << 31);
|
||||
constexpr uint32_t kPacketCount = 123u;
|
||||
constexpr uint32_t kOctetCount = 456u;
|
||||
// Forge a sender report and pass it to the receiver as if an RTCP SR were
|
||||
// sent by the sender.
|
||||
rtcp::SenderReport sr;
|
||||
sr.SetSenderSsrc(kSenderSsrc);
|
||||
sr.SetNtp(ntp);
|
||||
sr.SetPacketCount(kPacketCount);
|
||||
sr.SetOctetCount(kOctetCount);
|
||||
auto raw_packet = sr.Build();
|
||||
receiver_.impl_->IncomingRtcpPacket(raw_packet.data(), raw_packet.size());
|
||||
|
||||
EXPECT_THAT(
|
||||
receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(AllOf(Field(&SenderReportStats::last_remote_timestamp, Eq(ntp)),
|
||||
Field(&SenderReportStats::packets_sent, Eq(kPacketCount)),
|
||||
Field(&SenderReportStats::bytes_sent, Eq(kOctetCount)))));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats count equals the number of sent RTCP SRs.
|
||||
TEST_F(RtpRtcpImplTest, SenderReportStatsCount) {
|
||||
using SenderReportStats = RtpRtcpInterface::SenderReportStats;
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
// Send the first SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(Field(&SenderReportStats::reports_count, Eq(1u))));
|
||||
// Send the second SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(Field(&SenderReportStats::reports_count, Eq(2u))));
|
||||
}
|
||||
|
||||
// Checks that the sender report stats include a valid arrival time if an RTCP
|
||||
// SR was sent.
|
||||
TEST_F(RtpRtcpImplTest, SenderReportStatsArrivalTimestampSet) {
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
// Send an SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
auto stats = receiver_.impl_->GetSenderReportStats();
|
||||
ASSERT_THAT(stats, Not(Eq(absl::nullopt)));
|
||||
EXPECT_TRUE(stats->last_arrival_timestamp.Valid());
|
||||
}
|
||||
|
||||
// Checks that the packet and byte counters from an RTCP SR are not zero once
|
||||
// a frame is sent.
|
||||
TEST_F(RtpRtcpImplTest, SenderReportStatsPacketByteCounters) {
|
||||
using SenderReportStats = RtpRtcpInterface::SenderReportStats;
|
||||
// Send a frame in order to send an SR.
|
||||
SendFrame(&sender_, sender_video_.get(), kBaseLayerTid);
|
||||
ASSERT_THAT(sender_.transport_.rtp_packets_sent_, Gt(0));
|
||||
// Advance time otherwise the RTCP SR report will not include any packets
|
||||
// generated by `SendFrame()`.
|
||||
clock_.AdvanceTimeMilliseconds(1);
|
||||
// Send an SR.
|
||||
ASSERT_THAT(sender_.impl_->SendRTCP(kRtcpReport), Eq(0));
|
||||
EXPECT_THAT(receiver_.impl_->GetSenderReportStats(),
|
||||
Optional(AllOf(Field(&SenderReportStats::packets_sent, Gt(0u)),
|
||||
Field(&SenderReportStats::bytes_sent, Gt(0u)))));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "modules/rtp_rtcp/source/rtp_sequence_number_map.h"
|
||||
#include "modules/rtp_rtcp/source/video_fec_generator.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "system_wrappers/include/ntp_time.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -152,6 +153,27 @@ class RtpRtcpInterface : public RtcpFeedbackSenderInterface {
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Configuration);
|
||||
};
|
||||
|
||||
// Stats for RTCP sender reports (SR) for a specific SSRC.
|
||||
// Refer to https://tools.ietf.org/html/rfc3550#section-6.4.1.
|
||||
struct SenderReportStats {
|
||||
// Arrival NPT timestamp for the last received RTCP SR.
|
||||
NtpTime last_arrival_timestamp;
|
||||
// Received (a.k.a., remote) NTP timestamp for the last received RTCP SR.
|
||||
NtpTime last_remote_timestamp;
|
||||
// Total number of RTP data packets transmitted by the sender since starting
|
||||
// transmission up until the time this SR packet was generated. The count
|
||||
// should be reset if the sender changes its SSRC identifier.
|
||||
uint32_t packets_sent;
|
||||
// Total number of payload octets (i.e., not including header or padding)
|
||||
// transmitted in RTP data packets by the sender since starting transmission
|
||||
// up until the time this SR packet was generated. The count should be reset
|
||||
// if the sender changes its SSRC identifier.
|
||||
uint64_t bytes_sent;
|
||||
// Total number of RTCP SR blocks received.
|
||||
// https://www.w3.org/TR/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats-reportssent.
|
||||
uint64_t reports_count;
|
||||
};
|
||||
|
||||
// **************************************************************************
|
||||
// Receiver functions
|
||||
// **************************************************************************
|
||||
@ -372,6 +394,8 @@ class RtpRtcpInterface : public RtcpFeedbackSenderInterface {
|
||||
// ReportBlockData represents the latest Report Block that was received for
|
||||
// that pair.
|
||||
virtual std::vector<ReportBlockData> GetLatestReportBlockData() const = 0;
|
||||
// Returns stats based on the received RTCP SRs.
|
||||
virtual absl::optional<SenderReportStats> GetSenderReportStats() const = 0;
|
||||
|
||||
// (REMB) Receiver Estimated Max Bitrate.
|
||||
// Schedules sending REMB on next and following sender/receiver reports.
|
||||
|
||||
@ -377,7 +377,9 @@ void RtpVideoStreamReceiver::AddReceiveCodec(
|
||||
absl::optional<Syncable::Info> RtpVideoStreamReceiver::GetSyncInfo() const {
|
||||
Syncable::Info info;
|
||||
if (rtp_rtcp_->RemoteNTP(&info.capture_time_ntp_secs,
|
||||
&info.capture_time_ntp_frac, nullptr, nullptr,
|
||||
&info.capture_time_ntp_frac,
|
||||
/*rtcp_arrival_time_secs=*/nullptr,
|
||||
/*rtcp_arrival_time_frac=*/nullptr,
|
||||
&info.capture_time_source_clock) != 0) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
@ -346,7 +346,9 @@ absl::optional<Syncable::Info> RtpVideoStreamReceiver2::GetSyncInfo() const {
|
||||
RTC_DCHECK_RUN_ON(&worker_task_checker_);
|
||||
Syncable::Info info;
|
||||
if (rtp_rtcp_->RemoteNTP(&info.capture_time_ntp_secs,
|
||||
&info.capture_time_ntp_frac, nullptr, nullptr,
|
||||
&info.capture_time_ntp_frac,
|
||||
/*rtcp_arrival_time_secs=*/nullptr,
|
||||
/*rtcp_arrival_time_frac=*/nullptr,
|
||||
&info.capture_time_source_clock) != 0) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user