Skip to content

Commit

Permalink
Add remote-outbound stats for audio streams
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Åsa Persson <[email protected]>
Reviewed-by: Gustaf Ullberg <[email protected]>
Commit-Queue: Alessio Bazzica <[email protected]>
Cr-Commit-Position: refs/heads/master@{#33452}
  • Loading branch information
alebzk authored and Commit Bot committed Mar 12, 2021
1 parent c80f955 commit bc1c93d
Show file tree
Hide file tree
Showing 13 changed files with 318 additions and 11 deletions.
33 changes: 24 additions & 9 deletions audio/channel_receive.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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_);
Expand All @@ -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;

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down
7 changes: 7 additions & 0 deletions audio/channel_receive.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions modules/rtp_rtcp/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
4 changes: 4 additions & 0 deletions modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
21 changes: 21 additions & 0 deletions modules/rtp_rtcp/source/rtp_rtcp_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions modules/rtp_rtcp/source/rtp_rtcp_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
21 changes: 21 additions & 0 deletions modules/rtp_rtcp/source/rtp_rtcp_impl2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions modules/rtp_rtcp/source/rtp_rtcp_impl2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
105 changes: 105 additions & 0 deletions modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Loading

0 comments on commit bc1c93d

Please sign in to comment.