Integrate RTP Header extension API with SDP munging

in order to not regress existing use-cases while following rules
described by the specification. This change now makes the existing
regression test pass after the spec-compliant modifications.

BUG=chromium:1051821

Change-Id: Ia384adf9a172ed88b5ec6a3cc5c478764a686cb9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/299002
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#39726}
This commit is contained in:
Philipp Hancke 2023-03-30 13:51:39 +02:00 committed by WebRTC LUCI CQ
parent 80558f49fa
commit 49e5587e64
4 changed files with 76 additions and 11 deletions

View File

@ -685,7 +685,9 @@ static bool CreateContentOffer(
// TODO(crbug.com/1051821): Configure the extension direction from
// the information in the media_description_options extension
// capability.
extensions.push_back(extension_with_id);
if (extension.direction != RtpTransceiverDirection::kStopped) {
extensions.push_back(extension_with_id);
}
}
}
}

View File

@ -2018,7 +2018,7 @@ TEST_F(MediaSessionDescriptionFactoryTest,
}
TEST_F(MediaSessionDescriptionFactoryTest,
AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
AllowsStoppedExtensionsToBeRemovedFromSubsequentOffer) {
MediaSessionOptions opts;
AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
RtpTransceiverDirection::kSendRecv, kActive,
@ -2026,12 +2026,12 @@ TEST_F(MediaSessionDescriptionFactoryTest,
opts.media_description_options.back().header_extensions = {
webrtc::RtpHeaderExtensionCapability("uri1", 1,
RtpTransceiverDirection::kSendRecv),
webrtc::RtpHeaderExtensionCapability("uri2", 1,
webrtc::RtpHeaderExtensionCapability("uri2", 2,
RtpTransceiverDirection::kSendRecv)};
auto offer = f1_.CreateOffer(opts, nullptr);
// Now add "uri2" as stopped to the options verify that the offer contains
// uri2 since it's already present since before.
// Check that a subsequent offer after setting "uri2" to stopped no longer
// contains the extension.
opts.media_description_options.back().header_extensions = {
webrtc::RtpHeaderExtensionCapability("uri1", 1,
RtpTransceiverDirection::kSendRecv),
@ -2043,8 +2043,7 @@ TEST_F(MediaSessionDescriptionFactoryTest,
ElementsAre(Property(
&ContentInfo::media_description,
Pointee(Property(&MediaContentDescription::rtp_header_extensions,
ElementsAre(Field(&RtpExtension::uri, "uri1"),
Field(&RtpExtension::uri, "uri2")))))));
ElementsAre(Field(&RtpExtension::uri, "uri1")))))));
}
TEST_F(MediaSessionDescriptionFactoryTest,

View File

@ -321,11 +321,11 @@ TEST_P(PeerConnectionHeaderExtensionTest,
}
}
// This test is a regression test for behavior that the API
// These tests are regression tests for behavior that the API
// enables in a proper way. It conflicts with the behavior
// of the API to only offer non-stopped extensions.
TEST_P(PeerConnectionHeaderExtensionTest,
SdpMungingWithoutApiUsageEnablesExtensions) {
SdpMungingAnswerWithoutApiUsageEnablesExtensions) {
cricket::MediaType media_type;
SdpSemantics semantics;
std::tie(media_type, semantics) = GetParam();
@ -371,7 +371,6 @@ TEST_P(PeerConnectionHeaderExtensionTest,
ASSERT_TRUE(pc->SetLocalDescription(std::move(modified_answer)));
auto session_description = pc->CreateOffer();
ASSERT_TRUE(session_description->ToString(&sdp));
EXPECT_THAT(session_description->description()
->contents()[0]
.media_description()
@ -382,6 +381,37 @@ TEST_P(PeerConnectionHeaderExtensionTest,
Field(&RtpExtension::uri, "uri4")));
}
TEST_P(PeerConnectionHeaderExtensionTest,
SdpMungingOfferWithoutApiUsageEnablesExtensions) {
cricket::MediaType media_type;
SdpSemantics semantics;
std::tie(media_type, semantics) = GetParam();
if (semantics != SdpSemantics::kUnifiedPlan)
return;
std::unique_ptr<PeerConnectionWrapper> pc =
CreatePeerConnection(media_type, semantics);
pc->AddTransceiver(media_type);
auto offer =
pc->CreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions());
std::string modified_sdp;
ASSERT_TRUE(offer->ToString(&modified_sdp));
modified_sdp += "a=extmap:1 uri1\r\n";
auto modified_offer = CreateSessionDescription(SdpType::kOffer, modified_sdp);
ASSERT_TRUE(pc->SetLocalDescription(std::move(modified_offer)));
auto offer2 =
pc->CreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions());
EXPECT_THAT(offer2->description()
->contents()[0]
.media_description()
->rtp_header_extensions(),
ElementsAre(Field(&RtpExtension::uri, "uri2"),
Field(&RtpExtension::uri, "uri3"),
Field(&RtpExtension::uri, "uri4"),
Field(&RtpExtension::uri, "uri1")));
}
TEST_P(PeerConnectionHeaderExtensionTest, EnablingExtensionsAfterRemoteOffer) {
cricket::MediaType media_type;
SdpSemantics semantics;

View File

@ -815,8 +815,37 @@ bool ContentHasHeaderExtension(const cricket::ContentInfo& content_info,
} // namespace
void UpdateRtpHeaderExtensionPreferencesFromSdpMunging(
const cricket::SessionDescription* description,
TransceiverList* transceivers) {
// This integrates the RTP Header Extension Control API and local SDP munging
// for backward compability reasons. If something was enabled in the local
// description via SDP munging, consider it non-stopped in the API as well
// so that is shows up in subsequent offers/answers.
RTC_DCHECK(description);
RTC_DCHECK(transceivers);
for (const auto& content : description->contents()) {
auto transceiver = transceivers->FindByMid(content.name);
if (!transceiver) {
continue;
}
auto extension_capabilities = transceiver->GetHeaderExtensionsToNegotiate();
// Set the capability of every extension we see here to "sendrecv".
for (auto& ext : content.media_description()->rtp_header_extensions()) {
auto it = absl::c_find_if(extension_capabilities,
[&ext](const RtpHeaderExtensionCapability c) {
return ext.uri == c.uri;
});
if (it != extension_capabilities.end()) {
it->direction = RtpTransceiverDirection::kSendRecv;
}
}
transceiver->SetHeaderExtensionsToNegotiate(extension_capabilities);
}
}
// This class stores state related to a SetRemoteDescription operation, captures
// and reports potential errors that migth occur and makes sure to notify the
// and reports potential errors that might occur and makes sure to notify the
// observer of the operation and the operations chain of completion.
class SdpOfferAnswerHandler::RemoteDescriptionOperation {
public:
@ -1816,6 +1845,11 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
local_ice_credentials_to_replace_->ClearIceCredentials();
}
if (IsUnifiedPlan()) {
UpdateRtpHeaderExtensionPreferencesFromSdpMunging(
local_description()->description(), transceivers());
}
return RTCError::OK();
}