Extend testing of prAnswer
- Modify munger to take (mutable) std::unique_ptr<SessionDescriptionInterface> rather than cricket::SessionDescription (that latter is embedded in the former) - For all pranswer test cases, do a final SetRemoteDescription(kAnswer) and check that signaling_state == stable Add new test cases: 1) A test case that only applies it as prAnswer on caller (callee is stable) 2) A test case that "scramble" sdb between prAnswer and Anser. Bug: None Change-Id: Ifedd92ade01ae781a2e59d0569133c486c7093fe Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/360781 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Jonas Oreland <jonaso@webrtc.org> Commit-Queue: Jonas Oreland <jonaso@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42891}
This commit is contained in:
parent
2c637aa16f
commit
a49abbb3b6
@ -2440,6 +2440,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
||||
"../rtc_base:network",
|
||||
"../rtc_base:network_constants",
|
||||
"../rtc_base:null_socket_server",
|
||||
"../rtc_base:random",
|
||||
"../rtc_base:refcount",
|
||||
"../rtc_base:rtc_base_tests_utils",
|
||||
"../rtc_base:rtc_certificate_generator",
|
||||
|
||||
@ -111,8 +111,8 @@ class DataChannelIntegrationTestUnifiedPlan
|
||||
: PeerConnectionIntegrationBaseTest(SdpSemantics::kUnifiedPlan) {}
|
||||
};
|
||||
|
||||
void MakeActiveSctpOffer(cricket::SessionDescription* desc) {
|
||||
auto& transport_infos = desc->transport_infos();
|
||||
void MakeActiveSctpOffer(std::unique_ptr<SessionDescriptionInterface>& desc) {
|
||||
auto& transport_infos = desc->description()->transport_infos();
|
||||
for (auto& transport_info : transport_infos) {
|
||||
transport_info.description.connection_role = cricket::CONNECTIONROLE_ACTIVE;
|
||||
}
|
||||
@ -770,9 +770,10 @@ TEST_P(DataChannelIntegrationTest, SctpDataChannelToAudioVideoUpgrade) {
|
||||
ASSERT_TRUE(ExpectNewFrames(media_expectations));
|
||||
}
|
||||
|
||||
static void MakeSpecCompliantSctpOffer(cricket::SessionDescription* desc) {
|
||||
static void MakeSpecCompliantSctpOffer(
|
||||
std::unique_ptr<SessionDescriptionInterface>& desc) {
|
||||
cricket::SctpDataContentDescription* dcd_offer =
|
||||
GetFirstSctpDataContentDescription(desc);
|
||||
GetFirstSctpDataContentDescription(desc->description());
|
||||
// See https://crbug.com/webrtc/11211 - this function is a no-op
|
||||
ASSERT_TRUE(dcd_offer);
|
||||
dcd_offer->set_use_sctpmap(false);
|
||||
@ -913,10 +914,11 @@ TEST_P(DataChannelIntegrationTest,
|
||||
ConnectFakeSignaling();
|
||||
caller()->CreateDataChannel();
|
||||
|
||||
callee()->SetReceivedSdpMunger([this](cricket::SessionDescription* desc) {
|
||||
MakeActiveSctpOffer(desc);
|
||||
callee()->CreateDataChannel();
|
||||
});
|
||||
callee()->SetReceivedSdpMunger(
|
||||
[this](std::unique_ptr<SessionDescriptionInterface>& desc) {
|
||||
MakeActiveSctpOffer(desc);
|
||||
callee()->CreateDataChannel();
|
||||
});
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
|
||||
|
||||
@ -84,6 +84,7 @@
|
||||
#include "rtc_base/firewall_socket_server.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/random.h"
|
||||
#include "rtc_base/socket_address.h"
|
||||
#include "rtc_base/ssl_certificate.h"
|
||||
#include "rtc_base/ssl_fingerprint.h"
|
||||
@ -605,9 +606,10 @@ TEST_P(PeerConnectionIntegrationTest, BundlingEnabledWhileIceRestartOccurs) {
|
||||
caller()->AddAudioVideoTracks();
|
||||
callee()->AddAudioVideoTracks();
|
||||
// Remove the bundle group from the SDP received by the callee.
|
||||
callee()->SetReceivedSdpMunger([](cricket::SessionDescription* desc) {
|
||||
desc->RemoveGroupByName("BUNDLE");
|
||||
});
|
||||
callee()->SetReceivedSdpMunger(
|
||||
[](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
sdp->description()->RemoveGroupByName("BUNDLE");
|
||||
});
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
{
|
||||
@ -673,11 +675,12 @@ TEST_P(PeerConnectionIntegrationTest, RotatedVideoWithoutCVOExtension) {
|
||||
callee()->CreateLocalVideoTrackWithRotation(kVideoRotation_270));
|
||||
|
||||
// Remove the CVO extension from the offered SDP.
|
||||
callee()->SetReceivedSdpMunger([](cricket::SessionDescription* desc) {
|
||||
cricket::VideoContentDescription* video =
|
||||
GetFirstVideoContentDescription(desc);
|
||||
video->ClearRtpHeaderExtensions();
|
||||
});
|
||||
callee()->SetReceivedSdpMunger(
|
||||
[](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
cricket::VideoContentDescription* video =
|
||||
GetFirstVideoContentDescription(sdp->description());
|
||||
video->ClearRtpHeaderExtensions();
|
||||
});
|
||||
// Wait for video frames to be received by both sides.
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
@ -845,8 +848,8 @@ TEST_P(PeerConnectionIntegrationTest, VideoRejectedInSubsequentOffer) {
|
||||
// Renegotiate, rejecting the video m= section.
|
||||
if (sdp_semantics_ == SdpSemantics::kPlanB_DEPRECATED) {
|
||||
caller()->SetGeneratedSdpMunger(
|
||||
[](cricket::SessionDescription* description) {
|
||||
for (cricket::ContentInfo& content : description->contents()) {
|
||||
[](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
for (cricket::ContentInfo& content : sdp->description()->contents()) {
|
||||
if (cricket::IsVideoContent(&content)) {
|
||||
content.rejected = true;
|
||||
}
|
||||
@ -1010,10 +1013,11 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
}
|
||||
|
||||
// Used for the test below.
|
||||
void RemoveBundleGroupSsrcsAndMidExtension(cricket::SessionDescription* desc) {
|
||||
RemoveSsrcsAndKeepMsids(desc);
|
||||
desc->RemoveGroupByName("BUNDLE");
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
void RemoveBundleGroupSsrcsAndMidExtension(
|
||||
std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
RemoveSsrcsAndKeepMsids(sdp);
|
||||
sdp->description()->RemoveGroupByName("BUNDLE");
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
cricket::MediaContentDescription* media = content.media_description();
|
||||
cricket::RtpHeaderExtensions extensions = media->rtp_header_extensions();
|
||||
extensions.erase(std::remove_if(extensions.begin(), extensions.end(),
|
||||
@ -1058,9 +1062,9 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
|
||||
// Used for the test below.
|
||||
void ModifyPayloadTypesAndRemoveMidExtension(
|
||||
cricket::SessionDescription* desc) {
|
||||
std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
int pt = 96;
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
cricket::MediaContentDescription* media = content.media_description();
|
||||
cricket::RtpHeaderExtensions extensions = media->rtp_header_extensions();
|
||||
extensions.erase(std::remove_if(extensions.begin(), extensions.end(),
|
||||
@ -1154,9 +1158,10 @@ TEST_P(PeerConnectionIntegrationTest, EndToEndCallWithTwoVideoTracks) {
|
||||
ASSERT_TRUE(ExpectNewFrames(media_expectations));
|
||||
}
|
||||
|
||||
static void MakeSpecCompliantMaxBundleOffer(cricket::SessionDescription* desc) {
|
||||
static void MakeSpecCompliantMaxBundleOffer(
|
||||
std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
bool first = true;
|
||||
for (cricket::ContentInfo& content : desc->contents()) {
|
||||
for (cricket::ContentInfo& content : sdp->description()->contents()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
continue;
|
||||
@ -1164,7 +1169,8 @@ static void MakeSpecCompliantMaxBundleOffer(cricket::SessionDescription* desc) {
|
||||
content.bundle_only = true;
|
||||
}
|
||||
first = true;
|
||||
for (cricket::TransportInfo& transport : desc->transport_infos()) {
|
||||
for (cricket::TransportInfo& transport :
|
||||
sdp->description()->transport_infos()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
continue;
|
||||
@ -2567,9 +2573,10 @@ TEST_P(PeerConnectionIntegrationTest, CodecNamesAreCaseInsensitive) {
|
||||
|
||||
// Remove all but one audio/video codec (opus and VP8), and change the
|
||||
// casing of the caller's generated offer.
|
||||
caller()->SetGeneratedSdpMunger([](cricket::SessionDescription* description) {
|
||||
caller()->SetGeneratedSdpMunger([](std::unique_ptr<
|
||||
SessionDescriptionInterface>& sdp) {
|
||||
cricket::AudioContentDescription* audio =
|
||||
GetFirstAudioContentDescription(description);
|
||||
GetFirstAudioContentDescription(sdp->description());
|
||||
ASSERT_NE(nullptr, audio);
|
||||
auto audio_codecs = audio->codecs();
|
||||
audio_codecs.erase(std::remove_if(audio_codecs.begin(), audio_codecs.end(),
|
||||
@ -2582,7 +2589,7 @@ TEST_P(PeerConnectionIntegrationTest, CodecNamesAreCaseInsensitive) {
|
||||
audio->set_codecs(audio_codecs);
|
||||
|
||||
cricket::VideoContentDescription* video =
|
||||
GetFirstVideoContentDescription(description);
|
||||
GetFirstVideoContentDescription(sdp->description());
|
||||
ASSERT_NE(nullptr, video);
|
||||
auto video_codecs = video->codecs();
|
||||
video_codecs.erase(std::remove_if(video_codecs.begin(), video_codecs.end(),
|
||||
@ -3231,9 +3238,9 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
ConnectFakeSignaling();
|
||||
caller()->AddVideoTrack();
|
||||
callee()->AddVideoTrack();
|
||||
auto munger = [](cricket::SessionDescription* desc) {
|
||||
auto munger = [](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
cricket::VideoContentDescription* video =
|
||||
GetFirstVideoContentDescription(desc);
|
||||
GetFirstVideoContentDescription(sdp->description());
|
||||
auto codecs = video->codecs();
|
||||
for (auto&& codec : codecs) {
|
||||
if (codec.name == "H264") {
|
||||
@ -3254,17 +3261,18 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
// Observe that after munging the parameter is present in generated SDP.
|
||||
caller()->SetGeneratedSdpMunger([](cricket::SessionDescription* desc) {
|
||||
cricket::VideoContentDescription* video =
|
||||
GetFirstVideoContentDescription(desc);
|
||||
for (auto&& codec : video->codecs()) {
|
||||
if (codec.name == "H264") {
|
||||
std::string value;
|
||||
EXPECT_TRUE(
|
||||
codec.GetParam(cricket::kH264FmtpSpsPpsIdrInKeyframe, &value));
|
||||
}
|
||||
}
|
||||
});
|
||||
caller()->SetGeneratedSdpMunger(
|
||||
[](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
cricket::VideoContentDescription* video =
|
||||
GetFirstVideoContentDescription(sdp->description());
|
||||
for (auto&& codec : video->codecs()) {
|
||||
if (codec.name == "H264") {
|
||||
std::string value;
|
||||
EXPECT_TRUE(
|
||||
codec.GetParam(cricket::kH264FmtpSpsPpsIdrInKeyframe, &value));
|
||||
}
|
||||
}
|
||||
});
|
||||
caller()->CreateOfferAndWait();
|
||||
}
|
||||
|
||||
@ -3785,24 +3793,25 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
auto send_transceiver = audio_transceiver_or_error.MoveValue();
|
||||
// Munge the SDP to include NACK and RRTR on Opus, and remove all other
|
||||
// codecs.
|
||||
caller()->SetGeneratedSdpMunger([](cricket::SessionDescription* desc) {
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
cricket::MediaContentDescription* media = content.media_description();
|
||||
std::vector<cricket::Codec> codecs = media->codecs();
|
||||
std::vector<cricket::Codec> codecs_out;
|
||||
for (cricket::Codec codec : codecs) {
|
||||
if (codec.name == "opus") {
|
||||
codec.AddFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty));
|
||||
codec.AddFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamRrtr, cricket::kParamValueEmpty));
|
||||
codecs_out.push_back(codec);
|
||||
caller()->SetGeneratedSdpMunger(
|
||||
[](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
cricket::MediaContentDescription* media = content.media_description();
|
||||
std::vector<cricket::Codec> codecs = media->codecs();
|
||||
std::vector<cricket::Codec> codecs_out;
|
||||
for (cricket::Codec codec : codecs) {
|
||||
if (codec.name == "opus") {
|
||||
codec.AddFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty));
|
||||
codec.AddFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamRrtr, cricket::kParamValueEmpty));
|
||||
codecs_out.push_back(codec);
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(codecs_out.empty());
|
||||
media->set_codecs(codecs_out);
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(codecs_out.empty());
|
||||
media->set_codecs(codecs_out);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
// Check for failure in helpers
|
||||
@ -3835,22 +3844,23 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan, VideoPacketLossCausesNack) {
|
||||
auto send_transceiver = video_transceiver_or_error.MoveValue();
|
||||
// Munge the SDP to include NACK and RRTR on VP8, and remove all other
|
||||
// codecs.
|
||||
caller()->SetGeneratedSdpMunger([](cricket::SessionDescription* desc) {
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
cricket::MediaContentDescription* media = content.media_description();
|
||||
std::vector<cricket::Codec> codecs = media->codecs();
|
||||
std::vector<cricket::Codec> codecs_out;
|
||||
for (cricket::Codec codec : codecs) {
|
||||
if (codec.name == "VP8") {
|
||||
ASSERT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
||||
codecs_out.push_back(codec);
|
||||
caller()->SetGeneratedSdpMunger(
|
||||
[](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
cricket::MediaContentDescription* media = content.media_description();
|
||||
std::vector<cricket::Codec> codecs = media->codecs();
|
||||
std::vector<cricket::Codec> codecs_out;
|
||||
for (cricket::Codec codec : codecs) {
|
||||
if (codec.name == "VP8") {
|
||||
ASSERT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
|
||||
cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
|
||||
codecs_out.push_back(codec);
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(codecs_out.empty());
|
||||
media->set_codecs(codecs_out);
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(codecs_out.empty());
|
||||
media->set_codecs(codecs_out);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
// Check for failure in helpers
|
||||
@ -3877,14 +3887,181 @@ TEST_F(PeerConnectionIntegrationTestUnifiedPlan, PrAnswerStateTransitions) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config));
|
||||
ConnectFakeSignaling();
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalAudioTrack());
|
||||
callee()->SetAnswerWithPrAnswer(true);
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack());
|
||||
|
||||
callee()->SetGeneratedSdpMunger(
|
||||
[](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
SetSdpType(sdp, SdpType::kPrAnswer);
|
||||
});
|
||||
std::unique_ptr<SessionDescriptionInterface> answer;
|
||||
caller()->SetReceivedSdpMunger(
|
||||
[&](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
answer = sdp->Clone();
|
||||
});
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_FALSE(HasFailure());
|
||||
EXPECT_EQ(caller()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kHaveRemotePrAnswer);
|
||||
EXPECT_EQ(callee()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kHaveLocalPrAnswer);
|
||||
// Note: there should be code here for applying the permanent answer.
|
||||
|
||||
// // Apply the pranswer as a definitive one.
|
||||
SetSdpType(answer, SdpType::kAnswer);
|
||||
EXPECT_TRUE(caller()->SetRemoteDescription(std::move(answer)));
|
||||
EXPECT_EQ(caller()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kStable);
|
||||
}
|
||||
|
||||
// Let caller get a prAnswer followed by answer.
|
||||
TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
PrAnswerStateTransitionsAsymmetric) {
|
||||
RTCConfiguration config;
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config));
|
||||
ConnectFakeSignaling();
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalAudioTrack());
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack());
|
||||
|
||||
std::unique_ptr<SessionDescriptionInterface> answer;
|
||||
caller()->SetReceivedSdpMunger(
|
||||
[&](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
answer = sdp->Clone();
|
||||
SetSdpType(sdp, SdpType::kPrAnswer);
|
||||
});
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_FALSE(HasFailure());
|
||||
EXPECT_EQ(caller()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kHaveRemotePrAnswer);
|
||||
EXPECT_EQ(callee()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kStable);
|
||||
|
||||
// // Apply the pranswer as a definitive one.
|
||||
EXPECT_TRUE(caller()->SetRemoteDescription(std::move(answer)));
|
||||
EXPECT_EQ(caller()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kStable);
|
||||
}
|
||||
|
||||
int ReassignPayloadIds(std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
int swaps = 0;
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
if (!content.media_description()) {
|
||||
continue;
|
||||
}
|
||||
std::vector<cricket::Codec> codecs = content.media_description()->codecs();
|
||||
int left = 0;
|
||||
int right = codecs.size() - 1;
|
||||
while (left < right) {
|
||||
if (!codecs[left].IsMediaCodec()) {
|
||||
left++;
|
||||
continue;
|
||||
}
|
||||
if (!codecs[right].IsMediaCodec()) {
|
||||
right--;
|
||||
continue;
|
||||
}
|
||||
auto tmp = codecs[left].id;
|
||||
codecs[left].id = codecs[right].id;
|
||||
codecs[right].id = tmp;
|
||||
left++;
|
||||
right--;
|
||||
swaps++;
|
||||
}
|
||||
content.media_description()->set_codecs(codecs);
|
||||
}
|
||||
return swaps;
|
||||
}
|
||||
|
||||
int SetNewSsrcs(std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
int assignments = 0;
|
||||
std::unordered_set<uint32_t> already_used_ssrcs;
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
if (!content.media_description()) {
|
||||
continue;
|
||||
}
|
||||
for (const auto& stream : content.media_description()->streams()) {
|
||||
for (const auto& ssrc : stream.ssrcs) {
|
||||
already_used_ssrcs.insert(ssrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Random random(/* random_seed= */ 77);
|
||||
auto ssrc_generator = [&]() -> uint32_t {
|
||||
do {
|
||||
auto ssrc = random.Rand(1u, 0xFFFFFFF0u);
|
||||
if (already_used_ssrcs.find(ssrc) == already_used_ssrcs.end()) {
|
||||
already_used_ssrcs.insert(ssrc);
|
||||
return ssrc;
|
||||
}
|
||||
} while (true);
|
||||
};
|
||||
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
if (!content.media_description()) {
|
||||
continue;
|
||||
}
|
||||
for (auto& stream : content.media_description()->mutable_streams()) {
|
||||
// Only reassign primary ssrc for now...
|
||||
// but we should maybe also reassign ssrcs for ssrc groups?.
|
||||
if (stream.ssrcs.size() == 1) {
|
||||
assignments++;
|
||||
stream.ssrcs[0] = ssrc_generator();
|
||||
}
|
||||
}
|
||||
}
|
||||
return assignments;
|
||||
}
|
||||
|
||||
void SetNewFingerprint(std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
auto identity = rtc::SSLIdentity::Create("NewIdentity", rtc::KT_DEFAULT);
|
||||
auto new_fingerprint =
|
||||
rtc::SSLFingerprint::CreateUnique("sha-256", *identity.get());
|
||||
for (auto& transport_info : sdp->description()->transport_infos()) {
|
||||
transport_info.description.identity_fingerprint =
|
||||
absl::WrapUnique(new rtc::SSLFingerprint(*new_fingerprint.get()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
|
||||
PrAnswerStateTransitionsAsymmetricScrambled) {
|
||||
RTCConfiguration config;
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config));
|
||||
ConnectFakeSignaling();
|
||||
webrtc::RtpEncodingParameters init_send_encodings;
|
||||
init_send_encodings.active = false;
|
||||
caller()->pc()->AddTrack(caller()->CreateLocalAudioTrack(), {"name"},
|
||||
{init_send_encodings});
|
||||
caller()->pc()->AddTrack(caller()->CreateLocalVideoTrack(), {"name"},
|
||||
{init_send_encodings});
|
||||
callee()->pc()->AddTrack(callee()->CreateLocalAudioTrack(), {"name"},
|
||||
{init_send_encodings});
|
||||
callee()->pc()->AddTrack(callee()->CreateLocalVideoTrack(), {"name"},
|
||||
{init_send_encodings});
|
||||
|
||||
std::unique_ptr<SessionDescriptionInterface> answer;
|
||||
caller()->SetReceivedSdpMunger(
|
||||
[&](std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
answer = sdp->Clone();
|
||||
SetSdpType(sdp, SdpType::kPrAnswer);
|
||||
});
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
|
||||
ASSERT_FALSE(HasFailure());
|
||||
ASSERT_EQ(caller()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kHaveRemotePrAnswer);
|
||||
ASSERT_EQ(callee()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kStable);
|
||||
|
||||
// Now scramble the answer sdp so that it (really!) different from the first
|
||||
// prAnswer.
|
||||
// Note: this is maybe {possibly...probably?} a spec violation.
|
||||
ASSERT_GT(SetNewSsrcs(answer), 0);
|
||||
ASSERT_GT(ReassignPayloadIds(answer), 0);
|
||||
SetNewFingerprint(answer);
|
||||
|
||||
// Apply the modified answer as a definitive one.
|
||||
EXPECT_TRUE(caller()->SetRemoteDescription(std::move(answer)));
|
||||
EXPECT_EQ(caller()->pc()->signaling_state(),
|
||||
PeerConnectionInterface::kStable);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -18,15 +18,16 @@ PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
void RemoveSsrcsAndMsids(cricket::SessionDescription* desc) {
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
void RemoveSsrcsAndMsids(std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
content.media_description()->mutable_streams().clear();
|
||||
}
|
||||
desc->set_msid_signaling(0);
|
||||
sdp->description()->set_msid_signaling(0);
|
||||
}
|
||||
|
||||
void RemoveSsrcsAndKeepMsids(cricket::SessionDescription* desc) {
|
||||
for (ContentInfo& content : desc->contents()) {
|
||||
void RemoveSsrcsAndKeepMsids(
|
||||
std::unique_ptr<SessionDescriptionInterface>& sdp) {
|
||||
for (ContentInfo& content : sdp->description()->contents()) {
|
||||
std::string track_id;
|
||||
std::vector<std::string> stream_ids;
|
||||
if (!content.media_description()->streams().empty()) {
|
||||
@ -43,6 +44,13 @@ void RemoveSsrcsAndKeepMsids(cricket::SessionDescription* desc) {
|
||||
}
|
||||
}
|
||||
|
||||
void SetSdpType(std::unique_ptr<SessionDescriptionInterface>& sdp,
|
||||
SdpType sdpType) {
|
||||
std::string str;
|
||||
sdp->ToString(&str);
|
||||
sdp = CreateSessionDescription(sdpType, str);
|
||||
}
|
||||
|
||||
int FindFirstMediaStatsIndexByKind(
|
||||
const std::string& kind,
|
||||
const std::vector<const RTCInboundRtpStreamStats*>& inbound_rtps) {
|
||||
|
||||
@ -165,11 +165,16 @@ PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions();
|
||||
|
||||
// Remove all stream information (SSRCs, track IDs, etc.) and "msid-semantic"
|
||||
// attribute from received SDP, simulating a legacy endpoint.
|
||||
void RemoveSsrcsAndMsids(cricket::SessionDescription* desc);
|
||||
void RemoveSsrcsAndMsids(std::unique_ptr<SessionDescriptionInterface>& desc);
|
||||
|
||||
// Removes all stream information besides the stream ids, simulating an
|
||||
// endpoint that only signals a=msid lines to convey stream_ids.
|
||||
void RemoveSsrcsAndKeepMsids(cricket::SessionDescription* desc);
|
||||
void RemoveSsrcsAndKeepMsids(
|
||||
std::unique_ptr<SessionDescriptionInterface>& desc);
|
||||
|
||||
// Set SdpType.
|
||||
void SetSdpType(std::unique_ptr<SessionDescriptionInterface>& sdp,
|
||||
SdpType sdpType);
|
||||
|
||||
// Replaces the stream's primary SSRC and updates the first SSRC of all
|
||||
// ssrc-groups.
|
||||
@ -265,14 +270,16 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
// used to test SDP being applied that a PeerConnection would normally not
|
||||
// generate, but a non-JSEP endpoint might.
|
||||
void SetReceivedSdpMunger(
|
||||
std::function<void(cricket::SessionDescription*)> munger) {
|
||||
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
|
||||
munger) {
|
||||
received_sdp_munger_ = std::move(munger);
|
||||
}
|
||||
|
||||
// Similar to the above, but this is run on SDP immediately after it's
|
||||
// generated.
|
||||
void SetGeneratedSdpMunger(
|
||||
std::function<void(cricket::SessionDescription*)> munger) {
|
||||
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
|
||||
munger) {
|
||||
generated_sdp_munger_ = std::move(munger);
|
||||
}
|
||||
|
||||
@ -658,9 +665,21 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
candidates_expected_ = candidate_count;
|
||||
}
|
||||
|
||||
// For testing PR-Answer functionality
|
||||
// If true, an offer will get a pr-answer back.
|
||||
void SetAnswerWithPrAnswer(bool value) { answer_with_pr_answer_ = value; }
|
||||
bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc) {
|
||||
auto observer = rtc::make_ref_counted<FakeSetRemoteDescriptionObserver>();
|
||||
std::string str;
|
||||
desc->ToString(&str);
|
||||
RTC_LOG(LS_INFO) << debug_name_ << ": SetRemoteDescription SDP:\n" << str;
|
||||
pc()->SetRemoteDescription(std::move(desc), observer); // desc.release());
|
||||
RemoveUnusedVideoRenderers();
|
||||
EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
|
||||
auto err = observer->error();
|
||||
if (!err.ok()) {
|
||||
RTC_LOG(LS_WARNING) << debug_name_
|
||||
<< ": SetRemoteDescription error: " << err.message();
|
||||
}
|
||||
return observer->error().ok();
|
||||
}
|
||||
|
||||
private:
|
||||
// Constructor used by friend class PeerConnectionIntegrationBaseTest.
|
||||
@ -736,7 +755,7 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
std::unique_ptr<SessionDescriptionInterface> desc =
|
||||
CreateSessionDescription(SdpType::kOffer, msg);
|
||||
if (received_sdp_munger_) {
|
||||
received_sdp_munger_(desc->description());
|
||||
received_sdp_munger_(desc);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(SetRemoteDescription(std::move(desc)));
|
||||
@ -748,11 +767,6 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
}
|
||||
auto answer = CreateAnswer();
|
||||
ASSERT_NE(nullptr, answer);
|
||||
if (answer_with_pr_answer_) {
|
||||
std::string answer_string;
|
||||
answer->ToString(&answer_string);
|
||||
answer = CreateSessionDescription(SdpType::kPrAnswer, answer_string);
|
||||
}
|
||||
EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(answer)));
|
||||
}
|
||||
|
||||
@ -762,7 +776,7 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
std::unique_ptr<SessionDescriptionInterface> desc =
|
||||
CreateSessionDescription(type, msg);
|
||||
if (received_sdp_munger_) {
|
||||
received_sdp_munger_(desc->description());
|
||||
received_sdp_munger_(desc);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(SetRemoteDescription(std::move(desc)));
|
||||
@ -786,7 +800,7 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
}
|
||||
auto description = observer->MoveDescription();
|
||||
if (generated_sdp_munger_) {
|
||||
generated_sdp_munger_(description->description());
|
||||
generated_sdp_munger_(description);
|
||||
}
|
||||
return description;
|
||||
}
|
||||
@ -813,15 +827,6 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc) {
|
||||
auto observer = rtc::make_ref_counted<MockSetSessionDescriptionObserver>();
|
||||
RTC_LOG(LS_INFO) << debug_name_ << ": SetRemoteDescription";
|
||||
pc()->SetRemoteDescription(observer.get(), desc.release());
|
||||
RemoveUnusedVideoRenderers();
|
||||
EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
|
||||
return observer->result();
|
||||
}
|
||||
|
||||
// This is a work around to remove unused fake_video_renderers from
|
||||
// transceivers that have either stopped or are no longer receiving.
|
||||
void RemoveUnusedVideoRenderers() {
|
||||
@ -1059,8 +1064,10 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
|
||||
SdpSemantics sdp_semantics_;
|
||||
PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options_;
|
||||
std::function<void(cricket::SessionDescription*)> received_sdp_munger_;
|
||||
std::function<void(cricket::SessionDescription*)> generated_sdp_munger_;
|
||||
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
|
||||
received_sdp_munger_;
|
||||
std::function<void(std::unique_ptr<SessionDescriptionInterface>&)>
|
||||
generated_sdp_munger_;
|
||||
std::function<void()> remote_offer_handler_;
|
||||
MockAsyncDnsResolver* remote_async_dns_resolver_ = nullptr;
|
||||
// Result variables for the mock DNS resolver
|
||||
@ -1097,8 +1104,6 @@ class PeerConnectionIntegrationWrapper : public PeerConnectionObserver,
|
||||
uint64_t audio_concealed_stat_ = 0;
|
||||
std::string rtp_stats_id_;
|
||||
|
||||
bool answer_with_pr_answer_ = false;
|
||||
|
||||
ScopedTaskSafety task_safety_;
|
||||
|
||||
friend class PeerConnectionIntegrationBaseTest;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user