[Stats] Explicit RTP-RTX and RTP-FEC mappings. Unblocks simulcast stats.
--- Background ---
The webrtc::VideoSendStream::StreamStats are converted into
VideoSenderInfo objects which turn into "outbound-rtp" stats objects in
getStats() (or "ssrc" objects in legacy getStats()).
StreamStats are created for each type of substream: RTP media streams,
RTX streams and FlexFEC streams - each with individual packet counters.
The RTX stream is responsible for retransmissions of a referenced media
stream and the FlexFEC stream is responsible for FEC of a referenced
media stream. RTX/FEC streams do not show up as separate objects in
getStats(). Only the media streams become "outbound-rtp" objects, but
their packet and byte counters have to include the RTX and FEC counters.
--- Overview of this CL ---
This CL adds MergeInfoAboutOutboundRtpSubstreams(). It takes
StreamStats of all kinds as input, and outputs media-only StreamStats
- incorporating the RTX and FEC counters into the relevant media
StreamStats.
The merged StreamStats objects is a smaller set of objects than the
non-merged counterparts, but when aggregating all packet counters
together we end up with exact same packet and count as before.
Because WebRtcVideoSendStream::GetVideoSenderInfo() currently aggregates
the StreamStats into a single VideoSenderInfo (single "outbound-rtp"),
this CL should not have any observable side-effects. Prior to this CL:
aggregate StreamStats. After this CL: merge StreamStats and then
aggregate them.
However, when simulcast stats are implemented (WIP CL:
https://webrtc-review.googlesource.com/c/src/+/168120) each RTP media
stream should turn into an individual "outbound-rtp" object. We will
then no longer aggregate all StreamStats into a single "info". This CL
unblocks simulcast stats by providing StreamStats objects that could be
turned into individual VideoSenderInfos.
--- The Changes ---
1. Methods added to RtpConfig to be able to easily tell the relationship
between RTP, RTX and FEC ssrcs.
2. StreamStats gets a StreamType (kMedia, kRtx or kFlexfec) that
replaces the booleans (is_rtx, is_flexfec).
3. "referenced_media_ssrc" is added to StreamStats, making it possible
to tell which kRtx/kFlexFec stream stats need to be merged with which
kMedia StreamStats.
4. MergeInfoAboutOutboundRtpSubstreams() added and used.
Bug: webrtc:11439
Change-Id: Iaf9002041169a054ddfd32c7ea06bd1dc36c6bca
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/170826
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30869}
diff --git a/call/rtp_config.cc b/call/rtp_config.cc
index a23351b..d1db867 100644
--- a/call/rtp_config.cc
+++ b/call/rtp_config.cc
@@ -12,11 +12,29 @@
#include <cstdint>
+#include "absl/algorithm/container.h"
#include "api/array_view.h"
+#include "rtc_base/checks.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
+namespace {
+
+uint32_t FindAssociatedSsrc(uint32_t ssrc,
+ const std::vector<uint32_t>& ssrcs,
+ const std::vector<uint32_t>& associated_ssrcs) {
+ RTC_DCHECK_EQ(ssrcs.size(), associated_ssrcs.size());
+ for (size_t i = 0; i < ssrcs.size(); ++i) {
+ if (ssrcs[i] == ssrc)
+ return associated_ssrcs[i];
+ }
+ RTC_NOTREACHED();
+ return 0;
+}
+
+} // namespace
+
std::string LntfConfig::ToString() const {
return enabled ? "{enabled: true}" : "{enabled: false}";
}
@@ -124,4 +142,51 @@
ss << '}';
return ss.str();
}
+
+bool RtpConfig::IsMediaSsrc(uint32_t ssrc) const {
+ return absl::c_linear_search(ssrcs, ssrc);
+}
+
+bool RtpConfig::IsRtxSsrc(uint32_t ssrc) const {
+ return absl::c_linear_search(rtx.ssrcs, ssrc);
+}
+
+bool RtpConfig::IsFlexfecSsrc(uint32_t ssrc) const {
+ return flexfec.payload_type != -1 && ssrc == flexfec.ssrc;
+}
+
+absl::optional<uint32_t> RtpConfig::GetRtxSsrcAssociatedWithMediaSsrc(
+ uint32_t media_ssrc) const {
+ RTC_DCHECK(IsMediaSsrc(media_ssrc));
+ // If we don't use RTX there is no association.
+ if (rtx.ssrcs.empty())
+ return absl::nullopt;
+ // If we use RTX there MUST be an association ssrcs[i] <-> rtx.ssrcs[i].
+ RTC_DCHECK_EQ(ssrcs.size(), rtx.ssrcs.size());
+ return FindAssociatedSsrc(media_ssrc, ssrcs, rtx.ssrcs);
+}
+
+uint32_t RtpConfig::GetMediaSsrcAssociatedWithRtxSsrc(uint32_t rtx_ssrc) const {
+ RTC_DCHECK(IsRtxSsrc(rtx_ssrc));
+ // If we use RTX there MUST be an association ssrcs[i] <-> rtx.ssrcs[i].
+ RTC_DCHECK_EQ(ssrcs.size(), rtx.ssrcs.size());
+ return FindAssociatedSsrc(rtx_ssrc, rtx.ssrcs, ssrcs);
+}
+
+uint32_t RtpConfig::GetMediaSsrcAssociatedWithFlexfecSsrc(
+ uint32_t flexfec_ssrc) const {
+ RTC_DCHECK(IsFlexfecSsrc(flexfec_ssrc));
+ // If we use FlexFEC there MUST be an associated media ssrc.
+ //
+ // TODO(brandtr/hbos): The current implementation only supports an association
+ // with a single media ssrc. If multiple ssrcs are to be supported in the
+ // future, in order not to break GetStats()'s packet and byte counters, we
+ // must be able to tell how many packets and bytes have contributed to which
+ // SSRC.
+ RTC_DCHECK_EQ(1u, flexfec.protected_media_ssrcs.size());
+ uint32_t media_ssrc = flexfec.protected_media_ssrcs[0];
+ RTC_DCHECK(IsMediaSsrc(media_ssrc));
+ return media_ssrc;
+}
+
} // namespace webrtc