Revert "Rewrite WebRtcSession BUNDLE tests as PeerConnection tests"
This reverts commit 096e367bfd58f9c24199852dcfdb6447b71c4324.
Reason for revert:
suspected of breaking chromium.webrtc.fyi:
WebRtcBrowserTest.NegotiateUnsupportedVideoCodec
WebRtcBrowserTest.NegotiateNonCryptoCall
android https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Android%20Tests%20%28dbg%29%20%28L%20Nexus5%29/builds/25506
linux https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Linux%20Tester/builds/38809
mac
https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Mac%20Tester/builds/44120
windows
https://uberchromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win10%20Tester/builds/9236
Original change's description:
> Rewrite WebRtcSession BUNDLE tests as PeerConnection tests
>
> Bug: webrtc:8222
> Change-Id: Id47e4544dc073564ad7e63d02865ca80dd5a85ff
> Reviewed-on: https://webrtc-review.googlesource.com/8280
> Commit-Queue: Steve Anton <steveanton@webrtc.org>
> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#20365}
TBR=steveanton@webrtc.org,deadbeef@webrtc.org
Change-Id: I571d8c7fdce4b47137260e0f3276ea4eb04a496c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:8222
Reviewed-on: https://webrtc-review.googlesource.com/14240
Reviewed-by: Olga Sharonova <olka@webrtc.org>
Commit-Queue: Olga Sharonova <olka@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20374}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 3e552c9..02a8e9a 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -391,7 +391,6 @@
"localaudiosource_unittest.cc",
"mediaconstraintsinterface_unittest.cc",
"mediastream_unittest.cc",
- "peerconnection_bundle_unittest.cc",
"peerconnection_crypto_unittest.cc",
"peerconnection_ice_unittest.cc",
"peerconnection_integrationtest.cc",
diff --git a/pc/peerconnection_bundle_unittest.cc b/pc/peerconnection_bundle_unittest.cc
deleted file mode 100644
index 6bc177d..0000000
--- a/pc/peerconnection_bundle_unittest.cc
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * Copyright 2017 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "api/peerconnectionproxy.h"
-#include "p2p/base/fakeportallocator.h"
-#include "p2p/base/teststunserver.h"
-#include "p2p/client/basicportallocator.h"
-#include "pc/mediasession.h"
-#include "pc/peerconnection.h"
-#include "pc/peerconnectionwrapper.h"
-#include "pc/sdputils.h"
-#ifdef WEBRTC_ANDROID
-#include "pc/test/androidtestinitializer.h"
-#endif
-#include "pc/test/fakeaudiocapturemodule.h"
-#include "rtc_base/fakenetwork.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/ptr_util.h"
-#include "rtc_base/virtualsocketserver.h"
-#include "test/gmock.h"
-
-namespace webrtc {
-
-using BundlePolicy = PeerConnectionInterface::BundlePolicy;
-using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
-using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
-using RtcpMuxPolicy = PeerConnectionInterface::RtcpMuxPolicy;
-using rtc::SocketAddress;
-using ::testing::ElementsAre;
-using ::testing::UnorderedElementsAre;
-using ::testing::Values;
-
-constexpr int kDefaultTimeout = 10000;
-
-// TODO(steveanton): These tests should be rewritten to use the standard
-// RtpSenderInterface/DtlsTransportInterface objects once they're available in
-// the API. The RtpSender can be used to determine which transport a given media
-// will use: https://www.w3.org/TR/webrtc/#dom-rtcrtpsender-transport
-
-class PeerConnectionWrapperForBundleTest : public PeerConnectionWrapper {
- public:
- using PeerConnectionWrapper::PeerConnectionWrapper;
-
- bool AddIceCandidateToMedia(cricket::Candidate* candidate,
- cricket::MediaType media_type) {
- auto* desc = pc()->remote_description()->description();
- for (size_t i = 0; i < desc->contents().size(); i++) {
- const auto& content = desc->contents()[i];
- auto* media_desc =
- static_cast<cricket::MediaContentDescription*>(content.description);
- if (media_desc->type() == media_type) {
- candidate->set_transport_name(content.name);
- JsepIceCandidate jsep_candidate(content.name, i, *candidate);
- return pc()->AddIceCandidate(&jsep_candidate);
- }
- }
- RTC_NOTREACHED();
- return false;
- }
-
- rtc::PacketTransportInternal* voice_rtp_transport_channel() {
- return (voice_channel() ? voice_channel()->rtp_dtls_transport() : nullptr);
- }
-
- rtc::PacketTransportInternal* voice_rtcp_transport_channel() {
- return (voice_channel() ? voice_channel()->rtcp_dtls_transport() : nullptr);
- }
-
- cricket::VoiceChannel* voice_channel() {
- return GetInternalPeerConnection()->voice_channel();
- }
-
- rtc::PacketTransportInternal* video_rtp_transport_channel() {
- return (video_channel() ? video_channel()->rtp_dtls_transport() : nullptr);
- }
-
- rtc::PacketTransportInternal* video_rtcp_transport_channel() {
- return (video_channel() ? video_channel()->rtcp_dtls_transport() : nullptr);
- }
-
- cricket::VideoChannel* video_channel() {
- return GetInternalPeerConnection()->video_channel();
- }
-
- PeerConnection* GetInternalPeerConnection() {
- auto* pci = reinterpret_cast<
- PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(pc());
- return reinterpret_cast<PeerConnection*>(pci->internal());
- }
-
- // Returns true if the stats indicate that an ICE connection is either in
- // progress or established with the given remote address.
- bool HasConnectionWithRemoteAddress(const SocketAddress& address) {
- auto report = GetStats();
- if (!report) {
- return false;
- }
- std::string matching_candidate_id;
- for (auto* ice_candidate_stats :
- report->GetStatsOfType<RTCRemoteIceCandidateStats>()) {
- if (*ice_candidate_stats->ip == address.HostAsURIString() &&
- *ice_candidate_stats->port == address.port()) {
- matching_candidate_id = ice_candidate_stats->id();
- break;
- }
- }
- if (matching_candidate_id.empty()) {
- return false;
- }
- for (auto* pair_stats :
- report->GetStatsOfType<RTCIceCandidatePairStats>()) {
- if (*pair_stats->remote_candidate_id == matching_candidate_id) {
- if (*pair_stats->state == RTCStatsIceCandidatePairState::kInProgress ||
- *pair_stats->state == RTCStatsIceCandidatePairState::kSucceeded) {
- return true;
- }
- }
- }
- return false;
- }
-
- rtc::FakeNetworkManager* network() { return network_; }
-
- void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
-
- private:
- rtc::FakeNetworkManager* network_;
-};
-
-class PeerConnectionBundleTest : public ::testing::Test {
- protected:
- typedef std::unique_ptr<PeerConnectionWrapperForBundleTest> WrapperPtr;
-
- PeerConnectionBundleTest()
- : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
-#ifdef WEBRTC_ANDROID
- InitializeAndroidObjects();
-#endif
- pc_factory_ = CreatePeerConnectionFactory(
- rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
- FakeAudioCaptureModule::Create(), nullptr, nullptr);
- }
-
- WrapperPtr CreatePeerConnection() {
- return CreatePeerConnection(RTCConfiguration());
- }
-
- WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
- auto* fake_network = NewFakeNetwork();
- auto port_allocator =
- rtc::MakeUnique<cricket::BasicPortAllocator>(fake_network);
- port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
- cricket::PORTALLOCATOR_DISABLE_RELAY);
- port_allocator->set_step_delay(cricket::kMinimumStepDelay);
- auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
- auto pc = pc_factory_->CreatePeerConnection(
- config, std::move(port_allocator), nullptr, observer.get());
- if (!pc) {
- return nullptr;
- }
-
- auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForBundleTest>(
- pc_factory_, pc, std::move(observer));
- wrapper->set_network(fake_network);
- return wrapper;
- }
-
- // Accepts the same arguments as CreatePeerConnection and adds default audio
- // and video tracks.
- template <typename... Args>
- WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
- auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
- if (!wrapper) {
- return nullptr;
- }
- wrapper->AddAudioTrack("a");
- wrapper->AddVideoTrack("v");
- return wrapper;
- }
-
- cricket::Candidate CreateLocalUdpCandidate(
- const rtc::SocketAddress& address) {
- cricket::Candidate candidate;
- candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
- candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
- candidate.set_address(address);
- candidate.set_type(cricket::LOCAL_PORT_TYPE);
- return candidate;
- }
-
- rtc::FakeNetworkManager* NewFakeNetwork() {
- // The PeerConnection's port allocator is tied to the PeerConnection's
- // lifetime and expects the underlying NetworkManager to outlive it. If
- // PeerConnectionWrapper owned the NetworkManager, it would be destroyed
- // before the PeerConnection (since subclass members are destroyed before
- // base class members). Therefore, the test fixture will own all the fake
- // networks even though tests should access the fake network through the
- // PeerConnectionWrapper.
- auto* fake_network = new rtc::FakeNetworkManager();
- fake_networks_.emplace_back(fake_network);
- return fake_network;
- }
-
- std::unique_ptr<rtc::VirtualSocketServer> vss_;
- rtc::AutoSocketServerThread main_;
- rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
- std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
-};
-
-SdpContentMutator RemoveRtcpMux() {
- return [](cricket::ContentInfo* content, cricket::TransportInfo* transport) {
- auto* media_desc =
- static_cast<cricket::MediaContentDescription*>(content->description);
- media_desc->set_rtcp_mux(false);
- };
-}
-
-std::vector<int> GetCandidateComponents(
- const std::vector<IceCandidateInterface*> candidates) {
- std::vector<int> components;
- for (auto* candidate : candidates) {
- components.push_back(candidate->candidate().component());
- }
- return components;
-}
-
-// Test that there are 2 local UDP candidates (1 RTP and 1 RTCP candidate) for
-// each media section when disabling bundling and disabling RTCP multiplexing.
-TEST_F(PeerConnectionBundleTest,
- TwoCandidatesForEachTransportWhenNoBundleNoRtcpMux) {
- const SocketAddress kCallerAddress("1.1.1.1", 0);
- const SocketAddress kCalleeAddress("2.2.2.2", 0);
-
- RTCConfiguration config;
- config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
- auto caller = CreatePeerConnectionWithAudioVideo(config);
- caller->network()->AddInterface(kCallerAddress);
- auto callee = CreatePeerConnectionWithAudioVideo(config);
- callee->network()->AddInterface(kCalleeAddress);
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
- RTCOfferAnswerOptions options_no_bundle;
- options_no_bundle.use_rtp_mux = false;
- auto answer = callee->CreateAnswer(options_no_bundle);
- SdpContentsForEach(RemoveRtcpMux(), answer->description());
- ASSERT_TRUE(
- callee->SetLocalDescription(CloneSessionDescription(answer.get())));
- ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
-
- // Check that caller has separate RTP and RTCP candidates for each media.
- EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
- EXPECT_THAT(
- GetCandidateComponents(caller->observer()->GetCandidatesByMline(0)),
- UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
- cricket::ICE_CANDIDATE_COMPONENT_RTCP));
- EXPECT_THAT(
- GetCandidateComponents(caller->observer()->GetCandidatesByMline(1)),
- UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
- cricket::ICE_CANDIDATE_COMPONENT_RTCP));
-
- // Check that callee has separate RTP and RTCP candidates for each media.
- EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kDefaultTimeout);
- EXPECT_THAT(
- GetCandidateComponents(callee->observer()->GetCandidatesByMline(0)),
- UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
- cricket::ICE_CANDIDATE_COMPONENT_RTCP));
- EXPECT_THAT(
- GetCandidateComponents(callee->observer()->GetCandidatesByMline(1)),
- UnorderedElementsAre(cricket::ICE_CANDIDATE_COMPONENT_RTP,
- cricket::ICE_CANDIDATE_COMPONENT_RTCP));
-}
-
-// Test that there is 1 local UDP candidate for both RTP and RTCP for each media
-// section when disabling bundle but enabling RTCP multiplexing.
-TEST_F(PeerConnectionBundleTest,
- OneCandidateForEachTransportWhenNoBundleButRtcpMux) {
- const SocketAddress kCallerAddress("1.1.1.1", 0);
-
- auto caller = CreatePeerConnectionWithAudioVideo();
- caller->network()->AddInterface(kCallerAddress);
- auto callee = CreatePeerConnectionWithAudioVideo();
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
- RTCOfferAnswerOptions options_no_bundle;
- options_no_bundle.use_rtp_mux = false;
- ASSERT_TRUE(
- caller->SetRemoteDescription(callee->CreateAnswer(options_no_bundle)));
-
- EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
-
- EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
- EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(1).size());
-}
-
-// Test that there is 1 local UDP candidate in only the first media section when
-// bundling and enabling RTCP multiplexing.
-TEST_F(PeerConnectionBundleTest,
- OneCandidateOnlyOnFirstTransportWhenBundleAndRtcpMux) {
- const SocketAddress kCallerAddress("1.1.1.1", 0);
-
- RTCConfiguration config;
- config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
- auto caller = CreatePeerConnectionWithAudioVideo(config);
- caller->network()->AddInterface(kCallerAddress);
- auto callee = CreatePeerConnectionWithAudioVideo(config);
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
- ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
-
- EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kDefaultTimeout);
-
- EXPECT_EQ(1u, caller->observer()->GetCandidatesByMline(0).size());
- EXPECT_EQ(0u, caller->observer()->GetCandidatesByMline(1).size());
-}
-
-// The following parameterized test verifies that an offer/answer with varying
-// bundle policies and either bundle in the answer or not will produce the
-// expected RTP transports for audio and video. In particular, for bundling we
-// care about whether they are separate transports or the same.
-
-enum class BundleIncluded { kBundleInAnswer, kBundleNotInAnswer };
-std::ostream& operator<<(std::ostream& out, BundleIncluded value) {
- switch (value) {
- case BundleIncluded::kBundleInAnswer:
- return out << "bundle in answer";
- case BundleIncluded::kBundleNotInAnswer:
- return out << "bundle not in answer";
- }
- return out << "unknown";
-}
-
-class PeerConnectionBundleMatrixTest
- : public PeerConnectionBundleTest,
- public ::testing::WithParamInterface<
- std::tuple<BundlePolicy, BundleIncluded, bool, bool>> {
- protected:
- PeerConnectionBundleMatrixTest() {
- bundle_policy_ = std::get<0>(GetParam());
- bundle_included_ = std::get<1>(GetParam());
- expected_same_before_ = std::get<2>(GetParam());
- expected_same_after_ = std::get<3>(GetParam());
- }
-
- PeerConnectionInterface::BundlePolicy bundle_policy_;
- BundleIncluded bundle_included_;
- bool expected_same_before_;
- bool expected_same_after_;
-};
-
-TEST_P(PeerConnectionBundleMatrixTest,
- VerifyTransportsBeforeAndAfterSettingRemoteAnswer) {
- RTCConfiguration config;
- config.bundle_policy = bundle_policy_;
- auto caller = CreatePeerConnectionWithAudioVideo(config);
- auto callee = CreatePeerConnectionWithAudioVideo();
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
- bool equal_before = (caller->voice_rtp_transport_channel() ==
- caller->video_rtp_transport_channel());
- EXPECT_EQ(expected_same_before_, equal_before);
-
- RTCOfferAnswerOptions options;
- options.use_rtp_mux = (bundle_included_ == BundleIncluded::kBundleInAnswer);
- ASSERT_TRUE(
- caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
- bool equal_after = (caller->voice_rtp_transport_channel() ==
- caller->video_rtp_transport_channel());
- EXPECT_EQ(expected_same_after_, equal_after);
-}
-
-// The max-bundle policy means we should anticipate bundling being negotiated,
-// and multiplex audio/video from the start.
-// For all other policies, bundling should only be enabled if negotiated by the
-// answer.
-INSTANTIATE_TEST_CASE_P(
- PeerConnectionBundleTest,
- PeerConnectionBundleMatrixTest,
- Values(std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
- BundleIncluded::kBundleInAnswer,
- false,
- true),
- std::make_tuple(BundlePolicy::kBundlePolicyBalanced,
- BundleIncluded::kBundleNotInAnswer,
- false,
- false),
- std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
- BundleIncluded::kBundleInAnswer,
- true,
- true),
- std::make_tuple(BundlePolicy::kBundlePolicyMaxBundle,
- BundleIncluded::kBundleNotInAnswer,
- true,
- true),
- std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
- BundleIncluded::kBundleInAnswer,
- false,
- true),
- std::make_tuple(BundlePolicy::kBundlePolicyMaxCompat,
- BundleIncluded::kBundleNotInAnswer,
- false,
- false)));
-
-// Test that the audio/video transports on the callee side are the same before
-// and after setting a local answer when max BUNDLE is enabled and an offer with
-// BUNDLE is received.
-TEST_F(PeerConnectionBundleTest,
- TransportsSameForMaxBundleWithBundleInRemoteOffer) {
- auto caller = CreatePeerConnectionWithAudioVideo();
- RTCConfiguration config;
- config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
- auto callee = CreatePeerConnectionWithAudioVideo(config);
-
- RTCOfferAnswerOptions options_with_bundle;
- options_with_bundle.use_rtp_mux = true;
- ASSERT_TRUE(callee->SetRemoteDescription(
- caller->CreateOfferAndSetAsLocal(options_with_bundle)));
-
- EXPECT_EQ(callee->voice_rtp_transport_channel(),
- callee->video_rtp_transport_channel());
-
- ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
-
- EXPECT_EQ(callee->voice_rtp_transport_channel(),
- callee->video_rtp_transport_channel());
-}
-
-TEST_F(PeerConnectionBundleTest,
- FailToSetRemoteOfferWithNoBundleWhenBundlePolicyMaxBundle) {
- auto caller = CreatePeerConnectionWithAudioVideo();
- RTCConfiguration config;
- config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
- auto callee = CreatePeerConnectionWithAudioVideo(config);
-
- RTCOfferAnswerOptions options_no_bundle;
- options_no_bundle.use_rtp_mux = false;
- EXPECT_FALSE(callee->SetRemoteDescription(
- caller->CreateOfferAndSetAsLocal(options_no_bundle)));
-}
-
-// Test that if the media section which has the bundled transport is rejected,
-// then the peers still connect and the bundled transport switches to the other
-// media section.
-// Note: This is currently failing because of the following bug:
-// https://bugs.chromium.org/p/webrtc/issues/detail?id=6280
-TEST_F(PeerConnectionBundleTest,
- DISABLED_SuccessfullyNegotiateMaxBundleIfBundleTransportMediaRejected) {
- RTCConfiguration config;
- config.bundle_policy = BundlePolicy::kBundlePolicyMaxBundle;
- auto caller = CreatePeerConnectionWithAudioVideo(config);
- auto callee = CreatePeerConnection();
- callee->AddVideoTrack("v");
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
- RTCOfferAnswerOptions options;
- options.offer_to_receive_audio = 0;
- ASSERT_TRUE(
- caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(options)));
-
- EXPECT_FALSE(caller->voice_rtp_transport_channel());
- EXPECT_TRUE(caller->video_rtp_transport_channel());
-}
-
-// When requiring RTCP multiplexing, the PeerConnection never makes RTCP
-// transport channels.
-TEST_F(PeerConnectionBundleTest, NeverCreateRtcpTransportWithRtcpMuxRequired) {
- RTCConfiguration config;
- config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyRequire;
- auto caller = CreatePeerConnectionWithAudioVideo(config);
- auto callee = CreatePeerConnectionWithAudioVideo();
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
- EXPECT_FALSE(caller->voice_rtcp_transport_channel());
- EXPECT_FALSE(caller->video_rtcp_transport_channel());
-
- ASSERT_TRUE(
- caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
- EXPECT_FALSE(caller->voice_rtcp_transport_channel());
- EXPECT_FALSE(caller->video_rtcp_transport_channel());
-}
-
-// When negotiating RTCP multiplexing, the PeerConnection makes RTCP transport
-// channels when the offer is sent, but will destroy them once the remote answer
-// is set.
-TEST_F(PeerConnectionBundleTest,
- CreateRtcpTransportOnlyBeforeAnswerWithRtcpMuxNegotiate) {
- RTCConfiguration config;
- config.rtcp_mux_policy = RtcpMuxPolicy::kRtcpMuxPolicyNegotiate;
- auto caller = CreatePeerConnectionWithAudioVideo(config);
- auto callee = CreatePeerConnectionWithAudioVideo();
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
- EXPECT_TRUE(caller->voice_rtcp_transport_channel());
- EXPECT_TRUE(caller->video_rtcp_transport_channel());
-
- ASSERT_TRUE(
- caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
- EXPECT_FALSE(caller->voice_rtcp_transport_channel());
- EXPECT_FALSE(caller->video_rtcp_transport_channel());
-}
-
-TEST_F(PeerConnectionBundleTest, FailToSetDescriptionWithBundleAndNoRtcpMux) {
- auto caller = CreatePeerConnectionWithAudioVideo();
- auto callee = CreatePeerConnectionWithAudioVideo();
-
- RTCOfferAnswerOptions options;
- options.use_rtp_mux = true;
-
- auto offer = caller->CreateOffer(options);
- SdpContentsForEach(RemoveRtcpMux(), offer->description());
-
- std::string error;
- EXPECT_FALSE(caller->SetLocalDescription(CloneSessionDescription(offer.get()),
- &error));
- EXPECT_EQ(
- "Failed to set local offer SDP: rtcp-mux must be enabled when BUNDLE is "
- "enabled.",
- error);
-
- EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
- EXPECT_EQ(
- "Failed to set remote offer SDP: rtcp-mux must be enabled when BUNDLE is "
- "enabled.",
- error);
-}
-
-// Test that candidates sent to the "video" transport do not get pushed down to
-// the "audio" transport channel when bundling.
-TEST_F(PeerConnectionBundleTest,
- IgnoreCandidatesForUnusedTransportWhenBundling) {
- const SocketAddress kAudioAddress1("1.1.1.1", 1111);
- const SocketAddress kAudioAddress2("2.2.2.2", 2222);
- const SocketAddress kVideoAddress("3.3.3.3", 3333);
- const SocketAddress kCallerAddress("4.4.4.4", 0);
- const SocketAddress kCalleeAddress("5.5.5.5", 0);
-
- auto caller = CreatePeerConnectionWithAudioVideo();
- auto callee = CreatePeerConnectionWithAudioVideo();
-
- caller->network()->AddInterface(kCallerAddress);
- callee->network()->AddInterface(kCalleeAddress);
-
- RTCOfferAnswerOptions options;
- options.use_rtp_mux = true;
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
- ASSERT_TRUE(
- caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
- // The way the *_WAIT checks work is they only wait if the condition fails,
- // which does not help in the case where state is not changing. This is
- // problematic in this test since we want to verify that adding a video
- // candidate does _not_ change state. So we interleave candidates and assume
- // that messages are executed in the order they were posted.
-
- cricket::Candidate audio_candidate1 = CreateLocalUdpCandidate(kAudioAddress1);
- ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate1,
- cricket::MEDIA_TYPE_AUDIO));
-
- cricket::Candidate video_candidate = CreateLocalUdpCandidate(kVideoAddress);
- ASSERT_TRUE(caller->AddIceCandidateToMedia(&video_candidate,
- cricket::MEDIA_TYPE_VIDEO));
-
- cricket::Candidate audio_candidate2 = CreateLocalUdpCandidate(kAudioAddress2);
- ASSERT_TRUE(caller->AddIceCandidateToMedia(&audio_candidate2,
- cricket::MEDIA_TYPE_AUDIO));
-
- EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress1),
- kDefaultTimeout);
- EXPECT_TRUE_WAIT(caller->HasConnectionWithRemoteAddress(kAudioAddress2),
- kDefaultTimeout);
- EXPECT_FALSE(caller->HasConnectionWithRemoteAddress(kVideoAddress));
-}
-
-// Test that the transport used by both audio and video is the transport
-// associated with the first MID in the answer BUNDLE group, even if it's in a
-// different order from the offer.
-TEST_F(PeerConnectionBundleTest, BundleOnFirstMidInAnswer) {
- auto caller = CreatePeerConnectionWithAudioVideo();
- auto callee = CreatePeerConnectionWithAudioVideo();
-
- ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
- auto* old_video_transport = caller->video_rtp_transport_channel();
-
- auto answer = callee->CreateAnswer();
- auto* old_bundle_group =
- answer->description()->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
- ASSERT_THAT(old_bundle_group->content_names(),
- ElementsAre(cricket::CN_AUDIO, cricket::CN_VIDEO));
- answer->description()->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
-
- cricket::ContentGroup new_bundle_group(cricket::GROUP_TYPE_BUNDLE);
- new_bundle_group.AddContentName(cricket::CN_VIDEO);
- new_bundle_group.AddContentName(cricket::CN_AUDIO);
- answer->description()->AddGroup(new_bundle_group);
-
- ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
-
- EXPECT_EQ(old_video_transport, caller->video_rtp_transport_channel());
- EXPECT_EQ(caller->voice_rtp_transport_channel(),
- caller->video_rtp_transport_channel());
-}
-
-} // namespace webrtc
diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc
index d38433c..9453567 100644
--- a/pc/peerconnection_integrationtest.cc
+++ b/pc/peerconnection_integrationtest.cc
@@ -291,9 +291,6 @@
ice_connection_state_history() const {
return ice_connection_state_history_;
}
- void clear_ice_connection_state_history() {
- ice_connection_state_history_.clear();
- }
// Every ICE gathering state in order that has been seen by the observer.
std::vector<PeerConnectionInterface::IceGatheringState>
@@ -3085,31 +3082,6 @@
kMaxWaitForFramesMs);
}
-// With a max bundle policy and RTCP muxing, adding a new media description to
-// the connection should not affect ICE at all because the new media will use
-// the existing connection.
-TEST_F(PeerConnectionIntegrationTest,
- AddMediaToConnectedBundleDoesNotRestartIce) {
- PeerConnectionInterface::RTCConfiguration config;
- config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
- config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
- ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(
- config, PeerConnectionInterface::RTCConfiguration()));
- ConnectFakeSignaling();
-
- caller()->AddAudioOnlyMediaStream();
- caller()->CreateAndSetAndSignalOffer();
- ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-
- caller()->clear_ice_connection_state_history();
-
- caller()->AddVideoOnlyMediaStream();
- caller()->CreateAndSetAndSignalOffer();
- ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-
- EXPECT_EQ(0u, caller()->ice_connection_state_history().size());
-}
-
// This test sets up a call between two parties with audio and video. It then
// renegotiates setting the video m-line to "port 0", then later renegotiates
// again, enabling video.
diff --git a/pc/peerconnectioninterface_unittest.cc b/pc/peerconnectioninterface_unittest.cc
index d8fa486..a8b4f72 100644
--- a/pc/peerconnectioninterface_unittest.cc
+++ b/pc/peerconnectioninterface_unittest.cc
@@ -944,7 +944,7 @@
EXPECT_TRUE(DoSetLocalDescription(std::move(new_offer)));
EXPECT_EQ(PeerConnectionInterface::kHaveLocalOffer, observer_.state_);
// Wait for the ice_complete message, so that SDP will have candidates.
- EXPECT_TRUE_WAIT(observer_.ice_gathering_complete_, kTimeout);
+ EXPECT_TRUE_WAIT(observer_.ice_complete_, kTimeout);
}
void CreateAnswerAsRemoteDescription(const std::string& sdp) {
@@ -1598,7 +1598,7 @@
EXPECT_TRUE(DoSetLocalDescription(std::move(answer)));
EXPECT_TRUE_WAIT(observer_.last_candidate() != nullptr, kTimeout);
- EXPECT_TRUE_WAIT(observer_.ice_gathering_complete_, kTimeout);
+ EXPECT_TRUE_WAIT(observer_.ice_complete_, kTimeout);
EXPECT_TRUE(pc_->AddIceCandidate(observer_.last_candidate()));
}
diff --git a/pc/peerconnectionwrapper.cc b/pc/peerconnectionwrapper.cc
index 070deb9..9be9309 100644
--- a/pc/peerconnectionwrapper.cc
+++ b/pc/peerconnectionwrapper.cc
@@ -23,7 +23,7 @@
namespace webrtc {
namespace {
-const uint32_t kDefaultTimeout = 10000U;
+const uint32_t kWaitTimeout = 10000U;
}
PeerConnectionWrapper::PeerConnectionWrapper(
@@ -122,7 +122,7 @@
rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer(
new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>());
fn(observer);
- EXPECT_EQ_WAIT(true, observer->called(), kDefaultTimeout);
+ EXPECT_EQ_WAIT(true, observer->called(), kWaitTimeout);
if (error_out && !observer->result()) {
*error_out = observer->error();
}
@@ -155,7 +155,7 @@
rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
fn(observer);
- EXPECT_EQ_WAIT(true, observer->called(), kDefaultTimeout);
+ EXPECT_EQ_WAIT(true, observer->called(), kWaitTimeout);
if (error_out && !observer->result()) {
*error_out = observer->error();
}
@@ -186,20 +186,7 @@
}
bool PeerConnectionWrapper::IsIceGatheringDone() {
- return observer()->ice_gathering_complete_;
-}
-
-bool PeerConnectionWrapper::IsIceConnected() {
- return observer()->ice_connected_;
-}
-
-rtc::scoped_refptr<const webrtc::RTCStatsReport>
-PeerConnectionWrapper::GetStats() {
- rtc::scoped_refptr<webrtc::MockRTCStatsCollectorCallback> callback(
- new rtc::RefCountedObject<webrtc::MockRTCStatsCollectorCallback>());
- pc()->GetStats(callback);
- EXPECT_TRUE_WAIT(callback->called(), kDefaultTimeout);
- return callback->report();
+ return observer()->ice_complete_;
}
} // namespace webrtc
diff --git a/pc/peerconnectionwrapper.h b/pc/peerconnectionwrapper.h
index 88d2f07..f74fcdb 100644
--- a/pc/peerconnectionwrapper.h
+++ b/pc/peerconnectionwrapper.h
@@ -107,13 +107,6 @@
// Returns true if ICE has finished gathering candidates.
bool IsIceGatheringDone();
- // Returns true if ICE has established a connection.
- bool IsIceConnected();
-
- // Calls GetStats() on the underlying PeerConnection and returns the resulting
- // report. If GetStats() fails, this method returns null and fails the test.
- rtc::scoped_refptr<const RTCStatsReport> GetStats();
-
private:
std::unique_ptr<SessionDescriptionInterface> CreateSdp(
std::function<void(CreateSessionDescriptionObserver*)> fn,
diff --git a/pc/test/mockpeerconnectionobservers.h b/pc/test/mockpeerconnectionobservers.h
index 845dbc7..82098ca 100644
--- a/pc/test/mockpeerconnectionobservers.h
+++ b/pc/test/mockpeerconnectionobservers.h
@@ -73,15 +73,12 @@
void OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) override {
RTC_DCHECK(pc_->ice_connection_state() == new_state);
- ice_connected_ =
- (new_state == PeerConnectionInterface::kIceConnectionConnected);
callback_triggered_ = true;
}
void OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) override {
RTC_DCHECK(pc_->ice_gathering_state() == new_state);
- ice_gathering_complete_ =
- new_state == PeerConnectionInterface::kIceGatheringComplete;
+ ice_complete_ = new_state == PeerConnectionInterface::kIceGatheringComplete;
callback_triggered_ = true;
}
void OnIceCandidate(const IceCandidateInterface* candidate) override {
@@ -162,8 +159,7 @@
rtc::scoped_refptr<DataChannelInterface> last_datachannel_;
rtc::scoped_refptr<StreamCollection> remote_streams_;
bool renegotiation_needed_ = false;
- bool ice_gathering_complete_ = false;
- bool ice_connected_ = false;
+ bool ice_complete_ = false;
bool callback_triggered_ = false;
int num_added_tracks_ = 0;
std::string last_added_track_label_;
diff --git a/pc/webrtcsession.cc b/pc/webrtcsession.cc
index 4fd1e32..2e0ae50 100644
--- a/pc/webrtcsession.cc
+++ b/pc/webrtcsession.cc
@@ -56,9 +56,8 @@
namespace webrtc {
// Error messages
-const char kBundleWithoutRtcpMux[] =
- "rtcp-mux must be enabled when BUNDLE "
- "is enabled.";
+const char kBundleWithoutRtcpMux[] = "RTCP-MUX must be enabled when BUNDLE "
+ "is enabled.";
const char kCreateChannelFailed[] = "Failed to create channels.";
const char kInvalidCandidates[] = "Description contains invalid candidates.";
const char kInvalidSdp[] = "Invalid session description.";
diff --git a/pc/webrtcsession_unittest.cc b/pc/webrtcsession_unittest.cc
index a6fda21..0c54abc 100644
--- a/pc/webrtcsession_unittest.cc
+++ b/pc/webrtcsession_unittest.cc
@@ -83,9 +83,11 @@
// Media index of candidates belonging to the first media content.
static const int kMediaContentIndex0 = 0;
+static const char kMediaContentName0[] = "audio";
// Media index of candidates belonging to the second media content.
static const int kMediaContentIndex1 = 1;
+static const char kMediaContentName1[] = "video";
static const int kDefaultTimeout = 10000; // 10 seconds.
static const int kIceCandidatesTimeout = 10000;
@@ -398,6 +400,12 @@
Init();
}
+ void InitWithRtcpMuxPolicy(
+ PeerConnectionInterface::RtcpMuxPolicy rtcp_mux_policy) {
+ PeerConnectionInterface::RTCConfiguration configuration;
+ Init(nullptr, rtcp_mux_policy, rtc::CryptoOptions());
+ }
+
// Successfully init with DTLS; with a certificate generated and supplied or
// with a store that generates it for us.
void InitWithDtls(RTCCertificateGenerationMethod cert_gen_method) {
@@ -893,6 +901,51 @@
return CreateRemoteAnswer(offer, options, cricket::SEC_REQUIRED);
}
+ void TestSessionCandidatesWithBundleRtcpMux(bool bundle, bool rtcp_mux) {
+ AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
+ Init();
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = bundle;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ // SetLocalDescription and SetRemoteDescriptions takes ownership of offer
+ // and answer.
+ SetLocalDescriptionWithoutError(offer);
+
+ std::unique_ptr<SessionDescriptionInterface> answer(
+ CreateRemoteAnswer(session_->local_description()));
+ std::string sdp;
+ EXPECT_TRUE(answer->ToString(&sdp));
+
+ size_t expected_candidate_num = 2;
+ if (!rtcp_mux) {
+ // If rtcp_mux is enabled we should expect 4 candidates - host and srflex
+ // for rtp and rtcp.
+ expected_candidate_num = 4;
+ // Disable rtcp-mux from the answer
+ const std::string kRtcpMux = "a=rtcp-mux";
+ const std::string kXRtcpMux = "a=xrtcp-mux";
+ rtc::replace_substrs(kRtcpMux.c_str(), kRtcpMux.length(),
+ kXRtcpMux.c_str(), kXRtcpMux.length(),
+ &sdp);
+ }
+
+ SessionDescriptionInterface* new_answer = CreateSessionDescription(
+ JsepSessionDescription::kAnswer, sdp, NULL);
+
+ // SetRemoteDescription to enable rtcp mux.
+ SetRemoteDescriptionWithoutError(new_answer);
+ EXPECT_TRUE_WAIT(observer_.oncandidatesready_, kIceCandidatesTimeout);
+ EXPECT_EQ(expected_candidate_num, observer_.mline_0_candidates_.size());
+ if (bundle) {
+ EXPECT_EQ(0, observer_.mline_1_candidates_.size());
+ } else {
+ EXPECT_EQ(expected_candidate_num, observer_.mline_1_candidates_.size());
+ }
+ }
+
// The method sets up a call from the session to itself, in a loopback
// arrangement. It also uses a firewall rule to create a temporary
// disconnection, and then a permanent disconnection.
@@ -1014,6 +1067,20 @@
rtc::CryptoOptions crypto_options_;
};
+TEST_F(WebRtcSessionTest, TestSessionCandidates) {
+ TestSessionCandidatesWithBundleRtcpMux(false, false);
+}
+
+// Below test cases (TestSessionCandidatesWith*) verify the candidates gathered
+// with rtcp-mux and/or bundle.
+TEST_F(WebRtcSessionTest, TestSessionCandidatesWithRtcpMux) {
+ TestSessionCandidatesWithBundleRtcpMux(false, true);
+}
+
+TEST_F(WebRtcSessionTest, TestSessionCandidatesWithBundleRtcpMux) {
+ TestSessionCandidatesWithBundleRtcpMux(true, true);
+}
+
// Test that we can create and set an answer correctly when different
// SSL roles have been negotiated for different transports.
// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=4525
@@ -1077,6 +1144,466 @@
SetLocalDescriptionWithoutError(answer);
}
+// Test that candidates sent to the "video" transport do not get pushed down to
+// the "audio" transport channel when bundling.
+TEST_F(WebRtcSessionTest, TestIgnoreCandidatesForUnusedTransportWhenBundling) {
+ AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
+
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
+ SendAudioVideoStream1();
+
+ cricket::MediaSessionOptions offer_options;
+ GetOptionsForRemoteOffer(&offer_options);
+ offer_options.bundle_enabled = true;
+
+ SessionDescriptionInterface* offer = CreateRemoteOffer(offer_options);
+ SetRemoteDescriptionWithoutError(offer);
+
+ cricket::MediaSessionOptions answer_options;
+ answer_options.bundle_enabled = true;
+ SessionDescriptionInterface* answer = CreateAnswer(answer_options);
+ SetLocalDescriptionWithoutError(answer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ cricket::BaseChannel* voice_channel = session_->voice_channel();
+ ASSERT_TRUE(voice_channel != NULL);
+
+ // Checks if one of the transport channels contains a connection using a given
+ // port.
+ auto connection_with_remote_port = [this](int port) {
+ std::unique_ptr<webrtc::SessionStats> stats = session_->GetStats_s();
+ for (auto& kv : stats->transport_stats) {
+ for (auto& chan_stat : kv.second.channel_stats) {
+ for (auto& conn_info : chan_stat.connection_infos) {
+ if (conn_info.remote_candidate.address().port() == port) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ };
+
+ EXPECT_FALSE(connection_with_remote_port(5000));
+ EXPECT_FALSE(connection_with_remote_port(5001));
+ EXPECT_FALSE(connection_with_remote_port(6000));
+
+ // The way the *_WAIT checks work is they only wait if the condition fails,
+ // which does not help in the case where state is not changing. This is
+ // problematic in this test since we want to verify that adding a video
+ // candidate does _not_ change state. So we interleave candidates and assume
+ // that messages are executed in the order they were posted.
+
+ // First audio candidate.
+ cricket::Candidate candidate0;
+ candidate0.set_address(rtc::SocketAddress("1.1.1.1", 5000));
+ candidate0.set_component(1);
+ candidate0.set_protocol("udp");
+ candidate0.set_type("local");
+ JsepIceCandidate ice_candidate0(kMediaContentName0, kMediaContentIndex0,
+ candidate0);
+ EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate0));
+
+ // Video candidate.
+ cricket::Candidate candidate1;
+ candidate1.set_address(rtc::SocketAddress("1.1.1.1", 6000));
+ candidate1.set_component(1);
+ candidate1.set_protocol("udp");
+ candidate1.set_type("local");
+ JsepIceCandidate ice_candidate1(kMediaContentName1, kMediaContentIndex1,
+ candidate1);
+ EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate1));
+
+ // Second audio candidate.
+ cricket::Candidate candidate2;
+ candidate2.set_address(rtc::SocketAddress("1.1.1.1", 5001));
+ candidate2.set_component(1);
+ candidate2.set_protocol("udp");
+ candidate2.set_type("local");
+ JsepIceCandidate ice_candidate2(kMediaContentName0, kMediaContentIndex0,
+ candidate2);
+ EXPECT_TRUE(session_->ProcessIceMessage(&ice_candidate2));
+
+ EXPECT_TRUE_WAIT(connection_with_remote_port(5000), 1000);
+ EXPECT_TRUE_WAIT(connection_with_remote_port(5001), 1000);
+
+ // No need here for a _WAIT check since we are checking that state hasn't
+ // changed: if this is false we would be doing waits for nothing and if this
+ // is true then there will be no messages processed anyways.
+ EXPECT_FALSE(connection_with_remote_port(6000));
+}
+
+// kBundlePolicyBalanced BUNDLE policy and answer contains BUNDLE.
+TEST_F(WebRtcSessionTest, TestBalancedBundleInAnswer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_NE(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendAudioVideoStream2();
+ SessionDescriptionInterface* answer =
+ CreateRemoteAnswer(session_->local_description());
+ SetRemoteDescriptionWithoutError(answer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// kBundlePolicyBalanced BUNDLE policy but no BUNDLE in the answer.
+TEST_F(WebRtcSessionTest, TestBalancedNoBundleInAnswer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyBalanced);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_NE(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendAudioVideoStream2();
+
+ // Remove BUNDLE from the answer.
+ std::unique_ptr<SessionDescriptionInterface> answer(
+ CreateRemoteAnswer(session_->local_description()));
+ cricket::SessionDescription* answer_copy = answer->description()->Copy();
+ answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
+ JsepSessionDescription* modified_answer =
+ new JsepSessionDescription(JsepSessionDescription::kAnswer);
+ modified_answer->Initialize(answer_copy, "1", "1");
+ SetRemoteDescriptionWithoutError(modified_answer); //
+
+ EXPECT_NE(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// kBundlePolicyMaxBundle policy with BUNDLE in the answer.
+TEST_F(WebRtcSessionTest, TestMaxBundleBundleInAnswer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendAudioVideoStream2();
+ SessionDescriptionInterface* answer =
+ CreateRemoteAnswer(session_->local_description());
+ SetRemoteDescriptionWithoutError(answer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// kBundlePolicyMaxBundle policy with BUNDLE in the answer, but no
+// audio content in the answer.
+TEST_F(WebRtcSessionTest, TestMaxBundleRejectAudio) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendVideoOnlyStream2();
+ local_send_audio_ = false;
+ remote_recv_audio_ = false;
+ cricket::MediaSessionOptions recv_options;
+ GetOptionsForRemoteAnswer(&recv_options);
+ SessionDescriptionInterface* answer =
+ CreateRemoteAnswer(session_->local_description(), recv_options);
+ SetRemoteDescriptionWithoutError(answer);
+
+ EXPECT_TRUE(nullptr == session_->voice_channel());
+ EXPECT_TRUE(nullptr != session_->video_rtp_transport_channel());
+
+ session_->Close();
+ EXPECT_TRUE(nullptr == session_->voice_rtp_transport_channel());
+ EXPECT_TRUE(nullptr == session_->voice_rtcp_transport_channel());
+ EXPECT_TRUE(nullptr == session_->video_rtp_transport_channel());
+ EXPECT_TRUE(nullptr == session_->video_rtcp_transport_channel());
+}
+
+// kBundlePolicyMaxBundle policy but no BUNDLE in the answer.
+TEST_F(WebRtcSessionTest, TestMaxBundleNoBundleInAnswer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendAudioVideoStream2();
+
+ // Remove BUNDLE from the answer.
+ std::unique_ptr<SessionDescriptionInterface> answer(
+ CreateRemoteAnswer(session_->local_description()));
+ cricket::SessionDescription* answer_copy = answer->description()->Copy();
+ answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
+ JsepSessionDescription* modified_answer =
+ new JsepSessionDescription(JsepSessionDescription::kAnswer);
+ modified_answer->Initialize(answer_copy, "1", "1");
+ SetRemoteDescriptionWithoutError(modified_answer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// kBundlePolicyMaxBundle policy with BUNDLE in the remote offer.
+TEST_F(WebRtcSessionTest, TestMaxBundleBundleInRemoteOffer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
+ SendAudioVideoStream1();
+
+ SessionDescriptionInterface* offer = CreateRemoteOffer();
+ SetRemoteDescriptionWithoutError(offer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendAudioVideoStream2();
+ SessionDescriptionInterface* answer = CreateAnswer();
+ SetLocalDescriptionWithoutError(answer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// kBundlePolicyMaxBundle policy but no BUNDLE in the remote offer.
+TEST_F(WebRtcSessionTest, TestMaxBundleNoBundleInRemoteOffer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
+ SendAudioVideoStream1();
+
+ // Remove BUNDLE from the offer.
+ std::unique_ptr<SessionDescriptionInterface> offer(CreateRemoteOffer());
+ cricket::SessionDescription* offer_copy = offer->description()->Copy();
+ offer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
+ JsepSessionDescription* modified_offer =
+ new JsepSessionDescription(JsepSessionDescription::kOffer);
+ modified_offer->Initialize(offer_copy, "1", "1");
+
+ // Expect an error when applying the remote description
+ SetRemoteDescriptionExpectError(JsepSessionDescription::kOffer,
+ kCreateChannelFailed, modified_offer);
+}
+
+// kBundlePolicyMaxCompat bundle policy and answer contains BUNDLE.
+TEST_F(WebRtcSessionTest, TestMaxCompatBundleInAnswer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxCompat);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions rtc_options;
+ rtc_options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(rtc_options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_NE(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendAudioVideoStream2();
+ SessionDescriptionInterface* answer =
+ CreateRemoteAnswer(session_->local_description());
+ SetRemoteDescriptionWithoutError(answer);
+
+ // This should lead to an audio-only call but isn't implemented
+ // correctly yet.
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// kBundlePolicyMaxCompat BUNDLE policy but no BUNDLE in the answer.
+TEST_F(WebRtcSessionTest, TestMaxCompatNoBundleInAnswer) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxCompat);
+ SendAudioVideoStream1();
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_NE(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+
+ SendAudioVideoStream2();
+
+ // Remove BUNDLE from the answer.
+ std::unique_ptr<SessionDescriptionInterface> answer(
+ CreateRemoteAnswer(session_->local_description()));
+ cricket::SessionDescription* answer_copy = answer->description()->Copy();
+ answer_copy->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
+ JsepSessionDescription* modified_answer =
+ new JsepSessionDescription(JsepSessionDescription::kAnswer);
+ modified_answer->Initialize(answer_copy, "1", "1");
+ SetRemoteDescriptionWithoutError(modified_answer); //
+
+ EXPECT_NE(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// kBundlePolicyMaxbundle and then we call SetRemoteDescription first.
+TEST_F(WebRtcSessionTest, TestMaxBundleWithSetRemoteDescriptionFirst) {
+ InitWithBundlePolicy(PeerConnectionInterface::kBundlePolicyMaxBundle);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetRemoteDescriptionWithoutError(offer);
+
+ EXPECT_EQ(session_->voice_rtp_transport_channel(),
+ session_->video_rtp_transport_channel());
+}
+
+// Adding a new channel to a BUNDLE which is already connected should directly
+// assign the bundle transport to the channel, without first setting a
+// disconnected non-bundle transport and then replacing it. The application
+// should not receive any changes in the ICE state.
+TEST_F(WebRtcSessionTest, TestAddChannelToConnectedBundle) {
+ AddInterface(rtc::SocketAddress(kClientAddrHost1, kClientAddrPort));
+ // Both BUNDLE and RTCP-mux need to be enabled for the ICE state to remain
+ // connected. Disabling either of these two means that we need to wait for the
+ // answer to find out if more transports are needed.
+ configuration_.bundle_policy =
+ PeerConnectionInterface::kBundlePolicyMaxBundle;
+ options_.disable_encryption = true;
+ InitWithRtcpMuxPolicy(PeerConnectionInterface::kRtcpMuxPolicyRequire);
+
+ // Negotiate an audio channel with MAX_BUNDLE enabled.
+ SendAudioOnlyStream2();
+ SessionDescriptionInterface* offer = CreateOffer();
+ SetLocalDescriptionWithoutError(offer);
+ EXPECT_EQ_WAIT(PeerConnectionInterface::kIceGatheringComplete,
+ observer_.ice_gathering_state_, kIceCandidatesTimeout);
+ std::string sdp;
+ offer->ToString(&sdp);
+ SessionDescriptionInterface* answer = webrtc::CreateSessionDescription(
+ JsepSessionDescription::kAnswer, sdp, nullptr);
+ ASSERT_TRUE(answer != NULL);
+ SetRemoteDescriptionWithoutError(answer);
+
+ // Wait for the ICE state to stabilize.
+ EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
+ observer_.ice_connection_state_, kIceCandidatesTimeout);
+ observer_.ice_connection_state_history_.clear();
+
+ // Now add a video channel which should be using the same bundle transport.
+ SendAudioVideoStream2();
+ offer = CreateOffer();
+ offer->ToString(&sdp);
+ SetLocalDescriptionWithoutError(offer);
+ answer = webrtc::CreateSessionDescription(JsepSessionDescription::kAnswer,
+ sdp, nullptr);
+ ASSERT_TRUE(answer != NULL);
+ SetRemoteDescriptionWithoutError(answer);
+
+ // Wait for ICE state to stabilize
+ rtc::Thread::Current()->ProcessMessages(0);
+ EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
+ observer_.ice_connection_state_, kIceCandidatesTimeout);
+
+ // No ICE state changes are expected to happen.
+ EXPECT_EQ(0, observer_.ice_connection_state_history_.size());
+}
+
+TEST_F(WebRtcSessionTest, TestRequireRtcpMux) {
+ InitWithRtcpMuxPolicy(PeerConnectionInterface::kRtcpMuxPolicyRequire);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL);
+ EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL);
+
+ SendAudioVideoStream2();
+ SessionDescriptionInterface* answer =
+ CreateRemoteAnswer(session_->local_description());
+ SetRemoteDescriptionWithoutError(answer);
+
+ EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL);
+ EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL);
+}
+
+TEST_F(WebRtcSessionTest, TestNegotiateRtcpMux) {
+ InitWithRtcpMuxPolicy(PeerConnectionInterface::kRtcpMuxPolicyNegotiate);
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ SetLocalDescriptionWithoutError(offer);
+
+ EXPECT_TRUE(session_->voice_rtcp_transport_channel() != NULL);
+ EXPECT_TRUE(session_->video_rtcp_transport_channel() != NULL);
+
+ SendAudioVideoStream2();
+ SessionDescriptionInterface* answer =
+ CreateRemoteAnswer(session_->local_description());
+ SetRemoteDescriptionWithoutError(answer);
+
+ EXPECT_TRUE(session_->voice_rtcp_transport_channel() == NULL);
+ EXPECT_TRUE(session_->video_rtcp_transport_channel() == NULL);
+}
+
+// This test verifies that SetLocalDescription and SetRemoteDescription fails
+// if BUNDLE is enabled but rtcp-mux is disabled in m-lines.
+TEST_F(WebRtcSessionTest, TestDisabledRtcpMuxWithBundleEnabled) {
+ Init();
+ SendAudioVideoStream1();
+
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.use_rtp_mux = true;
+
+ SessionDescriptionInterface* offer = CreateOffer(options);
+ std::string offer_str;
+ offer->ToString(&offer_str);
+ // Disable rtcp-mux
+ const std::string rtcp_mux = "rtcp-mux";
+ const std::string xrtcp_mux = "xrtcp-mux";
+ rtc::replace_substrs(rtcp_mux.c_str(), rtcp_mux.length(),
+ xrtcp_mux.c_str(), xrtcp_mux.length(),
+ &offer_str);
+ SessionDescriptionInterface* local_offer = CreateSessionDescription(
+ SessionDescriptionInterface::kOffer, offer_str, nullptr);
+ ASSERT_TRUE(local_offer);
+ SetLocalDescriptionOfferExpectError(kBundleWithoutRtcpMux, local_offer);
+
+ SessionDescriptionInterface* remote_offer = CreateSessionDescription(
+ SessionDescriptionInterface::kOffer, offer_str, nullptr);
+ ASSERT_TRUE(remote_offer);
+ SetRemoteDescriptionOfferExpectError(kBundleWithoutRtcpMux, remote_offer);
+
+ // Trying unmodified SDP.
+ SetLocalDescriptionWithoutError(offer);
+}
+
TEST_F(WebRtcSessionTest, TestRtpDataChannel) {
configuration_.enable_rtp_data_channel = true;
Init();