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:
Jonas Oreland 2024-08-29 10:50:50 +02:00 committed by WebRTC LUCI CQ
parent 2c637aa16f
commit a49abbb3b6
5 changed files with 303 additions and 110 deletions

View File

@ -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",

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -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;