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