sdp: add rtcp-fb:* lines for common feedback
which potentially allows switching to that pattern in the future.
Video FEC mechanisms (ulpfec, flexfec-03, RED) that currently
do not have any feedback parameters but will still be considered "common" and feedback may be sent for them.
For audio this causes rtcp-feedback to be sent for G711 and G722 if negotiated.
BUG=webrtc:14802
Change-Id: I54852d39e176f918d4b36462526ceb40617b8fbe
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/290702
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39224}
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
index 3b34746..7a63ae4 100644
--- a/pc/webrtc_sdp.cc
+++ b/pc/webrtc_sdp.cc
@@ -1890,7 +1890,7 @@
template <class T>
void AddRtcpFbLines(const T& codec, std::string* message) {
- for (const cricket::FeedbackParam& param : codec.feedback_params.params()) {
+ for (const auto& param : codec.feedback_params.params()) {
rtc::StringBuilder os;
WriteRtcpFbHeader(codec.id, &os);
os << " " << param.id();
@@ -1901,6 +1901,30 @@
}
}
+template <class T>
+void AddWildcardRtcpFbLines(const std::vector<T>& codecs,
+ std::string* message) {
+ if (codecs.empty()) {
+ return;
+ }
+ for (const auto& param : codecs[0].feedback_params.params()) {
+ bool is_common_feedback = absl::c_all_of(codecs, [¶m](const T& codec) {
+ // FEC mechanisms like RED, ulpfec and flexfec have empty feedback.
+ return codec.feedback_params.params().empty() ||
+ codec.feedback_params.Has(param);
+ });
+ if (is_common_feedback) {
+ rtc::StringBuilder os;
+ WriteRtcpFbHeader(kWildcardPayloadType, &os);
+ os << " " << param.id();
+ if (!param.param().empty()) {
+ os << " " << param.param();
+ }
+ AddLine(os.str(), message);
+ }
+ }
+}
+
bool GetMinValue(const std::vector<int>& values, int* value) {
if (values.empty()) {
return false;
@@ -1944,6 +1968,9 @@
AddRtcpFbLines(codec, message);
AddFmtpLine(codec, message);
}
+ // rtcp-fb:* is added in addition to the per-codec feedback to allow
+ // downstream users time to upgrade their parsers.
+ AddWildcardRtcpFbLines(media_desc->as_video()->codecs(), message);
} else if (media_type == cricket::MEDIA_TYPE_AUDIO) {
std::vector<int> ptimes;
std::vector<int> maxptimes;
@@ -1975,6 +2002,9 @@
maxptimes.push_back(maxptime);
}
}
+ // rtcp-fb:* is added in addition to the per-codec feedback to allow
+ // downstream users time to upgrade their parsers.
+ AddWildcardRtcpFbLines(media_desc->as_audio()->codecs(), message);
// Populate the maxptime attribute with the smallest maxptime of all codecs
// under the same m-line.
int min_maxptime = INT_MAX;
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
index 9f1cfc9..3e5e9a0 100644
--- a/pc/webrtc_sdp_unittest.cc
+++ b/pc/webrtc_sdp_unittest.cc
@@ -3296,6 +3296,38 @@
TestSerialize(jdesc_output);
}
+TEST_F(WebRtcSdpTest, SerializeRtcpFbWildcard) {
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 18446744069414584320 18446462598732840960 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=video 3457 RTP/SAVPF 100 101 102 103\r\n"
+ "a=rtpmap:100 VP8/90000\r\n"
+ "a=rtcp-fb:100 nack\r\n"
+ "a=rtcp-fb:100 nack pli\r\n"
+ "a=rtpmap:101 rtx/90000\r\n"
+ "a=fmtp:101 apt=100\r\n"
+ "a=rtpmap:102 VP9/90000\r\n"
+ "a=rtcp-fb:102 nack\r\n"
+ "a=rtpmap:103 rtx/90000\r\n"
+ "a=fmtp:103 apt=102\r\n";
+ JsepSessionDescription jdesc(kDummyType);
+ SdpParseError error;
+ EXPECT_TRUE(webrtc::SdpDeserialize(sdp, &jdesc, &error));
+
+ std::string message = webrtc::SdpSerialize(jdesc);
+ // NACK is a common parameter so serialized with wildcard in addition to
+ // per-codec entries.
+ EXPECT_NE(message.find("\r\na=rtcp-fb:100 nack\r\n"), std::string::npos);
+ EXPECT_NE(message.find("\r\na=rtcp-fb:102 nack\r\n"), std::string::npos);
+ EXPECT_NE(message.find("\r\na=rtcp-fb:* nack\r\n"), std::string::npos);
+ // PLI is not a common parameter so no wildcard.
+ EXPECT_NE(message.find("\r\na=rtcp-fb:100 nack pli\r\n"), std::string::npos);
+ EXPECT_EQ(message.find("\r\na=rtcp-fb:102 nack pli\r\n"), std::string::npos);
+ EXPECT_EQ(message.find("\r\na=rtcp-fb:* nack pli\r\n"), std::string::npos);
+}
+
TEST_F(WebRtcSdpTest, DeserializeVideoFmtp) {
JsepSessionDescription jdesc_output(kDummyType);