Revert "Rewrite WebRtcSession media tests as PeerConnection tests"

This reverts commit 3df5dcac9b339ba4d3f4969602f094c2c8035b51.

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 media tests as PeerConnection tests
> 
> Bug: webrtc:8222
> Change-Id: I782a3227e30de70eb8f6c26a48723cb3510a84ad
> Reviewed-on: https://webrtc-review.googlesource.com/6640
> Commit-Queue: Steve Anton <steveanton@webrtc.org>
> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#20364}

TBR=steveanton@webrtc.org,deadbeef@webrtc.org

Change-Id: Iaacc950d050ba2835d262908658dc045f234ef5b
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:8222
Reviewed-on: https://webrtc-review.googlesource.com/14160
Commit-Queue: Olga Sharonova <olka@webrtc.org>
Reviewed-by: Olga Sharonova <olka@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20375}
diff --git a/media/base/fakemediaengine.h b/media/base/fakemediaengine.h
index 7b09dd4..29a129f 100644
--- a/media/base/fakemediaengine.h
+++ b/media/base/fakemediaengine.h
@@ -488,11 +488,12 @@
       if (it != local_sinks_.end()) {
         RTC_CHECK(it->second->source() == source);
       } else {
-        local_sinks_.insert(std::make_pair(
-            ssrc, rtc::MakeUnique<VoiceChannelAudioSink>(source)));
+        local_sinks_.insert(
+            std::make_pair(ssrc, new VoiceChannelAudioSink(source)));
       }
     } else {
       if (it != local_sinks_.end()) {
+        delete it->second;
         local_sinks_.erase(it);
       }
     }
@@ -505,7 +506,7 @@
   std::map<uint32_t, double> output_scalings_;
   std::vector<DtmfInfo> dtmf_info_queue_;
   AudioOptions options_;
-  std::map<uint32_t, std::unique_ptr<VoiceChannelAudioSink>> local_sinks_;
+  std::map<uint32_t, VoiceChannelAudioSink*> local_sinks_;
   std::unique_ptr<webrtc::AudioSinkInterface> sink_;
   int max_bps_;
 };
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 02a8e9a..c77a638 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -394,9 +394,7 @@
       "peerconnection_crypto_unittest.cc",
       "peerconnection_ice_unittest.cc",
       "peerconnection_integrationtest.cc",
-      "peerconnection_media_unittest.cc",
       "peerconnection_rtp_unittest.cc",
-      "peerconnection_signaling_unittest.cc",
       "peerconnectionendtoend_unittest.cc",
       "peerconnectionfactory_unittest.cc",
       "peerconnectioninterface_unittest.cc",
@@ -465,9 +463,7 @@
       "../api/audio_codecs:builtin_audio_encoder_factory",
       "../api/audio_codecs/L16:audio_decoder_L16",
       "../api/audio_codecs/L16:audio_encoder_L16",
-      "../call:call_interfaces",
       "../logging:rtc_event_log_api",
-      "../logging:rtc_event_log_impl",
       "../media:rtc_audio_video",
       "../media:rtc_data",  # TODO(phoglund): AFAIK only used for one sctp constant.
       "../media:rtc_media_base",
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 7cad0e1..9eb12d6 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -828,7 +828,10 @@
 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
                                  const MediaConstraintsInterface* constraints) {
   TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
-
+  if (!observer) {
+    LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
+    return;
+  }
   PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options;
   // Always create an offer even if |ConvertConstraintsToOfferAnswerOptions|
   // returns false for now. Because |ConvertConstraintsToOfferAnswerOptions|
@@ -845,19 +848,11 @@
 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
                                  const RTCOfferAnswerOptions& options) {
   TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
-
   if (!observer) {
     LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
     return;
   }
 
-  if (IsClosed()) {
-    std::string error = "CreateOffer called when PeerConnection is closed.";
-    LOG(LS_ERROR) << error;
-    PostCreateSessionDescriptionFailure(observer, error);
-    return;
-  }
-
   if (!ValidateOfferAnswerOptions(options)) {
     std::string error = "CreateOffer called with invalid options.";
     LOG(LS_ERROR) << error;
@@ -874,12 +869,20 @@
     CreateSessionDescriptionObserver* observer,
     const MediaConstraintsInterface* constraints) {
   TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
-
   if (!observer) {
     LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
     return;
   }
 
+  if (!session_->remote_description() ||
+      session_->remote_description()->type() !=
+          SessionDescriptionInterface::kOffer) {
+    std::string error = "CreateAnswer called without remote offer.";
+    LOG(LS_ERROR) << error;
+    PostCreateSessionDescriptionFailure(observer, error);
+    return;
+  }
+
   PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options;
   if (!ConvertConstraintsToOfferAnswerOptions(constraints,
                                               &offer_answer_options)) {
@@ -889,7 +892,9 @@
     return;
   }
 
-  CreateAnswer(observer, offer_answer_options);
+  cricket::MediaSessionOptions session_options;
+  GetOptionsForAnswer(offer_answer_options, &session_options);
+  session_->CreateAnswer(observer, session_options);
 }
 
 void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer,
@@ -900,22 +905,6 @@
     return;
   }
 
-  if (IsClosed()) {
-    std::string error = "CreateAnswer called when PeerConnection is closed.";
-    LOG(LS_ERROR) << error;
-    PostCreateSessionDescriptionFailure(observer, error);
-    return;
-  }
-
-  if (!session_->remote_description() ||
-      session_->remote_description()->type() !=
-          SessionDescriptionInterface::kOffer) {
-    std::string error = "CreateAnswer called without remote offer.";
-    LOG(LS_ERROR) << error;
-    PostCreateSessionDescriptionFailure(observer, error);
-    return;
-  }
-
   cricket::MediaSessionOptions session_options;
   GetOptionsForAnswer(options, &session_options);
 
@@ -926,6 +915,9 @@
     SetSessionDescriptionObserver* observer,
     SessionDescriptionInterface* desc) {
   TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
+  if (IsClosed()) {
+    return;
+  }
   if (!observer) {
     LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
     return;
@@ -934,23 +926,11 @@
     PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
     return;
   }
-
-  // Takes the ownership of |desc| regardless of the result.
-  std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
-
-  if (IsClosed()) {
-    std::string error = "Failed to set local " + desc->type() +
-                        " SDP: Called in wrong state: STATE_CLOSED";
-    LOG(LS_ERROR) << error;
-    PostSetSessionDescriptionFailure(observer, error);
-    return;
-  }
-
   // Update stats here so that we have the most recent stats for tracks and
   // streams that might be removed by updating the session description.
   stats_->UpdateStats(kStatsOutputLevelStandard);
   std::string error;
-  if (!session_->SetLocalDescription(std::move(desc_temp), &error)) {
+  if (!session_->SetLocalDescription(desc, &error)) {
     PostSetSessionDescriptionFailure(observer, error);
     return;
   }
@@ -1031,6 +1011,9 @@
     SetSessionDescriptionObserver* observer,
     SessionDescriptionInterface* desc) {
   TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
+  if (IsClosed()) {
+    return;
+  }
   if (!observer) {
     LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
     return;
@@ -1039,23 +1022,11 @@
     PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
     return;
   }
-
-  // Takes the ownership of |desc| regardless of the result.
-  std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
-
-  if (IsClosed()) {
-    std::string error = "Failed to set remote " + desc->type() +
-                        " SDP: Called in wrong state: STATE_CLOSED";
-    LOG(LS_ERROR) << error;
-    PostSetSessionDescriptionFailure(observer, error);
-    return;
-  }
-
   // Update stats here so that we have the most recent stats for tracks and
   // streams that might be removed by updating the session description.
   stats_->UpdateStats(kStatsOutputLevelStandard);
   std::string error;
-  if (!session_->SetRemoteDescription(std::move(desc_temp), &error)) {
+  if (!session_->SetRemoteDescription(desc, &error)) {
     PostSetSessionDescriptionFailure(observer, error);
     return;
   }
@@ -1090,15 +1061,6 @@
   // since only at that point will new streams have all their tracks.
   rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
 
-  // TODO(steveanton): When removing RTP senders/receivers in response to a
-  // rejected media section, there is some cleanup logic that expects the voice/
-  // video channel to still be set. But in this method the voice/video channel
-  // would have been destroyed by WebRtcSession's SetRemoteDescription method
-  // above, so the cleanup that relies on them fails to run. This is hard to fix
-  // with WebRtcSession and PeerConnection separated, but once the classes are
-  // merged it will be easy to call RemoveTracks right before destroying the
-  // voice/video channels.
-
   // Find all audio rtp streams and create corresponding remote AudioTracks
   // and MediaStreams.
   if (audio_content) {
diff --git a/pc/peerconnection_crypto_unittest.cc b/pc/peerconnection_crypto_unittest.cc
index 68eec08..081e11a 100644
--- a/pc/peerconnection_crypto_unittest.cc
+++ b/pc/peerconnection_crypto_unittest.cc
@@ -75,8 +75,7 @@
     if (!wrapper) {
       return nullptr;
     }
-    wrapper->AddAudioTrack("a");
-    wrapper->AddVideoTrack("v");
+    wrapper->AddAudioVideoStream("s", "a", "v");
     return wrapper;
   }
 
diff --git a/pc/peerconnection_ice_unittest.cc b/pc/peerconnection_ice_unittest.cc
index 3ab9acb..0880018 100644
--- a/pc/peerconnection_ice_unittest.cc
+++ b/pc/peerconnection_ice_unittest.cc
@@ -120,8 +120,7 @@
     if (!wrapper) {
       return nullptr;
     }
-    wrapper->AddAudioTrack("a");
-    wrapper->AddVideoTrack("v");
+    wrapper->AddAudioVideoStream("s", "a", "v");
     return wrapper;
   }
 
diff --git a/pc/peerconnection_media_unittest.cc b/pc/peerconnection_media_unittest.cc
deleted file mode 100644
index f106bbe..0000000
--- a/pc/peerconnection_media_unittest.cc
+++ /dev/null
@@ -1,889 +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.
- */
-
-// This file contains tests that check the interaction between the
-// PeerConnection and the underlying media engine, as well as tests that check
-// the media-related aspects of SDP.
-
-#include <tuple>
-
-#include "call/callfactoryinterface.h"
-#include "logging/rtc_event_log/rtc_event_log_factory.h"
-#include "media/base/fakemediaengine.h"
-#include "p2p/base/fakeportallocator.h"
-#include "pc/mediasession.h"
-#include "pc/peerconnectionwrapper.h"
-#include "pc/sdputils.h"
-#ifdef WEBRTC_ANDROID
-#include "pc/test/androidtestinitializer.h"
-#endif
-#include "pc/test/fakertccertificategenerator.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/ptr_util.h"
-#include "rtc_base/virtualsocketserver.h"
-#include "test/gmock.h"
-
-namespace webrtc {
-
-using cricket::FakeMediaEngine;
-using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
-using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
-using ::testing::Bool;
-using ::testing::Combine;
-using ::testing::Values;
-using ::testing::ElementsAre;
-
-class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
- public:
-  using PeerConnectionWrapper::PeerConnectionWrapper;
-
-  FakeMediaEngine* media_engine() { return media_engine_; }
-  void set_media_engine(FakeMediaEngine* media_engine) {
-    media_engine_ = media_engine;
-  }
-
- private:
-  FakeMediaEngine* media_engine_;
-};
-
-class PeerConnectionMediaTest : public ::testing::Test {
- protected:
-  typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
-
-  PeerConnectionMediaTest()
-      : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
-#ifdef WEBRTC_ANDROID
-    InitializeAndroidObjects();
-#endif
-  }
-
-  WrapperPtr CreatePeerConnection() {
-    return CreatePeerConnection(RTCConfiguration());
-  }
-
-  WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
-    auto media_engine = rtc::MakeUnique<FakeMediaEngine>();
-    auto* media_engine_ptr = media_engine.get();
-    auto pc_factory = CreateModularPeerConnectionFactory(
-        rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
-        std::move(media_engine), CreateCallFactory(),
-        CreateRtcEventLogFactory());
-
-    auto fake_port_allocator = rtc::MakeUnique<cricket::FakePortAllocator>(
-        rtc::Thread::Current(), nullptr);
-    auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
-    auto pc = pc_factory->CreatePeerConnection(
-        config, std::move(fake_port_allocator), nullptr, observer.get());
-    if (!pc) {
-      return nullptr;
-    }
-
-    auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForMediaTest>(
-        pc_factory, pc, std::move(observer));
-    wrapper->set_media_engine(media_engine_ptr);
-    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;
-  }
-
-  const cricket::MediaContentDescription* GetMediaContent(
-      const SessionDescriptionInterface* sdesc,
-      const std::string& mid) {
-    const auto* content_desc =
-        sdesc->description()->GetContentDescriptionByName(mid);
-    return static_cast<const cricket::MediaContentDescription*>(content_desc);
-  }
-
-  cricket::MediaContentDirection GetMediaContentDirection(
-      const SessionDescriptionInterface* sdesc,
-      const std::string& mid) {
-    auto* media_content = GetMediaContent(sdesc, mid);
-    RTC_DCHECK(media_content);
-    return media_content->direction();
-  }
-
-  std::unique_ptr<rtc::VirtualSocketServer> vss_;
-  rtc::AutoSocketServerThread main_;
-};
-
-TEST_F(PeerConnectionMediaTest,
-       FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-  callee->media_engine()->set_fail_create_channel(true);
-
-  std::string error;
-  ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
-  EXPECT_EQ("Failed to set remote offer SDP: Failed to create channels.",
-            error);
-}
-
-TEST_F(PeerConnectionMediaTest,
-       FailToSetLocalDescriptionIfCreateMediaChannelFails) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  caller->media_engine()->set_fail_create_channel(true);
-
-  std::string error;
-  ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
-  EXPECT_EQ("Failed to set local offer SDP: Failed to create channels.", error);
-}
-
-std::vector<std::string> GetIds(
-    const std::vector<cricket::StreamParams>& streams) {
-  std::vector<std::string> ids;
-  for (const auto& stream : streams) {
-    ids.push_back(stream.id);
-  }
-  return ids;
-}
-
-// Test that exchanging an offer and answer with each side having an audio and
-// video stream creates the appropriate send/recv streams in the underlying
-// media engine on both sides.
-TEST_F(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
-  const std::string kCallerAudioId = "caller_a";
-  const std::string kCallerVideoId = "caller_v";
-  const std::string kCalleeAudioId = "callee_a";
-  const std::string kCalleeVideoId = "callee_v";
-
-  auto caller = CreatePeerConnection();
-  caller->AddAudioTrack(kCallerAudioId);
-  caller->AddVideoTrack(kCallerVideoId);
-
-  auto callee = CreatePeerConnection();
-  callee->AddAudioTrack(kCalleeAudioId);
-  callee->AddVideoTrack(kCalleeVideoId);
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
-  EXPECT_THAT(GetIds(caller_voice->recv_streams()),
-              ElementsAre(kCalleeAudioId));
-  EXPECT_THAT(GetIds(caller_voice->send_streams()),
-              ElementsAre(kCallerAudioId));
-
-  auto* caller_video = caller->media_engine()->GetVideoChannel(0);
-  EXPECT_THAT(GetIds(caller_video->recv_streams()),
-              ElementsAre(kCalleeVideoId));
-  EXPECT_THAT(GetIds(caller_video->send_streams()),
-              ElementsAre(kCallerVideoId));
-
-  auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  EXPECT_THAT(GetIds(callee_voice->recv_streams()),
-              ElementsAre(kCallerAudioId));
-  EXPECT_THAT(GetIds(callee_voice->send_streams()),
-              ElementsAre(kCalleeAudioId));
-
-  auto* callee_video = callee->media_engine()->GetVideoChannel(0);
-  EXPECT_THAT(GetIds(callee_video->recv_streams()),
-              ElementsAre(kCallerVideoId));
-  EXPECT_THAT(GetIds(callee_video->send_streams()),
-              ElementsAre(kCalleeVideoId));
-}
-
-// Test that removing streams from a subsequent offer causes the receive streams
-// on the callee to be removed.
-TEST_F(PeerConnectionMediaTest, EmptyRemoteOfferRemovesRecvStreams) {
-  auto caller = CreatePeerConnection();
-  auto caller_audio_track = caller->AddAudioTrack("a");
-  auto caller_video_track = caller->AddVideoTrack("v");
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  // Remove both tracks from caller.
-  caller->pc()->RemoveTrack(caller_audio_track);
-  caller->pc()->RemoveTrack(caller_video_track);
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  EXPECT_EQ(1u, callee_voice->send_streams().size());
-  EXPECT_EQ(0u, callee_voice->recv_streams().size());
-
-  auto callee_video = callee->media_engine()->GetVideoChannel(0);
-  EXPECT_EQ(1u, callee_video->send_streams().size());
-  EXPECT_EQ(0u, callee_video->recv_streams().size());
-}
-
-// Test that removing streams from a subsequent answer causes the send streams
-// on the callee to be removed when applied locally.
-TEST_F(PeerConnectionMediaTest, EmptyLocalAnswerRemovesSendStreams) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnection();
-  auto callee_audio_track = callee->AddAudioTrack("a");
-  auto callee_video_track = callee->AddVideoTrack("v");
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  // Remove both tracks from callee.
-  callee->pc()->RemoveTrack(callee_audio_track);
-  callee->pc()->RemoveTrack(callee_video_track);
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  EXPECT_EQ(0u, callee_voice->send_streams().size());
-  EXPECT_EQ(1u, callee_voice->recv_streams().size());
-
-  auto callee_video = callee->media_engine()->GetVideoChannel(0);
-  EXPECT_EQ(0u, callee_video->send_streams().size());
-  EXPECT_EQ(1u, callee_video->recv_streams().size());
-}
-
-// Test that a new stream in a subsequent offer causes a new receive stream to
-// be created on the callee.
-TEST_F(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnection();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  // Add second set of tracks to the caller.
-  caller->AddAudioTrack("a2");
-  caller->AddVideoTrack("v2");
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  EXPECT_EQ(2u, callee_voice->recv_streams().size());
-  auto callee_video = callee->media_engine()->GetVideoChannel(0);
-  EXPECT_EQ(2u, callee_video->recv_streams().size());
-}
-
-// Test that a new stream in a subsequent answer causes a new send stream to be
-// created on the callee when added locally.
-TEST_F(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
-  auto caller = CreatePeerConnection();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  RTCOfferAnswerOptions options;
-  options.offer_to_receive_audio =
-      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
-  options.offer_to_receive_video =
-      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
-
-  ASSERT_TRUE(
-      callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  // Add second set of tracks to the callee.
-  callee->AddAudioTrack("a2");
-  callee->AddVideoTrack("v2");
-
-  ASSERT_TRUE(
-      callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  EXPECT_EQ(2u, callee_voice->send_streams().size());
-  auto callee_video = callee->media_engine()->GetVideoChannel(0);
-  EXPECT_EQ(2u, callee_video->send_streams().size());
-}
-
-// A PeerConnection with no local streams and no explicit answer constraints
-// should not reject any offered media sections.
-TEST_F(PeerConnectionMediaTest,
-       CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnection();
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  auto answer = callee->CreateAnswer();
-
-  const auto* audio_content =
-      cricket::GetFirstAudioContent(answer->description());
-  ASSERT_TRUE(audio_content);
-  EXPECT_FALSE(audio_content->rejected);
-
-  const auto* video_content =
-      cricket::GetFirstVideoContent(answer->description());
-  ASSERT_TRUE(video_content);
-  EXPECT_FALSE(video_content->rejected);
-}
-
-class PeerConnectionMediaOfferDirectionTest
-    : public PeerConnectionMediaTest,
-      public ::testing::WithParamInterface<
-          std::tuple<bool, int, cricket::MediaContentDirection>> {
- protected:
-  PeerConnectionMediaOfferDirectionTest() {
-    send_media_ = std::get<0>(GetParam());
-    offer_to_receive_ = std::get<1>(GetParam());
-    expected_direction_ = std::get<2>(GetParam());
-  }
-
-  bool send_media_;
-  int offer_to_receive_;
-  cricket::MediaContentDirection expected_direction_;
-};
-
-// Tests that the correct direction is set on the media description according
-// to the presence of a local media track and the offer_to_receive setting.
-TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
-  auto caller = CreatePeerConnection();
-  if (send_media_) {
-    caller->AddAudioTrack("a");
-  }
-
-  RTCOfferAnswerOptions options;
-  options.offer_to_receive_audio = offer_to_receive_;
-  auto offer = caller->CreateOffer(options);
-
-  auto* media_content = GetMediaContent(offer.get(), cricket::CN_AUDIO);
-  if (expected_direction_ == cricket::MD_INACTIVE) {
-    EXPECT_FALSE(media_content);
-  } else {
-    EXPECT_EQ(expected_direction_, media_content->direction());
-  }
-}
-
-// Note that in these tests, MD_INACTIVE indicates that no media section is
-// included in the offer, not that the media direction is inactive.
-INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
-                        PeerConnectionMediaOfferDirectionTest,
-                        Values(std::make_tuple(false, -1, cricket::MD_INACTIVE),
-                               std::make_tuple(false, 0, cricket::MD_INACTIVE),
-                               std::make_tuple(false, 1, cricket::MD_RECVONLY),
-                               std::make_tuple(true, -1, cricket::MD_SENDRECV),
-                               std::make_tuple(true, 0, cricket::MD_SENDONLY),
-                               std::make_tuple(true, 1, cricket::MD_SENDRECV)));
-
-class PeerConnectionMediaAnswerDirectionTest
-    : public PeerConnectionMediaTest,
-      public ::testing::WithParamInterface<
-          std::tuple<cricket::MediaContentDirection, bool, int>> {
- protected:
-  PeerConnectionMediaAnswerDirectionTest() {
-    offer_direction_ = std::get<0>(GetParam());
-    send_media_ = std::get<1>(GetParam());
-    offer_to_receive_ = std::get<2>(GetParam());
-  }
-
-  cricket::MediaContentDirection offer_direction_;
-  bool send_media_;
-  int offer_to_receive_;
-};
-
-// Tests that the direction in an answer is correct according to direction sent
-// in the offer, the presence of a local media track on the receive side and the
-// offer_to_receive setting.
-TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
-  auto caller = CreatePeerConnection();
-  caller->AddAudioTrack("a");
-
-  // Create the offer with an audio section and set its direction.
-  auto offer = caller->CreateOffer();
-  cricket::GetFirstAudioContentDescription(offer->description())
-      ->set_direction(offer_direction_);
-
-  auto callee = CreatePeerConnection();
-  if (send_media_) {
-    callee->AddAudioTrack("a");
-  }
-  ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
-
-  // Create the answer according to the test parameters.
-  RTCOfferAnswerOptions options;
-  options.offer_to_receive_audio = offer_to_receive_;
-  auto answer = callee->CreateAnswer(options);
-
-  // The expected direction in the answer is the intersection of each side's
-  // capability to send/recv media.
-  // For the offerer, the direction is given in the offer (offer_direction_).
-  // For the answerer, the direction has two components:
-  // 1. Send if the answerer has a local track to send.
-  // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
-  //    if it has been left as default.
-  auto offer_direction =
-      cricket::RtpTransceiverDirection::FromMediaContentDirection(
-          offer_direction_);
-
-  // The negotiated components determine the direction set in the answer.
-  bool negotiate_send = (send_media_ && offer_direction.recv);
-  bool negotiate_recv = ((offer_to_receive_ != 0) && offer_direction.send);
-
-  auto expected_direction =
-      cricket::RtpTransceiverDirection(negotiate_send, negotiate_recv)
-          .ToMediaContentDirection();
-  EXPECT_EQ(expected_direction,
-            GetMediaContentDirection(answer.get(), cricket::CN_AUDIO));
-}
-
-// Tests that the media section is rejected if and only if the callee has no
-// local media track and has set offer_to_receive to 0, no matter which
-// direction the caller indicated in the offer.
-TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
-  auto caller = CreatePeerConnection();
-  caller->AddAudioTrack("a");
-
-  // Create the offer with an audio section and set its direction.
-  auto offer = caller->CreateOffer();
-  cricket::GetFirstAudioContentDescription(offer->description())
-      ->set_direction(offer_direction_);
-
-  auto callee = CreatePeerConnection();
-  if (send_media_) {
-    callee->AddAudioTrack("a");
-  }
-  ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
-
-  // Create the answer according to the test parameters.
-  RTCOfferAnswerOptions options;
-  options.offer_to_receive_audio = offer_to_receive_;
-  auto answer = callee->CreateAnswer(options);
-
-  // The media section is rejected if and only if offer_to_receive is explicitly
-  // set to 0 and there is no media to send.
-  auto* audio_content = cricket::GetFirstAudioContent(answer->description());
-  ASSERT_TRUE(audio_content);
-  EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
-}
-
-INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
-                        PeerConnectionMediaAnswerDirectionTest,
-                        Combine(Values(cricket::MD_INACTIVE,
-                                       cricket::MD_SENDONLY,
-                                       cricket::MD_RECVONLY,
-                                       cricket::MD_SENDRECV),
-                                Bool(),
-                                Values(-1, 0, 1)));
-
-TEST_F(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
-  auto caller = CreatePeerConnection();
-  caller->AddVideoTrack("v");
-
-  RTCOfferAnswerOptions options;
-  options.offer_to_receive_audio = 1;
-  options.offer_to_receive_video = 0;
-  auto offer = caller->CreateOffer(options);
-
-  EXPECT_EQ(cricket::MD_RECVONLY,
-            GetMediaContentDirection(offer.get(), cricket::CN_AUDIO));
-  EXPECT_EQ(cricket::MD_SENDONLY,
-            GetMediaContentDirection(offer.get(), cricket::CN_VIDEO));
-}
-
-TEST_F(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnection();
-  callee->AddVideoTrack("v");
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  RTCOfferAnswerOptions options;
-  options.offer_to_receive_audio = 1;
-  options.offer_to_receive_video = 0;
-  auto answer = callee->CreateAnswer(options);
-
-  EXPECT_EQ(cricket::MD_RECVONLY,
-            GetMediaContentDirection(answer.get(), cricket::CN_AUDIO));
-  EXPECT_EQ(cricket::MD_SENDONLY,
-            GetMediaContentDirection(answer.get(), cricket::CN_VIDEO));
-}
-
-void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
-  const cricket::AudioCodec kComfortNoiseCodec8k(102, "CN", 8000, 0, 1);
-  const cricket::AudioCodec kComfortNoiseCodec16k(103, "CN", 16000, 0, 1);
-
-  auto codecs = media_engine->audio_send_codecs();
-  codecs.push_back(kComfortNoiseCodec8k);
-  codecs.push_back(kComfortNoiseCodec16k);
-  media_engine->SetAudioCodecs(codecs);
-}
-
-bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
-  const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
-  for (const auto& codec : audio_desc->codecs()) {
-    if (codec.name == "CN") {
-      return true;
-    }
-  }
-  return false;
-}
-
-TEST_F(PeerConnectionMediaTest,
-       CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  AddComfortNoiseCodecsToSend(caller->media_engine());
-
-  RTCOfferAnswerOptions options;
-  options.voice_activity_detection = false;
-  auto offer = caller->CreateOffer(options);
-
-  EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
-}
-
-TEST_F(PeerConnectionMediaTest,
-       CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  AddComfortNoiseCodecsToSend(caller->media_engine());
-  auto callee = CreatePeerConnectionWithAudioVideo();
-  AddComfortNoiseCodecsToSend(callee->media_engine());
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  RTCOfferAnswerOptions options;
-  options.voice_activity_detection = false;
-  auto answer = callee->CreateAnswer(options);
-
-  EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
-}
-
-// The following test group verifies that we reject answers with invalid media
-// sections as per RFC 3264.
-
-class PeerConnectionMediaInvalidMediaTest
-    : public PeerConnectionMediaTest,
-      public ::testing::WithParamInterface<
-          std::tuple<std::string,
-                     std::function<void(cricket::SessionDescription*)>,
-                     std::string>> {
- protected:
-  PeerConnectionMediaInvalidMediaTest() {
-    mutator_ = std::get<1>(GetParam());
-    expected_error_ = std::get<2>(GetParam());
-  }
-
-  std::function<void(cricket::SessionDescription*)> mutator_;
-  std::string expected_error_;
-};
-
-TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  auto answer = callee->CreateAnswer();
-  mutator_(answer->description());
-
-  std::string error;
-  ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
-  EXPECT_EQ("Failed to set remote answer SDP: " + expected_error_, error);
-}
-
-TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  auto answer = callee->CreateAnswer();
-  mutator_(answer->description());
-
-  std::string error;
-  ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
-  EXPECT_EQ("Failed to set local answer SDP: " + expected_error_, error);
-}
-
-void RemoveVideoContent(cricket::SessionDescription* desc) {
-  auto content_name = cricket::GetFirstVideoContent(desc)->name;
-  desc->RemoveContentByName(content_name);
-  desc->RemoveTransportInfoByName(content_name);
-}
-
-void RenameVideoContent(cricket::SessionDescription* desc) {
-  auto* video_content = cricket::GetFirstVideoContent(desc);
-  auto* transport_info = desc->GetTransportInfoByName(video_content->name);
-  video_content->name = "video_renamed";
-  transport_info->content_name = video_content->name;
-}
-
-void ReverseMediaContent(cricket::SessionDescription* desc) {
-  std::reverse(desc->contents().begin(), desc->contents().end());
-  std::reverse(desc->transport_infos().begin(), desc->transport_infos().end());
-}
-
-void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
-  desc->RemoveContentByName(cricket::CN_AUDIO);
-  auto* video_content = desc->GetContentByName(cricket::CN_VIDEO);
-  desc->AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP,
-                   video_content->description->Copy());
-}
-
-constexpr char kMLinesOutOfOrder[] =
-    "The order of m-lines in answer doesn't match order in offer. Rejecting "
-    "answer.";
-
-INSTANTIATE_TEST_CASE_P(
-    PeerConnectionMediaTest,
-    PeerConnectionMediaInvalidMediaTest,
-    Values(
-        std::make_tuple("remove video", RemoveVideoContent, kMLinesOutOfOrder),
-        std::make_tuple("rename video", RenameVideoContent, kMLinesOutOfOrder),
-        std::make_tuple("reverse media sections",
-                        ReverseMediaContent,
-                        kMLinesOutOfOrder),
-        std::make_tuple("change audio type to video type",
-                        ChangeMediaTypeAudioToVideo,
-                        kMLinesOutOfOrder)));
-
-// Test that the correct media engine send/recv streams are created when doing
-// a series of offer/answers where audio/video are both sent, then audio is
-// rejected, then both audio/video sent again.
-TEST_F(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
-  RTCOfferAnswerOptions options_reject_video;
-  options_reject_video.offer_to_receive_audio =
-      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
-  options_reject_video.offer_to_receive_video = 0;
-
-  auto caller = CreatePeerConnection();
-  caller->AddAudioTrack("a");
-  caller->AddVideoTrack("v");
-  auto callee = CreatePeerConnection();
-
-  // Caller initially offers to send/recv audio and video.
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  // Callee accepts the audio as recv only but rejects the video.
-  ASSERT_TRUE(caller->SetRemoteDescription(
-      callee->CreateAnswerAndSetAsLocal(options_reject_video)));
-
-  auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
-  ASSERT_TRUE(caller_voice);
-  EXPECT_EQ(0u, caller_voice->recv_streams().size());
-  EXPECT_EQ(1u, caller_voice->send_streams().size());
-  auto caller_video = caller->media_engine()->GetVideoChannel(0);
-  EXPECT_FALSE(caller_video);
-
-  // Callee adds its own audio/video stream and offers to receive audio/video
-  // too.
-  callee->AddAudioTrack("a");
-  auto callee_video_track = callee->AddVideoTrack("v");
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  ASSERT_TRUE(callee_voice);
-  EXPECT_EQ(1u, callee_voice->recv_streams().size());
-  EXPECT_EQ(1u, callee_voice->send_streams().size());
-  auto callee_video = callee->media_engine()->GetVideoChannel(0);
-  ASSERT_TRUE(callee_video);
-  EXPECT_EQ(1u, callee_video->recv_streams().size());
-  EXPECT_EQ(1u, callee_video->send_streams().size());
-
-  // Callee removes video but keeps audio and rejects the video once again.
-  callee->pc()->RemoveTrack(callee_video_track);
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
-
-  callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  ASSERT_TRUE(callee_voice);
-  EXPECT_EQ(1u, callee_voice->recv_streams().size());
-  EXPECT_EQ(1u, callee_voice->send_streams().size());
-  callee_video = callee->media_engine()->GetVideoChannel(0);
-  EXPECT_FALSE(callee_video);
-}
-
-// Test that the correct media engine send/recv streams are created when doing
-// a series of offer/answers where audio/video are both sent, then video is
-// rejected, then both audio/video sent again.
-TEST_F(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
-  // Disable the bundling here. If the media is bundled on audio
-  // transport, then we can't reject the audio because switching the bundled
-  // transport is not currently supported.
-  // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
-  RTCOfferAnswerOptions options_no_bundle;
-  options_no_bundle.use_rtp_mux = false;
-  RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
-  options_reject_audio.offer_to_receive_audio = 0;
-  options_reject_audio.offer_to_receive_video =
-      RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
-
-  auto caller = CreatePeerConnection();
-  caller->AddAudioTrack("a");
-  caller->AddVideoTrack("v");
-  auto callee = CreatePeerConnection();
-
-  // Caller initially offers to send/recv audio and video.
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  // Callee accepts the video as recv only but rejects the audio.
-  ASSERT_TRUE(caller->SetRemoteDescription(
-      callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
-
-  auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
-  EXPECT_FALSE(caller_voice);
-  auto caller_video = caller->media_engine()->GetVideoChannel(0);
-  ASSERT_TRUE(caller_video);
-  EXPECT_EQ(0u, caller_video->recv_streams().size());
-  EXPECT_EQ(1u, caller_video->send_streams().size());
-
-  // Callee adds its own audio/video stream and offers to receive audio/video
-  // too.
-  auto callee_audio_track = callee->AddAudioTrack("a");
-  callee->AddVideoTrack("v");
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(caller->SetRemoteDescription(
-      callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
-
-  auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  ASSERT_TRUE(callee_voice);
-  EXPECT_EQ(1u, callee_voice->recv_streams().size());
-  EXPECT_EQ(1u, callee_voice->send_streams().size());
-  auto callee_video = callee->media_engine()->GetVideoChannel(0);
-  ASSERT_TRUE(callee_video);
-  EXPECT_EQ(1u, callee_video->recv_streams().size());
-  EXPECT_EQ(1u, callee_video->send_streams().size());
-
-  // Callee removes audio but keeps video and rejects the audio once again.
-  callee->pc()->RemoveTrack(callee_audio_track);
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
-
-  callee_voice = callee->media_engine()->GetVoiceChannel(0);
-  EXPECT_FALSE(callee_voice);
-  callee_video = callee->media_engine()->GetVideoChannel(0);
-  ASSERT_TRUE(callee_video);
-  EXPECT_EQ(1u, callee_video->recv_streams().size());
-  EXPECT_EQ(1u, callee_video->send_streams().size());
-}
-
-// Tests that if the underlying video encoder fails to be initialized (signaled
-// by failing to set send codecs), the PeerConnection signals the error to the
-// client.
-TEST_F(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  auto video_channel = caller->media_engine()->GetVideoChannel(0);
-  video_channel->set_fail_set_send_codecs(true);
-
-  std::string error;
-  ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
-                                            &error));
-  EXPECT_EQ(
-      "Failed to set remote answer SDP: Session error code: ERROR_CONTENT. "
-      "Session error description: Failed to set remote video description send "
-      "parameters..",
-      error);
-}
-
-// Tests that if the underlying video encoder fails once then subsequent
-// attempts at setting the local/remote description will also fail, even if
-// SetSendCodecs no longer fails.
-TEST_F(PeerConnectionMediaTest,
-       FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  auto video_channel = caller->media_engine()->GetVideoChannel(0);
-  video_channel->set_fail_set_send_codecs(true);
-
-  EXPECT_FALSE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  video_channel->set_fail_set_send_codecs(false);
-
-  EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
-  EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
-}
-
-void RenameContent(cricket::SessionDescription* desc,
-                   const std::string& old_name,
-                   const std::string& new_name) {
-  auto* content = desc->GetContentByName(old_name);
-  RTC_DCHECK(content);
-  content->name = new_name;
-  auto* transport = desc->GetTransportInfoByName(old_name);
-  RTC_DCHECK(transport);
-  transport->content_name = new_name;
-}
-
-// Tests that an answer responds with the same MIDs as the offer.
-TEST_F(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
-  const std::string kAudioMid = "not default1";
-  const std::string kVideoMid = "not default2";
-
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  auto offer = caller->CreateOffer();
-  RenameContent(offer->description(), cricket::CN_AUDIO, kAudioMid);
-  RenameContent(offer->description(), cricket::CN_VIDEO, kVideoMid);
-  ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
-
-  auto answer = callee->CreateAnswer();
-  EXPECT_EQ(kAudioMid,
-            cricket::GetFirstAudioContent(answer->description())->name);
-  EXPECT_EQ(kVideoMid,
-            cricket::GetFirstVideoContent(answer->description())->name);
-}
-
-// Test that if the callee creates a re-offer, the MIDs are the same as the
-// original offer.
-TEST_F(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
-  const std::string kAudioMid = "not default1";
-  const std::string kVideoMid = "not default2";
-
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  auto offer = caller->CreateOffer();
-  RenameContent(offer->description(), cricket::CN_AUDIO, kAudioMid);
-  RenameContent(offer->description(), cricket::CN_VIDEO, kVideoMid);
-  ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
-  ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
-
-  auto reoffer = callee->CreateOffer();
-  EXPECT_EQ(kAudioMid,
-            cricket::GetFirstAudioContent(reoffer->description())->name);
-  EXPECT_EQ(kVideoMid,
-            cricket::GetFirstVideoContent(reoffer->description())->name);
-}
-
-TEST_F(PeerConnectionMediaTest,
-       CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
-  RTCConfiguration config;
-  config.combined_audio_video_bwe.emplace(true);
-  auto caller = CreatePeerConnectionWithAudioVideo(config);
-
-  ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
-
-  auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
-  ASSERT_TRUE(caller_voice);
-  const cricket::AudioOptions& audio_options = caller_voice->options();
-  EXPECT_EQ(config.combined_audio_video_bwe,
-            audio_options.combined_audio_video_bwe);
-}
-
-}  // namespace webrtc
diff --git a/pc/peerconnection_signaling_unittest.cc b/pc/peerconnection_signaling_unittest.cc
deleted file mode 100644
index caaac4c..0000000
--- a/pc/peerconnection_signaling_unittest.cc
+++ /dev/null
@@ -1,501 +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.
- */
-
-// This file contains tests that check the PeerConnection's signaling state
-// machine, as well as tests that check basic, media-agnostic aspects of SDP.
-
-#include <tuple>
-
-#include "api/audio_codecs/builtin_audio_decoder_factory.h"
-#include "api/audio_codecs/builtin_audio_encoder_factory.h"
-#include "api/peerconnectionproxy.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 "pc/test/fakertccertificategenerator.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/ptr_util.h"
-#include "rtc_base/stringutils.h"
-#include "rtc_base/virtualsocketserver.h"
-#include "test/gmock.h"
-
-namespace webrtc {
-
-using SignalingState = PeerConnectionInterface::SignalingState;
-using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
-using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
-using ::testing::Bool;
-using ::testing::Combine;
-using ::testing::Values;
-
-class PeerConnectionWrapperForSignalingTest : public PeerConnectionWrapper {
- public:
-  using PeerConnectionWrapper::PeerConnectionWrapper;
-
-  bool initial_offerer() {
-    return GetInternalPeerConnection()->initial_offerer();
-  }
-
-  PeerConnection* GetInternalPeerConnection() {
-    auto* pci = reinterpret_cast<
-        PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(pc());
-    return reinterpret_cast<PeerConnection*>(pci->internal());
-  }
-};
-
-class PeerConnectionSignalingTest : public ::testing::Test {
- protected:
-  typedef std::unique_ptr<PeerConnectionWrapperForSignalingTest> WrapperPtr;
-
-  PeerConnectionSignalingTest()
-      : 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(), CreateBuiltinAudioEncoderFactory(),
-        CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
-  }
-
-  WrapperPtr CreatePeerConnection() {
-    return CreatePeerConnection(RTCConfiguration());
-  }
-
-  WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
-    auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
-    auto pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr,
-                                                observer.get());
-    if (!pc) {
-      return nullptr;
-    }
-
-    return rtc::MakeUnique<PeerConnectionWrapperForSignalingTest>(
-        pc_factory_, pc, std::move(observer));
-  }
-
-  // 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;
-  }
-
-  std::unique_ptr<rtc::VirtualSocketServer> vss_;
-  rtc::AutoSocketServerThread main_;
-  rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
-};
-
-TEST_F(PeerConnectionSignalingTest, SetLocalOfferTwiceWorks) {
-  auto caller = CreatePeerConnection();
-
-  EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
-  EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
-}
-
-TEST_F(PeerConnectionSignalingTest, SetRemoteOfferTwiceWorks) {
-  auto caller = CreatePeerConnection();
-  auto callee = CreatePeerConnection();
-
-  EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
-  EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
-}
-
-TEST_F(PeerConnectionSignalingTest, FailToSetNullLocalDescription) {
-  auto caller = CreatePeerConnection();
-  std::string error;
-  ASSERT_FALSE(caller->SetLocalDescription(nullptr, &error));
-  EXPECT_EQ("SessionDescription is NULL.", error);
-}
-
-TEST_F(PeerConnectionSignalingTest, FailToSetNullRemoteDescription) {
-  auto caller = CreatePeerConnection();
-  std::string error;
-  ASSERT_FALSE(caller->SetRemoteDescription(nullptr, &error));
-  EXPECT_EQ("SessionDescription is NULL.", error);
-}
-
-// The following parameterized test verifies that calls to various signaling
-// methods on PeerConnection will succeed/fail depending on what is the
-// PeerConnection's signaling state. Note that the test tries many different
-// forms of SignalingState::kClosed by arriving at a valid state then calling
-// |Close()|. This is intended to catch cases where the PeerConnection signaling
-// method ignores the closed flag but may work/not work because of the single
-// state the PeerConnection was created in before it was closed.
-
-class PeerConnectionSignalingStateTest
-    : public PeerConnectionSignalingTest,
-      public ::testing::WithParamInterface<std::tuple<SignalingState, bool>> {
- protected:
-  RTCConfiguration GetConfig() {
-    RTCConfiguration config;
-    config.certificates.push_back(
-        FakeRTCCertificateGenerator::GenerateCertificate());
-    return config;
-  }
-
-  WrapperPtr CreatePeerConnectionInState(SignalingState state) {
-    return CreatePeerConnectionInState(std::make_tuple(state, false));
-  }
-
-  WrapperPtr CreatePeerConnectionInState(
-      std::tuple<SignalingState, bool> state_tuple) {
-    SignalingState state = std::get<0>(state_tuple);
-    bool closed = std::get<1>(state_tuple);
-
-    auto wrapper = CreatePeerConnectionWithAudioVideo(GetConfig());
-    switch (state) {
-      case SignalingState::kStable: {
-        break;
-      }
-      case SignalingState::kHaveLocalOffer: {
-        wrapper->SetLocalDescription(wrapper->CreateOffer());
-        break;
-      }
-      case SignalingState::kHaveLocalPrAnswer: {
-        auto caller = CreatePeerConnectionWithAudioVideo(GetConfig());
-        wrapper->SetRemoteDescription(caller->CreateOffer());
-        auto answer = wrapper->CreateAnswer();
-        wrapper->SetLocalDescription(CloneSessionDescriptionAsType(
-            answer.get(), SessionDescriptionInterface::kPrAnswer));
-        break;
-      }
-      case SignalingState::kHaveRemoteOffer: {
-        auto caller = CreatePeerConnectionWithAudioVideo(GetConfig());
-        wrapper->SetRemoteDescription(caller->CreateOffer());
-        break;
-      }
-      case SignalingState::kHaveRemotePrAnswer: {
-        auto callee = CreatePeerConnectionWithAudioVideo(GetConfig());
-        callee->SetRemoteDescription(wrapper->CreateOfferAndSetAsLocal());
-        auto answer = callee->CreateAnswer();
-        wrapper->SetRemoteDescription(CloneSessionDescriptionAsType(
-            answer.get(), SessionDescriptionInterface::kPrAnswer));
-        break;
-      }
-      case SignalingState::kClosed: {
-        RTC_NOTREACHED() << "Set the second member of the tuple to true to "
-                            "achieve a closed state from an existing, valid "
-                            "state.";
-      }
-    }
-
-    RTC_DCHECK_EQ(state, wrapper->pc()->signaling_state());
-
-    if (closed) {
-      wrapper->pc()->Close();
-      RTC_DCHECK_EQ(SignalingState::kClosed, wrapper->signaling_state());
-    }
-
-    return wrapper;
-  }
-};
-
-::testing::AssertionResult AssertStartsWith(const char* str_expr,
-                                            const char* prefix_expr,
-                                            const std::string& str,
-                                            const std::string& prefix) {
-  if (rtc::starts_with(str.c_str(), prefix.c_str())) {
-    return ::testing::AssertionSuccess();
-  } else {
-    return ::testing::AssertionFailure()
-           << str_expr << "\nwhich is\n\"" << str << "\"\ndoes not start with\n"
-           << prefix_expr << "\nwhich is\n\"" << prefix << "\"";
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, CreateOffer) {
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() != SignalingState::kClosed) {
-    EXPECT_TRUE(wrapper->CreateOffer());
-  } else {
-    std::string error;
-    ASSERT_FALSE(wrapper->CreateOffer(RTCOfferAnswerOptions(), &error));
-    EXPECT_PRED_FORMAT2(AssertStartsWith, error,
-                        "CreateOffer called when PeerConnection is closed.");
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, CreateAnswer) {
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
-      wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
-    EXPECT_TRUE(wrapper->CreateAnswer());
-  } else {
-    std::string error;
-    ASSERT_FALSE(wrapper->CreateAnswer(RTCOfferAnswerOptions(), &error));
-    if (wrapper->signaling_state() == SignalingState::kClosed) {
-      EXPECT_PRED_FORMAT2(AssertStartsWith, error,
-                          "CreateAnswer called when PeerConnection is closed.");
-    } else {
-      EXPECT_PRED_FORMAT2(AssertStartsWith, error,
-                          "CreateAnswer called without remote offer.");
-    }
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, SetLocalOffer) {
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() == SignalingState::kStable ||
-      wrapper->signaling_state() == SignalingState::kHaveLocalOffer) {
-    // Need to call CreateOffer on the PeerConnection under test, otherwise when
-    // setting the local offer it will want to verify the DTLS fingerprint
-    // against the locally generated certificate, but without a call to
-    // CreateOffer the certificate will never be generated.
-    EXPECT_TRUE(wrapper->SetLocalDescription(wrapper->CreateOffer()));
-  } else {
-    auto wrapper_for_offer =
-        CreatePeerConnectionInState(SignalingState::kHaveLocalOffer);
-    auto offer =
-        CloneSessionDescription(wrapper_for_offer->pc()->local_description());
-
-    std::string error;
-    ASSERT_FALSE(wrapper->SetLocalDescription(std::move(offer), &error));
-    EXPECT_PRED_FORMAT2(
-        AssertStartsWith, error,
-        "Failed to set local offer SDP: Called in wrong state:");
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, SetLocalPrAnswer) {
-  auto wrapper_for_pranswer =
-      CreatePeerConnectionInState(SignalingState::kHaveLocalPrAnswer);
-  auto pranswer =
-      CloneSessionDescription(wrapper_for_pranswer->pc()->local_description());
-
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
-      wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
-    EXPECT_TRUE(wrapper->SetLocalDescription(std::move(pranswer)));
-  } else {
-    std::string error;
-    ASSERT_FALSE(wrapper->SetLocalDescription(std::move(pranswer), &error));
-    EXPECT_PRED_FORMAT2(
-        AssertStartsWith, error,
-        "Failed to set local pranswer SDP: Called in wrong state:");
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, SetLocalAnswer) {
-  auto wrapper_for_answer =
-      CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
-  auto answer = wrapper_for_answer->CreateAnswer();
-
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
-      wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
-    EXPECT_TRUE(wrapper->SetLocalDescription(std::move(answer)));
-  } else {
-    std::string error;
-    ASSERT_FALSE(wrapper->SetLocalDescription(std::move(answer), &error));
-    EXPECT_PRED_FORMAT2(
-        AssertStartsWith, error,
-        "Failed to set local answer SDP: Called in wrong state:");
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, SetRemoteOffer) {
-  auto wrapper_for_offer =
-      CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
-  auto offer =
-      CloneSessionDescription(wrapper_for_offer->pc()->remote_description());
-
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() == SignalingState::kStable ||
-      wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
-    EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(offer)));
-  } else {
-    std::string error;
-    ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(offer), &error));
-    EXPECT_PRED_FORMAT2(
-        AssertStartsWith, error,
-        "Failed to set remote offer SDP: Called in wrong state:");
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, SetRemotePrAnswer) {
-  auto wrapper_for_pranswer =
-      CreatePeerConnectionInState(SignalingState::kHaveRemotePrAnswer);
-  auto pranswer =
-      CloneSessionDescription(wrapper_for_pranswer->pc()->remote_description());
-
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() == SignalingState::kHaveLocalOffer ||
-      wrapper->signaling_state() == SignalingState::kHaveRemotePrAnswer) {
-    EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(pranswer)));
-  } else {
-    std::string error;
-    ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(pranswer), &error));
-    EXPECT_PRED_FORMAT2(
-        AssertStartsWith, error,
-        "Failed to set remote pranswer SDP: Called in wrong state:");
-  }
-}
-
-TEST_P(PeerConnectionSignalingStateTest, SetRemoteAnswer) {
-  auto wrapper_for_answer =
-      CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
-  auto answer = wrapper_for_answer->CreateAnswer();
-
-  auto wrapper = CreatePeerConnectionInState(GetParam());
-  if (wrapper->signaling_state() == SignalingState::kHaveLocalOffer ||
-      wrapper->signaling_state() == SignalingState::kHaveRemotePrAnswer) {
-    EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(answer)));
-  } else {
-    std::string error;
-    ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(answer), &error));
-    EXPECT_PRED_FORMAT2(
-        AssertStartsWith, error,
-        "Failed to set remote answer SDP: Called in wrong state:");
-  }
-}
-
-INSTANTIATE_TEST_CASE_P(PeerConnectionSignalingTest,
-                        PeerConnectionSignalingStateTest,
-                        Combine(Values(SignalingState::kStable,
-                                       SignalingState::kHaveLocalOffer,
-                                       SignalingState::kHaveLocalPrAnswer,
-                                       SignalingState::kHaveRemoteOffer,
-                                       SignalingState::kHaveRemotePrAnswer),
-                                Bool()));
-
-TEST_F(PeerConnectionSignalingTest,
-       CreateAnswerSucceedsIfStableAndRemoteDescriptionIsOffer) {
-  auto caller = CreatePeerConnection();
-  auto callee = CreatePeerConnection();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  ASSERT_EQ(SignalingState::kStable, callee->signaling_state());
-  EXPECT_TRUE(callee->CreateAnswer());
-}
-
-TEST_F(PeerConnectionSignalingTest,
-       CreateAnswerFailsIfStableButRemoteDescriptionIsAnswer) {
-  auto caller = CreatePeerConnection();
-  auto callee = CreatePeerConnection();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  ASSERT_EQ(SignalingState::kStable, caller->signaling_state());
-  std::string error;
-  ASSERT_FALSE(caller->CreateAnswer(RTCOfferAnswerOptions(), &error));
-  EXPECT_EQ("CreateAnswer called without remote offer.", error);
-}
-
-// According to https://tools.ietf.org/html/rfc3264#section-8, the session id
-// stays the same but the version must be incremented if a later, different
-// session description is generated. These two tests verify that is the case for
-// both offers and answers.
-TEST_F(PeerConnectionSignalingTest,
-       SessionVersionIncrementedInSubsequentDifferentOffer) {
-  auto caller = CreatePeerConnection();
-  auto callee = CreatePeerConnection();
-
-  auto original_offer = caller->CreateOfferAndSetAsLocal();
-  const std::string original_id = original_offer->session_id();
-  const std::string original_version = original_offer->session_version();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(std::move(original_offer)));
-  ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
-
-  // Add track to get a different offer.
-  caller->AddAudioTrack("a");
-
-  auto later_offer = caller->CreateOffer();
-
-  EXPECT_EQ(original_id, later_offer->session_id());
-  EXPECT_LT(rtc::FromString<uint64_t>(original_version),
-            rtc::FromString<uint64_t>(later_offer->session_version()));
-}
-TEST_F(PeerConnectionSignalingTest,
-       SessionVersionIncrementedInSubsequentDifferentAnswer) {
-  auto caller = CreatePeerConnection();
-  auto callee = CreatePeerConnection();
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  auto original_answer = callee->CreateAnswerAndSetAsLocal();
-  const std::string original_id = original_answer->session_id();
-  const std::string original_version = original_answer->session_version();
-
-  // Add track to get a different answer.
-  callee->AddAudioTrack("a");
-
-  auto later_answer = callee->CreateAnswer();
-
-  EXPECT_EQ(original_id, later_answer->session_id());
-  EXPECT_LT(rtc::FromString<uint64_t>(original_version),
-            rtc::FromString<uint64_t>(later_answer->session_version()));
-}
-
-TEST_F(PeerConnectionSignalingTest, InitiatorFlagSetOnCallerAndNotOnCallee) {
-  auto caller = CreatePeerConnectionWithAudioVideo();
-  auto callee = CreatePeerConnectionWithAudioVideo();
-
-  EXPECT_FALSE(caller->initial_offerer());
-  EXPECT_FALSE(callee->initial_offerer());
-
-  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
-
-  EXPECT_TRUE(caller->initial_offerer());
-  EXPECT_FALSE(callee->initial_offerer());
-
-  ASSERT_TRUE(
-      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
-
-  EXPECT_TRUE(caller->initial_offerer());
-  EXPECT_FALSE(callee->initial_offerer());
-}
-
-// Test creating a PeerConnection, request multiple offers, destroy the
-// PeerConnection and make sure we get success/failure callbacks for all of the
-// requests.
-// Background: crbug.com/507307
-TEST_F(PeerConnectionSignalingTest, CreateOffersAndShutdown) {
-  auto caller = CreatePeerConnection();
-
-  RTCOfferAnswerOptions options;
-  options.offer_to_receive_audio =
-      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
-
-  rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observers[100];
-  for (auto& observer : observers) {
-    observer =
-        new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>();
-    caller->pc()->CreateOffer(observer, options);
-  }
-
-  // Destroy the PeerConnection.
-  caller.reset(nullptr);
-
-  for (auto& observer : observers) {
-    // We expect to have received a notification now even if the PeerConnection
-    // was terminated. The offer creation may or may not have succeeded, but we
-    // must have received a notification.
-    EXPECT_TRUE(observer->called());
-  }
-}
-
-}  // namespace webrtc
diff --git a/pc/peerconnectioninterface_unittest.cc b/pc/peerconnectioninterface_unittest.cc
index a8b4f72..99f3301 100644
--- a/pc/peerconnectioninterface_unittest.cc
+++ b/pc/peerconnectioninterface_unittest.cc
@@ -2517,9 +2517,9 @@
   EXPECT_TRUE(pc_->remote_description() != NULL);
 
   std::unique_ptr<SessionDescriptionInterface> offer;
-  EXPECT_FALSE(DoCreateOffer(&offer, nullptr));
+  EXPECT_TRUE(DoCreateOffer(&offer, nullptr));
   std::unique_ptr<SessionDescriptionInterface> answer;
-  EXPECT_FALSE(DoCreateAnswer(&answer, nullptr));
+  EXPECT_TRUE(DoCreateAnswer(&answer, nullptr));
 
   std::string sdp;
   ASSERT_TRUE(pc_->remote_description()->ToString(&sdp));
@@ -3558,6 +3558,32 @@
   EXPECT_NE(nullptr, GetFirstVideoContent(offer->description()));
 }
 
+// Test that if |voice_activity_detection| is false, no CN codec is added to the
+// offer.
+TEST_F(PeerConnectionInterfaceTest, CreateOfferWithVADOptions) {
+  RTCOfferAnswerOptions rtc_options;
+  rtc_options.offer_to_receive_audio = 1;
+  rtc_options.offer_to_receive_video = 0;
+
+  std::unique_ptr<SessionDescriptionInterface> offer;
+  CreatePeerConnection();
+  offer = CreateOfferWithOptions(rtc_options);
+  ASSERT_TRUE(offer);
+  const cricket::ContentInfo* audio_content =
+      offer->description()->GetContentByName(cricket::CN_AUDIO);
+  ASSERT_TRUE(audio_content);
+  // |voice_activity_detection| is true by default.
+  EXPECT_TRUE(HasCNCodecs(audio_content));
+
+  rtc_options.voice_activity_detection = false;
+  CreatePeerConnection();
+  offer = CreateOfferWithOptions(rtc_options);
+  ASSERT_TRUE(offer);
+  audio_content = offer->description()->GetContentByName(cricket::CN_AUDIO);
+  ASSERT_TRUE(audio_content);
+  EXPECT_FALSE(HasCNCodecs(audio_content));
+}
+
 // Test that no media content will be added to the offer if using default
 // RTCOfferAnswerOptions.
 TEST_F(PeerConnectionInterfaceTest, CreateOfferWithDefaultOfferAnswerOptions) {
@@ -3638,6 +3664,42 @@
   EXPECT_FALSE(offer->description()->HasGroup(cricket::GROUP_TYPE_BUNDLE));
 }
 
+// If SetMandatoryReceiveAudio(false) and SetMandatoryReceiveVideo(false) are
+// called for the answer constraints, but an audio and a video section were
+// offered, there will still be an audio and a video section in the answer.
+TEST_F(PeerConnectionInterfaceTest,
+       RejectAudioAndVideoInAnswerWithConstraints) {
+  // Offer both audio and video.
+  RTCOfferAnswerOptions rtc_offer_options;
+  rtc_offer_options.offer_to_receive_audio = 1;
+  rtc_offer_options.offer_to_receive_video = 1;
+
+  CreatePeerConnection();
+  std::unique_ptr<SessionDescriptionInterface> offer;
+  CreateOfferWithOptionsAsRemoteDescription(&offer, rtc_offer_options);
+  EXPECT_NE(nullptr, GetFirstAudioContent(offer->description()));
+  EXPECT_NE(nullptr, GetFirstVideoContent(offer->description()));
+
+  // Since an offer has been created with both audio and video,
+  // Answers will contain the media types that exist in the offer regardless of
+  // the value of |answer_options.has_audio| and |answer_options.has_video|.
+  FakeConstraints answer_c;
+  // Reject both audio and video.
+  answer_c.SetMandatoryReceiveAudio(false);
+  answer_c.SetMandatoryReceiveVideo(false);
+
+  std::unique_ptr<SessionDescriptionInterface> answer;
+  ASSERT_TRUE(DoCreateAnswer(&answer, &answer_c));
+  const cricket::ContentInfo* audio_content =
+      GetFirstAudioContent(answer->description());
+  const cricket::ContentInfo* video_content =
+      GetFirstVideoContent(answer->description());
+  ASSERT_NE(nullptr, audio_content);
+  ASSERT_NE(nullptr, video_content);
+  EXPECT_TRUE(audio_content->rejected);
+  EXPECT_TRUE(video_content->rejected);
+}
+
 // This test ensures OnRenegotiationNeeded is called when we add track with
 // MediaStream -> AddTrack in the same way it is called when we add track with
 // PeerConnection -> AddTrack.
@@ -3672,6 +3734,52 @@
   observer_.renegotiation_needed_ = false;
 }
 
+// Tests that creating answer would fail gracefully without being crashed if the
+// remote description is unset.
+TEST_F(PeerConnectionInterfaceTest, CreateAnswerWithoutRemoteDescription) {
+  CreatePeerConnection();
+  // Creating answer fails because the remote description is unset.
+  std::unique_ptr<SessionDescriptionInterface> answer;
+  EXPECT_FALSE(DoCreateAnswer(&answer, nullptr));
+
+  // Createing answer succeeds when the remote description is set.
+  CreateOfferAsRemoteDescription();
+  EXPECT_TRUE(DoCreateAnswer(&answer, nullptr));
+}
+
+// Test that an error is returned if a description is applied that doesn't
+// respect the order of existing media sections.
+TEST_F(PeerConnectionInterfaceTest,
+       MediaSectionOrderEnforcedForSubsequentOffers) {
+  CreatePeerConnection();
+  FakeConstraints constraints;
+  constraints.SetMandatoryReceiveAudio(true);
+  constraints.SetMandatoryReceiveVideo(true);
+  std::unique_ptr<SessionDescriptionInterface> offer;
+  ASSERT_TRUE(DoCreateOffer(&offer, &constraints));
+  EXPECT_TRUE(DoSetRemoteDescription(std::move(offer)));
+
+  std::unique_ptr<SessionDescriptionInterface> answer;
+  ASSERT_TRUE(DoCreateAnswer(&answer, nullptr));
+  EXPECT_TRUE(DoSetLocalDescription(std::move(answer)));
+
+  // A remote offer with different m=line order should be rejected.
+  ASSERT_TRUE(DoCreateOffer(&offer, &constraints));
+  std::reverse(offer->description()->contents().begin(),
+               offer->description()->contents().end());
+  std::reverse(offer->description()->transport_infos().begin(),
+               offer->description()->transport_infos().end());
+  EXPECT_FALSE(DoSetRemoteDescription(std::move(offer)));
+
+  // A subsequent local offer with different m=line order should be rejected.
+  ASSERT_TRUE(DoCreateOffer(&offer, &constraints));
+  std::reverse(offer->description()->contents().begin(),
+               offer->description()->contents().end());
+  std::reverse(offer->description()->transport_infos().begin(),
+               offer->description()->transport_infos().end());
+  EXPECT_FALSE(DoSetLocalDescription(std::move(offer)));
+}
+
 class PeerConnectionMediaConfigTest : public testing::Test {
  protected:
   void SetUp() override {
diff --git a/pc/peerconnectionwrapper.cc b/pc/peerconnectionwrapper.cc
index 9be9309..dd11460 100644
--- a/pc/peerconnectionwrapper.cc
+++ b/pc/peerconnectionwrapper.cc
@@ -30,7 +30,7 @@
     rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory,
     rtc::scoped_refptr<PeerConnectionInterface> pc,
     std::unique_ptr<MockPeerConnectionObserver> observer)
-    : pc_factory_(pc_factory), observer_(std::move(observer)), pc_(pc) {
+    : pc_factory_(pc_factory), pc_(pc), observer_(std::move(observer)) {
   RTC_DCHECK(pc_factory_);
   RTC_DCHECK(pc_);
   RTC_DCHECK(observer_);
@@ -57,25 +57,15 @@
 }
 
 std::unique_ptr<SessionDescriptionInterface> PeerConnectionWrapper::CreateOffer(
-    const PeerConnectionInterface::RTCOfferAnswerOptions& options,
-    std::string* error_out) {
-  return CreateSdp(
-      [this, options](CreateSessionDescriptionObserver* observer) {
-        pc()->CreateOffer(observer, options);
-      },
-      error_out);
+    const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
+  return CreateSdp([this, options](CreateSessionDescriptionObserver* observer) {
+    pc()->CreateOffer(observer, options);
+  });
 }
 
 std::unique_ptr<SessionDescriptionInterface>
 PeerConnectionWrapper::CreateOfferAndSetAsLocal() {
-  return CreateOfferAndSetAsLocal(
-      PeerConnectionInterface::RTCOfferAnswerOptions());
-}
-
-std::unique_ptr<SessionDescriptionInterface>
-PeerConnectionWrapper::CreateOfferAndSetAsLocal(
-    const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
-  auto offer = CreateOffer(options);
+  auto offer = CreateOffer();
   if (!offer) {
     return nullptr;
   }
@@ -90,25 +80,15 @@
 
 std::unique_ptr<SessionDescriptionInterface>
 PeerConnectionWrapper::CreateAnswer(
-    const PeerConnectionInterface::RTCOfferAnswerOptions& options,
-    std::string* error_out) {
-  return CreateSdp(
-      [this, options](CreateSessionDescriptionObserver* observer) {
-        pc()->CreateAnswer(observer, options);
-      },
-      error_out);
+    const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
+  return CreateSdp([this, options](CreateSessionDescriptionObserver* observer) {
+    pc()->CreateAnswer(observer, options);
+  });
 }
 
 std::unique_ptr<SessionDescriptionInterface>
 PeerConnectionWrapper::CreateAnswerAndSetAsLocal() {
-  return CreateAnswerAndSetAsLocal(
-      PeerConnectionInterface::RTCOfferAnswerOptions());
-}
-
-std::unique_ptr<SessionDescriptionInterface>
-PeerConnectionWrapper::CreateAnswerAndSetAsLocal(
-    const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
-  auto answer = CreateAnswer(options);
+  auto answer = CreateAnswer();
   if (!answer) {
     return nullptr;
   }
@@ -117,72 +97,73 @@
 }
 
 std::unique_ptr<SessionDescriptionInterface> PeerConnectionWrapper::CreateSdp(
-    std::function<void(CreateSessionDescriptionObserver*)> fn,
-    std::string* error_out) {
+    std::function<void(CreateSessionDescriptionObserver*)> fn) {
   rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer(
       new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>());
   fn(observer);
   EXPECT_EQ_WAIT(true, observer->called(), kWaitTimeout);
-  if (error_out && !observer->result()) {
-    *error_out = observer->error();
-  }
   return observer->MoveDescription();
 }
 
 bool PeerConnectionWrapper::SetLocalDescription(
-    std::unique_ptr<SessionDescriptionInterface> desc,
-    std::string* error_out) {
-  return SetSdp(
-      [this, &desc](SetSessionDescriptionObserver* observer) {
-        pc()->SetLocalDescription(observer, desc.release());
-      },
-      error_out);
+    std::unique_ptr<SessionDescriptionInterface> desc) {
+  return SetSdp([this, &desc](SetSessionDescriptionObserver* observer) {
+    pc()->SetLocalDescription(observer, desc.release());
+  });
 }
 
 bool PeerConnectionWrapper::SetRemoteDescription(
-    std::unique_ptr<SessionDescriptionInterface> desc,
-    std::string* error_out) {
-  return SetSdp(
-      [this, &desc](SetSessionDescriptionObserver* observer) {
-        pc()->SetRemoteDescription(observer, desc.release());
-      },
-      error_out);
+    std::unique_ptr<SessionDescriptionInterface> desc) {
+  return SetSdp([this, &desc](SetSessionDescriptionObserver* observer) {
+    pc()->SetRemoteDescription(observer, desc.release());
+  });
 }
 
 bool PeerConnectionWrapper::SetSdp(
-    std::function<void(SetSessionDescriptionObserver*)> fn,
-    std::string* error_out) {
+    std::function<void(SetSessionDescriptionObserver*)> fn) {
   rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
       new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
   fn(observer);
-  EXPECT_EQ_WAIT(true, observer->called(), kWaitTimeout);
-  if (error_out && !observer->result()) {
-    *error_out = observer->error();
+  if (pc()->signaling_state() != PeerConnectionInterface::kClosed) {
+    EXPECT_EQ_WAIT(true, observer->called(), kWaitTimeout);
   }
   return observer->result();
 }
 
-rtc::scoped_refptr<RtpSenderInterface> PeerConnectionWrapper::AddAudioTrack(
-    const std::string& track_label,
-    std::vector<MediaStreamInterface*> streams) {
-  auto media_stream_track =
-      pc_factory()->CreateAudioTrack(track_label, nullptr);
-  return pc()->AddTrack(media_stream_track, streams);
+void PeerConnectionWrapper::AddAudioStream(const std::string& stream_label,
+                                           const std::string& track_label) {
+  auto stream = pc_factory()->CreateLocalMediaStream(stream_label);
+  auto audio_track = pc_factory()->CreateAudioTrack(track_label, nullptr);
+  EXPECT_TRUE(pc()->AddTrack(audio_track, {stream}));
+  EXPECT_TRUE_WAIT(observer()->renegotiation_needed_, kWaitTimeout);
+  observer()->renegotiation_needed_ = false;
 }
 
-rtc::scoped_refptr<RtpSenderInterface> PeerConnectionWrapper::AddVideoTrack(
-    const std::string& track_label,
-    std::vector<MediaStreamInterface*> streams) {
+void PeerConnectionWrapper::AddVideoStream(const std::string& stream_label,
+                                           const std::string& track_label) {
+  auto stream = pc_factory()->CreateLocalMediaStream(stream_label);
   auto video_source = pc_factory()->CreateVideoSource(
       rtc::MakeUnique<cricket::FakeVideoCapturer>());
-  auto media_stream_track =
-      pc_factory()->CreateVideoTrack(track_label, video_source);
-  return pc()->AddTrack(media_stream_track, streams);
+  auto video_track = pc_factory()->CreateVideoTrack(track_label, video_source);
+  EXPECT_TRUE(pc()->AddTrack(video_track, {stream}));
+  EXPECT_TRUE_WAIT(observer()->renegotiation_needed_, kWaitTimeout);
+  observer()->renegotiation_needed_ = false;
 }
 
-PeerConnectionInterface::SignalingState
-PeerConnectionWrapper::signaling_state() {
-  return pc()->signaling_state();
+void PeerConnectionWrapper::AddAudioVideoStream(
+    const std::string& stream_label,
+    const std::string& audio_track_label,
+    const std::string& video_track_label) {
+  auto stream = pc_factory()->CreateLocalMediaStream(stream_label);
+  auto audio_track = pc_factory()->CreateAudioTrack(audio_track_label, nullptr);
+  EXPECT_TRUE(pc()->AddTrack(audio_track, {stream}));
+  auto video_source = pc_factory()->CreateVideoSource(
+      rtc::MakeUnique<cricket::FakeVideoCapturer>());
+  auto video_track =
+      pc_factory()->CreateVideoTrack(video_track_label, video_source);
+  EXPECT_TRUE(pc()->AddTrack(video_track, {stream}));
+  EXPECT_TRUE_WAIT(observer()->renegotiation_needed_, kWaitTimeout);
+  observer()->renegotiation_needed_ = false;
 }
 
 bool PeerConnectionWrapper::IsIceGatheringDone() {
diff --git a/pc/peerconnectionwrapper.h b/pc/peerconnectionwrapper.h
index f74fcdb..783ae38 100644
--- a/pc/peerconnectionwrapper.h
+++ b/pc/peerconnectionwrapper.h
@@ -54,69 +54,54 @@
   // resulting SessionDescription once it is available. If the method call
   // failed, null is returned.
   std::unique_ptr<SessionDescriptionInterface> CreateOffer(
-      const PeerConnectionInterface::RTCOfferAnswerOptions& options,
-      std::string* error_out = nullptr);
+      const PeerConnectionInterface::RTCOfferAnswerOptions& options);
   // Calls CreateOffer with default options.
   std::unique_ptr<SessionDescriptionInterface> CreateOffer();
   // Calls CreateOffer and sets a copy of the offer as the local description.
-  std::unique_ptr<SessionDescriptionInterface> CreateOfferAndSetAsLocal(
-      const PeerConnectionInterface::RTCOfferAnswerOptions& options);
-  // Calls CreateOfferAndSetAsLocal with default options.
   std::unique_ptr<SessionDescriptionInterface> CreateOfferAndSetAsLocal();
 
   // Calls the underlying PeerConnection's CreateAnswer method and returns the
   // resulting SessionDescription once it is available. If the method call
   // failed, null is returned.
   std::unique_ptr<SessionDescriptionInterface> CreateAnswer(
-      const PeerConnectionInterface::RTCOfferAnswerOptions& options,
-      std::string* error_out = nullptr);
+      const PeerConnectionInterface::RTCOfferAnswerOptions& options);
   // Calls CreateAnswer with the default options.
   std::unique_ptr<SessionDescriptionInterface> CreateAnswer();
   // Calls CreateAnswer and sets a copy of the offer as the local description.
-  std::unique_ptr<SessionDescriptionInterface> CreateAnswerAndSetAsLocal(
-      const PeerConnectionInterface::RTCOfferAnswerOptions& options);
-  // Calls CreateAnswerAndSetAsLocal with default options.
   std::unique_ptr<SessionDescriptionInterface> CreateAnswerAndSetAsLocal();
 
   // Calls the underlying PeerConnection's SetLocalDescription method with the
   // given session description and waits for the success/failure response.
   // Returns true if the description was successfully set.
-  bool SetLocalDescription(std::unique_ptr<SessionDescriptionInterface> desc,
-                           std::string* error_out = nullptr);
+  bool SetLocalDescription(std::unique_ptr<SessionDescriptionInterface> desc);
   // Calls the underlying PeerConnection's SetRemoteDescription method with the
   // given session description and waits for the success/failure response.
   // Returns true if the description was successfully set.
-  bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc,
-                            std::string* error_out = nullptr);
+  bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc);
 
-  // Calls the underlying PeerConnection's AddTrack method with an audio media
-  // stream track not bound to any source.
-  rtc::scoped_refptr<RtpSenderInterface> AddAudioTrack(
-      const std::string& track_label,
-      std::vector<MediaStreamInterface*> streams = {});
-
-  // Calls the underlying PeerConnection's AddTrack method with a video media
-  // stream track fed by a fake video capturer.
-  rtc::scoped_refptr<RtpSenderInterface> AddVideoTrack(
-      const std::string& track_label,
-      std::vector<MediaStreamInterface*> streams = {});
-
-  // Returns the signaling state of the underlying PeerConnection.
-  PeerConnectionInterface::SignalingState signaling_state();
+  // Adds a new stream with one audio track to the underlying PeerConnection.
+  void AddAudioStream(const std::string& stream_label,
+                      const std::string& track_label);
+  // Adds a new stream with one video track to the underlying PeerConnection.
+  void AddVideoStream(const std::string& stream_label,
+                      const std::string& track_label);
+  // Adds a new stream with one audio and one video track to the underlying
+  // PeerConnection.
+  void AddAudioVideoStream(const std::string& stream_label,
+                           const std::string& audio_track_label,
+                           const std::string& video_track_label);
 
   // Returns true if ICE has finished gathering candidates.
   bool IsIceGatheringDone();
 
  private:
   std::unique_ptr<SessionDescriptionInterface> CreateSdp(
-      std::function<void(CreateSessionDescriptionObserver*)> fn,
-      std::string* error_out);
-  bool SetSdp(std::function<void(SetSessionDescriptionObserver*)> fn,
-              std::string* error_out);
+      std::function<void(CreateSessionDescriptionObserver*)> fn);
+  bool SetSdp(std::function<void(SetSessionDescriptionObserver*)> fn);
 
   rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
-  std::unique_ptr<MockPeerConnectionObserver> observer_;
   rtc::scoped_refptr<PeerConnectionInterface> pc_;
+  std::unique_ptr<MockPeerConnectionObserver> observer_;
 };
 
 }  // namespace webrtc
diff --git a/pc/sdputils.cc b/pc/sdputils.cc
index 8932bea..9339fdb 100644
--- a/pc/sdputils.cc
+++ b/pc/sdputils.cc
@@ -20,14 +20,7 @@
 std::unique_ptr<SessionDescriptionInterface> CloneSessionDescription(
     const SessionDescriptionInterface* sdesc) {
   RTC_DCHECK(sdesc);
-  return CloneSessionDescriptionAsType(sdesc, sdesc->type());
-}
-
-std::unique_ptr<SessionDescriptionInterface> CloneSessionDescriptionAsType(
-    const SessionDescriptionInterface* sdesc,
-    const std::string& type) {
-  RTC_DCHECK(sdesc);
-  auto clone = rtc::MakeUnique<JsepSessionDescription>(type);
+  auto clone = rtc::MakeUnique<JsepSessionDescription>(sdesc->type());
   clone->Initialize(sdesc->description()->Copy(), sdesc->session_id(),
                               sdesc->session_version());
   // As of writing, our version of GCC does not allow returning a unique_ptr of
diff --git a/pc/sdputils.h b/pc/sdputils.h
index 3a53a41..7d67fd8 100644
--- a/pc/sdputils.h
+++ b/pc/sdputils.h
@@ -23,11 +23,6 @@
 std::unique_ptr<SessionDescriptionInterface> CloneSessionDescription(
     const SessionDescriptionInterface* sdesc);
 
-// Returns a copy of the given session description with the type changed.
-std::unique_ptr<SessionDescriptionInterface> CloneSessionDescriptionAsType(
-    const SessionDescriptionInterface* sdesc,
-    const std::string& type);
-
 // Function that takes a single session description content with its
 // corresponding transport and produces a boolean.
 typedef std::function<bool(const cricket::ContentInfo*,
diff --git a/pc/test/mockpeerconnectionobservers.h b/pc/test/mockpeerconnectionobservers.h
index 82098ca..9b077f5 100644
--- a/pc/test/mockpeerconnectionobservers.h
+++ b/pc/test/mockpeerconnectionobservers.h
@@ -177,27 +177,26 @@
  public:
   MockCreateSessionDescriptionObserver()
       : called_(false),
-        error_("MockCreateSessionDescriptionObserver not called") {}
+        result_(false) {}
   virtual ~MockCreateSessionDescriptionObserver() {}
   virtual void OnSuccess(SessionDescriptionInterface* desc) {
     called_ = true;
-    error_ = "";
+    result_ = true;
     desc_.reset(desc);
   }
   virtual void OnFailure(const std::string& error) {
     called_ = true;
-    error_ = error;
+    result_ = false;
   }
   bool called() const { return called_; }
-  bool result() const { return error_.empty(); }
-  const std::string& error() const { return error_; }
+  bool result() const { return result_; }
   std::unique_ptr<SessionDescriptionInterface> MoveDescription() {
     return std::move(desc_);
   }
 
  private:
   bool called_;
-  std::string error_;
+  bool result_;
   std::unique_ptr<SessionDescriptionInterface> desc_;
 };
 
@@ -206,23 +205,22 @@
  public:
   MockSetSessionDescriptionObserver()
       : called_(false),
-        error_("MockSetSessionDescriptionObserver not called") {}
+        result_(false) {}
   virtual ~MockSetSessionDescriptionObserver() {}
   virtual void OnSuccess() {
     called_ = true;
-    error_ = "";
+    result_ = true;
   }
   virtual void OnFailure(const std::string& error) {
     called_ = true;
-    error_ = error;
+    result_ = false;
   }
   bool called() const { return called_; }
-  bool result() const { return error_.empty(); }
-  const std::string& error() const { return error_; }
+  bool result() const { return result_; }
 
  private:
   bool called_;
-  std::string error_;
+  bool result_;
 };
 
 class MockDataChannelObserver : public webrtc::DataChannelObserver {
diff --git a/pc/webrtcsession.cc b/pc/webrtcsession.cc
index 2e0ae50..f556204 100644
--- a/pc/webrtcsession.cc
+++ b/pc/webrtcsession.cc
@@ -337,7 +337,7 @@
   if (!type.empty()) {
     desc << " " << type;
   }
-  desc << " SDP: " << reason;
+  desc << " sdp: " << reason;
 
   if (err_desc) {
     *err_desc = desc.str();
@@ -707,13 +707,15 @@
   webrtc_session_desc_factory_->CreateAnswer(observer, session_options);
 }
 
-bool WebRtcSession::SetLocalDescription(
-    std::unique_ptr<SessionDescriptionInterface> desc,
-    std::string* err_desc) {
+bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc,
+                                        std::string* err_desc) {
   RTC_DCHECK(signaling_thread()->IsCurrent());
 
+  // Takes the ownership of |desc| regardless of the result.
+  std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
+
   // Validate SDP.
-  if (!ValidateSessionDescription(desc.get(), cricket::CS_LOCAL, err_desc)) {
+  if (!ValidateSessionDescription(desc, cricket::CS_LOCAL, err_desc)) {
     return false;
   }
 
@@ -725,19 +727,18 @@
   }
 
   if (action == kAnswer) {
-    current_local_description_ = std::move(desc);
-    pending_local_description_ = nullptr;
-    current_remote_description_ = std::move(pending_remote_description_);
+    current_local_description_.reset(desc_temp.release());
+    pending_local_description_.reset(nullptr);
+    current_remote_description_.reset(pending_remote_description_.release());
   } else {
-    pending_local_description_ = std::move(desc);
+    pending_local_description_.reset(desc_temp.release());
   }
 
   // Transport and Media channels will be created only when offer is set.
   if (action == kOffer && !CreateChannels(local_description()->description())) {
     // TODO(mallinath) - Handle CreateChannel failure, as new local description
     // is applied. Restore back to old description.
-    return BadLocalSdp(local_description()->type(), kCreateChannelFailed,
-                       err_desc);
+    return BadLocalSdp(desc->type(), kCreateChannelFailed, err_desc);
   }
 
   // Remove unused channels if MediaContentDescription is rejected.
@@ -753,54 +754,50 @@
 
   pending_ice_restarts_.clear();
   if (error() != ERROR_NONE) {
-    return BadLocalSdp(local_description()->type(), GetSessionErrorMsg(),
-                       err_desc);
+    return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc);
   }
   return true;
 }
 
-bool WebRtcSession::SetRemoteDescription(
-    std::unique_ptr<SessionDescriptionInterface> desc,
-    std::string* err_desc) {
+bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc,
+                                         std::string* err_desc) {
   RTC_DCHECK(signaling_thread()->IsCurrent());
 
+  // Takes the ownership of |desc| regardless of the result.
+  std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
+
   // Validate SDP.
-  if (!ValidateSessionDescription(desc.get(), cricket::CS_REMOTE, err_desc)) {
+  if (!ValidateSessionDescription(desc, cricket::CS_REMOTE, err_desc)) {
     return false;
   }
 
-  // Hold this pointer so candidates can be copied to it later in the method.
-  SessionDescriptionInterface* desc_ptr = desc.get();
-
   const SessionDescriptionInterface* old_remote_description =
       remote_description();
   // Grab ownership of the description being replaced for the remainder of this
-  // method, since it's used below as |old_remote_description|.
+  // method, since it's used below.
   std::unique_ptr<SessionDescriptionInterface> replaced_remote_description;
   Action action = GetAction(desc->type());
   if (action == kAnswer) {
-    replaced_remote_description = pending_remote_description_
-                                      ? std::move(pending_remote_description_)
-                                      : std::move(current_remote_description_);
-    current_remote_description_ = std::move(desc);
-    pending_remote_description_ = nullptr;
-    current_local_description_ = std::move(pending_local_description_);
+    replaced_remote_description.reset(
+        pending_remote_description_ ? pending_remote_description_.release()
+                                    : current_remote_description_.release());
+    current_remote_description_.reset(desc_temp.release());
+    pending_remote_description_.reset(nullptr);
+    current_local_description_.reset(pending_local_description_.release());
   } else {
-    replaced_remote_description = std::move(pending_remote_description_);
-    pending_remote_description_ = std::move(desc);
+    replaced_remote_description.reset(pending_remote_description_.release());
+    pending_remote_description_.reset(desc_temp.release());
   }
 
   // Transport and Media channels will be created only when offer is set.
-  if (action == kOffer &&
-      !CreateChannels(remote_description()->description())) {
+  if (action == kOffer && !CreateChannels(desc->description())) {
     // TODO(mallinath) - Handle CreateChannel failure, as new local description
     // is applied. Restore back to old description.
-    return BadRemoteSdp(remote_description()->type(), kCreateChannelFailed,
-                        err_desc);
+    return BadRemoteSdp(desc->type(), kCreateChannelFailed, err_desc);
   }
 
   // Remove unused channels if MediaContentDescription is rejected.
-  RemoveUnusedChannels(remote_description()->description());
+  RemoveUnusedChannels(desc->description());
 
   // NOTE: Candidates allocation will be initiated only when SetLocalDescription
   // is called.
@@ -808,10 +805,8 @@
     return false;
   }
 
-  if (local_description() &&
-      !UseCandidatesInSessionDescription(remote_description())) {
-    return BadRemoteSdp(remote_description()->type(), kInvalidCandidates,
-                        err_desc);
+  if (local_description() && !UseCandidatesInSessionDescription(desc)) {
+    return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc);
   }
 
   if (old_remote_description) {
@@ -822,7 +817,7 @@
       // TODO(deadbeef): When we start storing both the current and pending
       // remote description, this should reset pending_ice_restarts and compare
       // against the current description.
-      if (CheckForRemoteIceRestart(old_remote_description, remote_description(),
+      if (CheckForRemoteIceRestart(old_remote_description, desc,
                                    content.name)) {
         if (action == kOffer) {
           pending_ice_restarts_.insert(content.name);
@@ -836,14 +831,13 @@
         // description plus any candidates added since then. We should remove
         // this once we're sure it won't break anything.
         WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
-            old_remote_description, content.name, desc_ptr);
+            old_remote_description, content.name, desc);
       }
     }
   }
 
   if (error() != ERROR_NONE) {
-    return BadRemoteSdp(remote_description()->type(), GetSessionErrorMsg(),
-                        err_desc);
+    return BadRemoteSdp(desc->type(), GetSessionErrorMsg(), err_desc);
   }
 
   // Set the the ICE connection state to connecting since the connection may
@@ -854,7 +848,7 @@
   // transport and expose a new checking() member from transport that can be
   // read to determine the current checking state. The existing SignalConnecting
   // actually means "gathering candidates", so cannot be be used here.
-  if (remote_description()->type() != SessionDescriptionInterface::kOffer &&
+  if (desc->type() != SessionDescriptionInterface::kOffer &&
       ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew) {
     SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
   }
diff --git a/pc/webrtcsession.h b/pc/webrtcsession.h
index 185fa05..16c3931 100644
--- a/pc/webrtcsession.h
+++ b/pc/webrtcsession.h
@@ -254,9 +254,11 @@
       const cricket::MediaSessionOptions& session_options);
   void CreateAnswer(CreateSessionDescriptionObserver* observer,
                     const cricket::MediaSessionOptions& session_options);
-  bool SetLocalDescription(std::unique_ptr<SessionDescriptionInterface> desc,
+  // The ownership of |desc| will be transferred after this call.
+  bool SetLocalDescription(SessionDescriptionInterface* desc,
                            std::string* err_desc);
-  bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc,
+  // The ownership of |desc| will be transferred after this call.
+  bool SetRemoteDescription(SessionDescriptionInterface* desc,
                             std::string* err_desc);
 
   bool ProcessIceMessage(const IceCandidateInterface* ice_candidate);
diff --git a/pc/webrtcsession_unittest.cc b/pc/webrtcsession_unittest.cc
index 0c54abc..25cb35a 100644
--- a/pc/webrtcsession_unittest.cc
+++ b/pc/webrtcsession_unittest.cc
@@ -92,6 +92,26 @@
 static const int kDefaultTimeout = 10000;  // 10 seconds.
 static const int kIceCandidatesTimeout = 10000;
 
+static const char kSdpWithRtx[] =
+    "v=0\r\n"
+    "o=- 4104004319237231850 2 IN IP4 127.0.0.1\r\n"
+    "s=-\r\n"
+    "t=0 0\r\n"
+    "a=msid-semantic: WMS stream1\r\n"
+    "m=video 9 RTP/SAVPF 0 96\r\n"
+    "c=IN IP4 0.0.0.0\r\n"
+    "a=rtcp:9 IN IP4 0.0.0.0\r\n"
+    "a=ice-ufrag:CerjGp19G7wpXwl7\r\n"
+    "a=ice-pwd:cMvOlFvQ6ochez1ZOoC2uBEC\r\n"
+    "a=mid:video\r\n"
+    "a=sendrecv\r\n"
+    "a=rtcp-mux\r\n"
+    "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
+    "inline:5/4N5CDvMiyDArHtBByUM71VIkguH17ZNoX60GrA\r\n"
+    "a=rtpmap:0 fake_video_codec/90000\r\n"
+    "a=rtpmap:96 rtx/90000\r\n"
+    "a=fmtp:96 apt=0\r\n";
+
 static const char kStream1[] = "stream1";
 static const char kVideoTrack1[] = "video1";
 static const char kAudioTrack1[] = "audio1";
@@ -100,6 +120,7 @@
 static const char kVideoTrack2[] = "video2";
 static const char kAudioTrack2[] = "audio2";
 
+static constexpr bool kStopped = true;
 static constexpr bool kActive = false;
 
 enum RTCCertificateGenerationMethod { ALREADY_GENERATED, DTLS_IDENTITY_STORE };
@@ -444,6 +465,24 @@
     remote_send_video_ = true;
   }
 
+  void SendAudioVideoStream1And2() {
+    send_stream_1_ = true;
+    send_stream_2_ = true;
+    local_send_audio_ = true;
+    local_send_video_ = true;
+    remote_send_audio_ = true;
+    remote_send_video_ = true;
+  }
+
+  void SendNothing() {
+    send_stream_1_ = false;
+    send_stream_2_ = false;
+    local_send_audio_ = false;
+    local_send_video_ = false;
+    remote_send_audio_ = false;
+    remote_send_video_ = false;
+  }
+
   void SendAudioOnlyStream2() {
     send_stream_1_ = false;
     send_stream_2_ = true;
@@ -462,6 +501,19 @@
     remote_send_video_ = true;
   }
 
+  // Helper function used to add a specific media section to the
+  // |session_options|.
+  void AddMediaSection(cricket::MediaType type,
+                       const std::string& mid,
+                       cricket::MediaContentDirection direction,
+                       bool stopped,
+                       cricket::MediaSessionOptions* opts) {
+    opts->media_description_options.push_back(cricket::MediaDescriptionOptions(
+        type, mid,
+        cricket::RtpTransceiverDirection::FromMediaContentDirection(direction),
+        stopped));
+  }
+
   // Add the media sections to the options from |offered_media_sections_| when
   // creating an answer or a new offer.
   // This duplicates a lot of logic from PeerConnection but this can be fixed
@@ -636,6 +688,13 @@
     session_options->crypto_options = crypto_options_;
   }
 
+  void GetOptionsForAudioOnlyRemoteOffer(
+      cricket::MediaSessionOptions* session_options) {
+    remote_recv_audio_ = true;
+    remote_recv_video_ = false;
+    GetOptionsForRemoteOffer(session_options);
+  }
+
   void GetOptionsForRemoteOffer(cricket::MediaSessionOptions* session_options) {
     AddMediaSectionsAndSendersToOptions(session_options, remote_send_audio_,
                                         remote_recv_audio_, remote_send_video_,
@@ -752,15 +811,30 @@
     transport_desc->ice_pwd = pwd;
   }
 
+  // Creates a remote offer and and applies it as a remote description,
+  // creates a local answer and applies is as a local description.
+  // Call SendAudioVideoStreamX() before this function
+  // to decide which local and remote streams to create.
+  void CreateAndSetRemoteOfferAndLocalAnswer() {
+    SessionDescriptionInterface* offer = CreateRemoteOffer();
+    SetRemoteDescriptionWithoutError(offer);
+    SessionDescriptionInterface* answer = CreateAnswer();
+    SetLocalDescriptionWithoutError(answer);
+  }
   void SetLocalDescriptionWithoutError(SessionDescriptionInterface* desc) {
-    ASSERT_TRUE(session_->SetLocalDescription(rtc::WrapUnique(desc), nullptr));
+    ASSERT_TRUE(session_->SetLocalDescription(desc, nullptr));
     session_->MaybeStartGathering();
   }
+  void SetLocalDescriptionExpectState(SessionDescriptionInterface* desc,
+                                      WebRtcSession::State expected_state) {
+    SetLocalDescriptionWithoutError(desc);
+    EXPECT_EQ(expected_state, session_->state());
+  }
   void SetLocalDescriptionExpectError(const std::string& action,
                                       const std::string& expected_error,
                                       SessionDescriptionInterface* desc) {
     std::string error;
-    EXPECT_FALSE(session_->SetLocalDescription(rtc::WrapUnique(desc), &error));
+    EXPECT_FALSE(session_->SetLocalDescription(desc, &error));
     std::string sdp_type = "local ";
     sdp_type.append(action);
     EXPECT_NE(std::string::npos, error.find(sdp_type));
@@ -771,14 +845,24 @@
     SetLocalDescriptionExpectError(SessionDescriptionInterface::kOffer,
                                    expected_error, desc);
   }
+  void SetLocalDescriptionAnswerExpectError(const std::string& expected_error,
+                                            SessionDescriptionInterface* desc) {
+    SetLocalDescriptionExpectError(SessionDescriptionInterface::kAnswer,
+                                   expected_error, desc);
+  }
   void SetRemoteDescriptionWithoutError(SessionDescriptionInterface* desc) {
-    ASSERT_TRUE(session_->SetRemoteDescription(rtc::WrapUnique(desc), nullptr));
+    ASSERT_TRUE(session_->SetRemoteDescription(desc, nullptr));
+  }
+  void SetRemoteDescriptionExpectState(SessionDescriptionInterface* desc,
+                                       WebRtcSession::State expected_state) {
+    SetRemoteDescriptionWithoutError(desc);
+    EXPECT_EQ(expected_state, session_->state());
   }
   void SetRemoteDescriptionExpectError(const std::string& action,
                                        const std::string& expected_error,
                                        SessionDescriptionInterface* desc) {
     std::string error;
-    EXPECT_FALSE(session_->SetRemoteDescription(rtc::WrapUnique(desc), &error));
+    EXPECT_FALSE(session_->SetRemoteDescription(desc, &error));
     std::string sdp_type = "remote ";
     sdp_type.append(action);
     EXPECT_NE(std::string::npos, error.find(sdp_type));
@@ -789,6 +873,11 @@
     SetRemoteDescriptionExpectError(SessionDescriptionInterface::kOffer,
                                     expected_error, desc);
   }
+  void SetRemoteDescriptionAnswerExpectError(
+      const std::string& expected_error, SessionDescriptionInterface* desc) {
+    SetRemoteDescriptionExpectError(SessionDescriptionInterface::kAnswer,
+                                    expected_error, desc);
+  }
 
   JsepSessionDescription* CreateRemoteOfferWithVersion(
         cricket::MediaSessionOptions options,
@@ -946,6 +1035,23 @@
     }
   }
 
+  bool ContainsVideoCodecWithName(const SessionDescriptionInterface* desc,
+                                  const std::string& codec_name) {
+    for (const auto& content : desc->description()->contents()) {
+      if (static_cast<cricket::MediaContentDescription*>(content.description)
+              ->type() == cricket::MEDIA_TYPE_VIDEO) {
+        const auto* mdesc =
+            static_cast<cricket::VideoContentDescription*>(content.description);
+        for (const auto& codec : mdesc->codecs()) {
+          if (codec.name == codec_name) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
   // 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.
@@ -1009,6 +1115,33 @@
     EXPECT_GT(fake_call_.last_sent_packet().send_time_ms, -1);
   }
 
+  // Adds CN codecs to FakeMediaEngine and MediaDescriptionFactory.
+  void AddCNCodecs() {
+    const cricket::AudioCodec kCNCodec1(102, "CN", 8000, 0, 1);
+    const cricket::AudioCodec kCNCodec2(103, "CN", 16000, 0, 1);
+
+    // Add kCNCodec for dtmf test.
+    std::vector<cricket::AudioCodec> codecs =
+        media_engine_->audio_send_codecs();
+    codecs.push_back(kCNCodec1);
+    codecs.push_back(kCNCodec2);
+    media_engine_->SetAudioCodecs(codecs);
+    desc_factory_->set_audio_codecs(codecs, codecs);
+  }
+
+  bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
+    const cricket::ContentDescription* description = content->description;
+    RTC_CHECK(description != NULL);
+    const cricket::AudioContentDescription* audio_content_desc =
+        static_cast<const cricket::AudioContentDescription*>(description);
+    RTC_CHECK(audio_content_desc != NULL);
+    for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
+      if (audio_content_desc->codecs()[i].name == "CN")
+        return false;
+    }
+    return true;
+  }
+
   void CreateDataChannel() {
     webrtc::InternalDataChannelInit dci;
     RTC_CHECK(session_.get());
@@ -1081,6 +1214,141 @@
   TestSessionCandidatesWithBundleRtcpMux(true, true);
 }
 
+TEST_F(WebRtcSessionTest, SetSdpFailedOnInvalidSdp) {
+  Init();
+  SessionDescriptionInterface* offer = NULL;
+  // Since |offer| is NULL, there's no way to tell if it's an offer or answer.
+  std::string unknown_action;
+  SetLocalDescriptionExpectError(unknown_action, kInvalidSdp, offer);
+  SetRemoteDescriptionExpectError(unknown_action, kInvalidSdp, offer);
+}
+
+// Test creating offers and receive answers and make sure the
+// media engine creates the expected send and receive streams.
+TEST_F(WebRtcSessionTest, TestCreateSdesOfferReceiveSdesAnswer) {
+  Init();
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* offer = CreateOffer();
+  const std::string session_id_orig = offer->session_id();
+  const std::string session_version_orig = offer->session_version();
+  SetLocalDescriptionWithoutError(offer);
+
+  SendAudioVideoStream2();
+  SessionDescriptionInterface* answer =
+      CreateRemoteAnswer(session_->local_description());
+  SetRemoteDescriptionWithoutError(answer);
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  ASSERT_EQ(1u, video_channel_->recv_streams().size());
+  EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id);
+
+  ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+  EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id);
+
+  ASSERT_EQ(1u, video_channel_->send_streams().size());
+  EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id);
+  ASSERT_EQ(1u, voice_channel_->send_streams().size());
+  EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id);
+
+  // Create new offer without send streams.
+  SendNothing();
+  offer = CreateOffer();
+
+  // Verify the session id is the same and the session version is
+  // increased.
+  EXPECT_EQ(session_id_orig, offer->session_id());
+  EXPECT_LT(rtc::FromString<uint64_t>(session_version_orig),
+            rtc::FromString<uint64_t>(offer->session_version()));
+
+  SetLocalDescriptionWithoutError(offer);
+  EXPECT_EQ(0u, video_channel_->send_streams().size());
+  EXPECT_EQ(0u, voice_channel_->send_streams().size());
+
+  SendAudioVideoStream2();
+  answer = CreateRemoteAnswer(session_->local_description());
+  SetRemoteDescriptionWithoutError(answer);
+
+  // Make sure the receive streams have not changed.
+  ASSERT_EQ(1u, video_channel_->recv_streams().size());
+  EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id);
+  ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+  EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id);
+}
+
+// Test receiving offers and creating answers and make sure the
+// media engine creates the expected send and receive streams.
+TEST_F(WebRtcSessionTest, TestReceiveSdesOfferCreateSdesAnswer) {
+  Init();
+  SendAudioVideoStream2();
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetRemoteDescriptionWithoutError(offer);
+
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* answer = CreateAnswer();
+  SetLocalDescriptionWithoutError(answer);
+
+  const std::string session_id_orig = answer->session_id();
+  const std::string session_version_orig = answer->session_version();
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  ASSERT_TRUE(video_channel_);
+  ASSERT_TRUE(voice_channel_);
+  ASSERT_EQ(1u, video_channel_->recv_streams().size());
+  EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[0].id);
+
+  ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+  EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[0].id);
+
+  ASSERT_EQ(1u, video_channel_->send_streams().size());
+  EXPECT_TRUE(kVideoTrack1 == video_channel_->send_streams()[0].id);
+  ASSERT_EQ(1u, voice_channel_->send_streams().size());
+  EXPECT_TRUE(kAudioTrack1 == voice_channel_->send_streams()[0].id);
+
+  SendAudioVideoStream1And2();
+  offer = CreateOffer();
+  SetRemoteDescriptionWithoutError(offer);
+
+  // Answer by turning off all send streams.
+  SendNothing();
+  answer = CreateAnswer();
+
+  // Verify the session id is the same and the session version is
+  // increased.
+  EXPECT_EQ(session_id_orig, answer->session_id());
+  EXPECT_LT(rtc::FromString<uint64_t>(session_version_orig),
+            rtc::FromString<uint64_t>(answer->session_version()));
+  SetLocalDescriptionWithoutError(answer);
+
+  ASSERT_EQ(2u, video_channel_->recv_streams().size());
+  EXPECT_TRUE(kVideoTrack1 == video_channel_->recv_streams()[0].id);
+  EXPECT_TRUE(kVideoTrack2 == video_channel_->recv_streams()[1].id);
+  ASSERT_EQ(2u, voice_channel_->recv_streams().size());
+  EXPECT_TRUE(kAudioTrack1 == voice_channel_->recv_streams()[0].id);
+  EXPECT_TRUE(kAudioTrack2 == voice_channel_->recv_streams()[1].id);
+
+  // Make sure we have no send streams.
+  EXPECT_EQ(0u, video_channel_->send_streams().size());
+  EXPECT_EQ(0u, voice_channel_->send_streams().size());
+}
+
+TEST_F(WebRtcSessionTest, SetLocalSdpFailedOnCreateChannel) {
+  Init();
+  media_engine_->set_fail_create_channel(true);
+
+  SessionDescriptionInterface* offer = CreateOffer();
+  ASSERT_TRUE(offer != NULL);
+  // SetRemoteDescription and SetLocalDescription will take the ownership of
+  // the offer.
+  SetRemoteDescriptionOfferExpectError(kCreateChannelFailed, offer);
+  offer = CreateOffer();
+  ASSERT_TRUE(offer != NULL);
+  SetLocalDescriptionOfferExpectError(kCreateChannelFailed, offer);
+}
+
 // 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
@@ -1144,6 +1412,592 @@
   SetLocalDescriptionWithoutError(answer);
 }
 
+TEST_F(WebRtcSessionTest, TestSetLocalOfferTwice) {
+  Init();
+  SendNothing();
+  // SetLocalDescription take ownership of offer.
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetLocalDescriptionWithoutError(offer);
+
+  // SetLocalDescription take ownership of offer.
+  SessionDescriptionInterface* offer2 = CreateOffer();
+  SetLocalDescriptionWithoutError(offer2);
+}
+
+TEST_F(WebRtcSessionTest, TestSetRemoteOfferTwice) {
+  Init();
+  SendNothing();
+  // SetLocalDescription take ownership of offer.
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetRemoteDescriptionWithoutError(offer);
+
+  SessionDescriptionInterface* offer2 = CreateOffer();
+  SetRemoteDescriptionWithoutError(offer2);
+}
+
+TEST_F(WebRtcSessionTest, TestSetLocalAndRemoteOffer) {
+  Init();
+  SendNothing();
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetLocalDescriptionWithoutError(offer);
+  offer = CreateOffer();
+  SetRemoteDescriptionOfferExpectError("Called in wrong state: STATE_SENTOFFER",
+                                       offer);
+}
+
+TEST_F(WebRtcSessionTest, TestSetRemoteAndLocalOffer) {
+  Init();
+  SendNothing();
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetRemoteDescriptionWithoutError(offer);
+  offer = CreateOffer();
+  SetLocalDescriptionOfferExpectError(
+      "Called in wrong state: STATE_RECEIVEDOFFER", offer);
+}
+
+TEST_F(WebRtcSessionTest, TestSetLocalPrAnswer) {
+  Init();
+  SendNothing();
+  SessionDescriptionInterface* offer = CreateRemoteOffer();
+  SetRemoteDescriptionExpectState(offer, WebRtcSession::STATE_RECEIVEDOFFER);
+
+  JsepSessionDescription* pranswer =
+      static_cast<JsepSessionDescription*>(CreateAnswer());
+  pranswer->set_type(SessionDescriptionInterface::kPrAnswer);
+  SetLocalDescriptionExpectState(pranswer, WebRtcSession::STATE_SENTPRANSWER);
+
+  SendAudioVideoStream1();
+  JsepSessionDescription* pranswer2 =
+      static_cast<JsepSessionDescription*>(CreateAnswer());
+  pranswer2->set_type(SessionDescriptionInterface::kPrAnswer);
+
+  SetLocalDescriptionExpectState(pranswer2, WebRtcSession::STATE_SENTPRANSWER);
+
+  SendAudioVideoStream2();
+  SessionDescriptionInterface* answer = CreateAnswer();
+  SetLocalDescriptionExpectState(answer, WebRtcSession::STATE_INPROGRESS);
+}
+
+TEST_F(WebRtcSessionTest, TestSetRemotePrAnswer) {
+  Init();
+  SendNothing();
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetLocalDescriptionExpectState(offer, WebRtcSession::STATE_SENTOFFER);
+
+  JsepSessionDescription* pranswer =
+      CreateRemoteAnswer(session_->local_description());
+  pranswer->set_type(SessionDescriptionInterface::kPrAnswer);
+
+  SetRemoteDescriptionExpectState(pranswer,
+                                  WebRtcSession::STATE_RECEIVEDPRANSWER);
+
+  SendAudioVideoStream1();
+  JsepSessionDescription* pranswer2 =
+      CreateRemoteAnswer(session_->local_description());
+  pranswer2->set_type(SessionDescriptionInterface::kPrAnswer);
+
+  SetRemoteDescriptionExpectState(pranswer2,
+                                  WebRtcSession::STATE_RECEIVEDPRANSWER);
+
+  SendAudioVideoStream2();
+  SessionDescriptionInterface* answer =
+      CreateRemoteAnswer(session_->local_description());
+  SetRemoteDescriptionExpectState(answer, WebRtcSession::STATE_INPROGRESS);
+}
+
+TEST_F(WebRtcSessionTest, TestSetLocalAnswerWithoutOffer) {
+  Init();
+  SendNothing();
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer());
+
+  SessionDescriptionInterface* answer =
+      CreateRemoteAnswer(offer.get());
+  SetLocalDescriptionAnswerExpectError("Called in wrong state: STATE_INIT",
+                                       answer);
+}
+
+TEST_F(WebRtcSessionTest, TestSetRemoteAnswerWithoutOffer) {
+  Init();
+  SendNothing();
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer());
+
+  SessionDescriptionInterface* answer =
+      CreateRemoteAnswer(offer.get());
+  SetRemoteDescriptionAnswerExpectError(
+      "Called in wrong state: STATE_INIT", answer);
+}
+
+// Verifies TransportProxy and media channels are created with content names
+// present in the SessionDescription.
+TEST_F(WebRtcSessionTest, TestChannelCreationsWithContentNames) {
+  Init();
+  SendAudioVideoStream1();
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer());
+
+  // CreateOffer creates session description with the content names "audio" and
+  // "video". Goal is to modify these content names and verify transport
+  // channels
+  // in the WebRtcSession, as channels are created with the content names
+  // present in SDP.
+  std::string sdp;
+  EXPECT_TRUE(offer->ToString(&sdp));
+
+  SessionDescriptionInterface* modified_offer =
+      CreateSessionDescription(JsepSessionDescription::kOffer, sdp, NULL);
+
+  SetRemoteDescriptionWithoutError(modified_offer);
+
+  cricket::MediaSessionOptions answer_options;
+  answer_options.bundle_enabled = false;
+  SessionDescriptionInterface* answer = CreateAnswer(answer_options);
+  SetLocalDescriptionWithoutError(answer);
+
+  rtc::PacketTransportInternal* voice_transport_channel =
+      session_->voice_rtp_transport_channel();
+  EXPECT_TRUE(voice_transport_channel != NULL);
+  EXPECT_EQ(voice_transport_channel->debug_name(),
+            "audio " + std::to_string(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  rtc::PacketTransportInternal* video_transport_channel =
+      session_->video_rtp_transport_channel();
+  ASSERT_TRUE(video_transport_channel != NULL);
+  EXPECT_EQ(video_transport_channel->debug_name(),
+            "video " + std::to_string(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  EXPECT_TRUE((video_channel_ = media_engine_->GetVideoChannel(0)) != NULL);
+  EXPECT_TRUE((voice_channel_ = media_engine_->GetVoiceChannel(0)) != NULL);
+}
+
+// Test that an offer contains the correct media content descriptions based on
+// the send streams when no constraints have been set.
+TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraintsOrStreams) {
+  Init();
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer());
+
+  ASSERT_TRUE(offer != NULL);
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(offer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_EQ(
+      cricket::MD_RECVONLY,
+      static_cast<const cricket::AudioContentDescription*>(content->description)
+          ->direction());
+  content = cricket::GetFirstVideoContent(offer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_EQ(
+      cricket::MD_RECVONLY,
+      static_cast<const cricket::VideoContentDescription*>(content->description)
+          ->direction());
+}
+
+// Test that an offer contains the correct media content descriptions based on
+// the send streams when no constraints have been set.
+TEST_F(WebRtcSessionTest, CreateOfferWithoutConstraints) {
+  Init();
+  // Test Audio only offer.
+  SendAudioOnlyStream2();
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer());
+
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(offer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_EQ(
+      cricket::MD_SENDRECV,
+      static_cast<const cricket::AudioContentDescription*>(content->description)
+          ->direction());
+  content = cricket::GetFirstVideoContent(offer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_EQ(
+      cricket::MD_RECVONLY,
+      static_cast<const cricket::VideoContentDescription*>(content->description)
+          ->direction());
+
+  // Test Audio / Video offer.
+  SendAudioVideoStream1();
+  offer.reset(CreateOffer());
+  content = cricket::GetFirstAudioContent(offer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_EQ(
+      cricket::MD_SENDRECV,
+      static_cast<const cricket::AudioContentDescription*>(content->description)
+          ->direction());
+
+  content = cricket::GetFirstVideoContent(offer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_EQ(
+      cricket::MD_SENDRECV,
+      static_cast<const cricket::VideoContentDescription*>(content->description)
+          ->direction());
+}
+
+// Test that an offer contains no media content descriptions if
+// kOfferToReceiveVideo and kOfferToReceiveAudio constraints are set to false.
+TEST_F(WebRtcSessionTest, CreateOfferWithConstraintsWithoutStreams) {
+  Init();
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_audio = 0;
+  options.offer_to_receive_video = 0;
+
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer(options));
+
+  ASSERT_TRUE(offer != NULL);
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(offer->description());
+  EXPECT_TRUE(content == NULL);
+  content = cricket::GetFirstVideoContent(offer->description());
+  EXPECT_TRUE(content == NULL);
+}
+
+// Test that an offer contains only audio media content descriptions if
+// kOfferToReceiveAudio constraints are set to true.
+TEST_F(WebRtcSessionTest, CreateAudioOnlyOfferWithConstraints) {
+  Init();
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_audio =
+      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
+  options.offer_to_receive_video = 0;
+
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer(options));
+
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(offer->description());
+  EXPECT_TRUE(content != NULL);
+  content = cricket::GetFirstVideoContent(offer->description());
+  EXPECT_TRUE(content == NULL);
+}
+
+// Test that an offer contains audio and video media content descriptions if
+// kOfferToReceiveAudio and kOfferToReceiveVideo constraints are set to true.
+TEST_F(WebRtcSessionTest, CreateOfferWithConstraints) {
+  Init();
+  // Test Audio / Video offer.
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_audio =
+      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
+  options.offer_to_receive_video =
+      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
+
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer(options));
+
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(offer->description());
+  EXPECT_TRUE(content != NULL);
+
+  content = cricket::GetFirstVideoContent(offer->description());
+  EXPECT_TRUE(content != NULL);
+
+  // Sets constraints to false and verifies that audio/video contents are
+  // removed.
+  options.offer_to_receive_audio = 0;
+  options.offer_to_receive_video = 0;
+  // Remove the media sections added in previous offer.
+  offered_media_sections_.clear();
+  offer.reset(CreateOffer(options));
+
+  content = cricket::GetFirstAudioContent(offer->description());
+  EXPECT_TRUE(content == NULL);
+  content = cricket::GetFirstVideoContent(offer->description());
+  EXPECT_TRUE(content == NULL);
+}
+
+// Test that an answer can not be created if the last remote description is not
+// an offer.
+TEST_F(WebRtcSessionTest, CreateAnswerWithoutAnOffer) {
+  Init();
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetLocalDescriptionWithoutError(offer);
+  SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
+  SetRemoteDescriptionWithoutError(answer);
+  EXPECT_TRUE(CreateAnswer() == NULL);
+}
+
+// Test that an answer contains the correct media content descriptions when no
+// constraints have been set.
+TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraintsOrStreams) {
+  Init();
+  // Create a remote offer with audio and video content.
+  std::unique_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
+  SetRemoteDescriptionWithoutError(offer.release());
+  std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer());
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_FALSE(content->rejected);
+
+  content = cricket::GetFirstVideoContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_FALSE(content->rejected);
+}
+
+// Test that an answer contains the correct media content descriptions when no
+// constraints have been set and the offer only contain audio.
+TEST_F(WebRtcSessionTest, CreateAudioAnswerWithoutConstraintsOrStreams) {
+  Init();
+  // Create a remote offer with audio only.
+  cricket::MediaSessionOptions options;
+  GetOptionsForAudioOnlyRemoteOffer(&options);
+
+  std::unique_ptr<JsepSessionDescription> offer(CreateRemoteOffer(options));
+  ASSERT_TRUE(cricket::GetFirstVideoContent(offer->description()) == NULL);
+  ASSERT_TRUE(cricket::GetFirstAudioContent(offer->description()) != NULL);
+
+  SetRemoteDescriptionWithoutError(offer.release());
+  std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer());
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_FALSE(content->rejected);
+
+  EXPECT_TRUE(cricket::GetFirstVideoContent(answer->description()) == NULL);
+}
+
+// Test that an answer contains the correct media content descriptions when no
+// constraints have been set.
+TEST_F(WebRtcSessionTest, CreateAnswerWithoutConstraints) {
+  Init();
+  // Create a remote offer with audio and video content.
+  std::unique_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
+  SetRemoteDescriptionWithoutError(offer.release());
+  // Test with a stream with tracks.
+  SendAudioVideoStream1();
+  std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer());
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_FALSE(content->rejected);
+
+  content = cricket::GetFirstVideoContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_FALSE(content->rejected);
+}
+
+// Test that an answer contains the correct media content descriptions when
+// constraints have been set but no stream is sent.
+TEST_F(WebRtcSessionTest, CreateAnswerWithConstraintsWithoutStreams) {
+  Init();
+  // Create a remote offer with audio and video content.
+  std::unique_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
+  SetRemoteDescriptionWithoutError(offer.release());
+
+  cricket::MediaSessionOptions session_options;
+  remote_send_audio_ = false;
+  remote_send_video_ = false;
+  local_recv_audio_ = false;
+  local_recv_video_ = false;
+  std::unique_ptr<SessionDescriptionInterface> answer(
+      CreateAnswer(session_options));
+
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_TRUE(content->rejected);
+
+  content = cricket::GetFirstVideoContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_TRUE(content->rejected);
+}
+
+// Test that an answer contains the correct media content descriptions when
+// constraints have been set and streams are sent.
+TEST_F(WebRtcSessionTest, CreateAnswerWithConstraints) {
+  Init();
+  // Create a remote offer with audio and video content.
+  std::unique_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
+  SetRemoteDescriptionWithoutError(offer.release());
+
+  cricket::MediaSessionOptions options;
+  // Test with a stream with tracks.
+  SendAudioVideoStream1();
+  std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer(options));
+
+  // TODO(perkj): Should the direction be set to SEND_ONLY?
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_FALSE(content->rejected);
+
+  // TODO(perkj): Should the direction be set to SEND_ONLY?
+  content = cricket::GetFirstVideoContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_FALSE(content->rejected);
+}
+
+TEST_F(WebRtcSessionTest, CreateOfferWithoutCNCodecs) {
+  AddCNCodecs();
+  Init();
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_audio =
+      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
+  options.voice_activity_detection = false;
+
+  std::unique_ptr<SessionDescriptionInterface> offer(CreateOffer(options));
+
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(offer->description());
+  EXPECT_TRUE(content != NULL);
+  EXPECT_TRUE(VerifyNoCNCodecs(content));
+}
+
+TEST_F(WebRtcSessionTest, CreateAnswerWithoutCNCodecs) {
+  AddCNCodecs();
+  Init();
+  // Create a remote offer with audio and video content.
+  std::unique_ptr<JsepSessionDescription> offer(CreateRemoteOffer());
+  SetRemoteDescriptionWithoutError(offer.release());
+
+  cricket::MediaSessionOptions options;
+  options.vad_enabled = false;
+  std::unique_ptr<SessionDescriptionInterface> answer(CreateAnswer(options));
+  const cricket::ContentInfo* content =
+      cricket::GetFirstAudioContent(answer->description());
+  ASSERT_TRUE(content != NULL);
+  EXPECT_TRUE(VerifyNoCNCodecs(content));
+}
+
+// This test verifies the call setup when remote answer with audio only and
+// later updates with video.
+TEST_F(WebRtcSessionTest, TestAVOfferWithAudioOnlyAnswer) {
+  Init();
+  EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL);
+  EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL);
+
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* offer = CreateOffer();
+
+  cricket::MediaSessionOptions options;
+  AddMediaSection(cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
+                  cricket::MD_RECVONLY, kActive, &options);
+  AddMediaSection(cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
+                  cricket::MD_INACTIVE, kStopped, &options);
+  local_recv_video_ = false;
+  SessionDescriptionInterface* answer = CreateRemoteAnswer(offer, options);
+
+  // SetLocalDescription and SetRemoteDescriptions takes ownership of offer
+  // and answer;
+  SetLocalDescriptionWithoutError(offer);
+  SetRemoteDescriptionWithoutError(answer);
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  ASSERT_TRUE(video_channel_ == nullptr);
+
+  ASSERT_EQ(0u, voice_channel_->recv_streams().size());
+  ASSERT_EQ(1u, voice_channel_->send_streams().size());
+  EXPECT_EQ(kAudioTrack1, voice_channel_->send_streams()[0].id);
+
+  // Let the remote end update the session descriptions, with Audio and Video.
+  SendAudioVideoStream2();
+  local_recv_video_ = true;
+  CreateAndSetRemoteOfferAndLocalAnswer();
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  ASSERT_TRUE(video_channel_ != nullptr);
+  ASSERT_TRUE(voice_channel_ != nullptr);
+
+  ASSERT_EQ(1u, video_channel_->recv_streams().size());
+  ASSERT_EQ(1u, video_channel_->send_streams().size());
+  EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id);
+  EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id);
+  ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+  ASSERT_EQ(1u, voice_channel_->send_streams().size());
+  EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id);
+  EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
+
+  // Change session back to audio only.
+  // The remote side doesn't send and recv video.
+  SendAudioOnlyStream2();
+  remote_recv_video_ = false;
+  CreateAndSetRemoteOfferAndLocalAnswer();
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  // The audio is expected to be rejected.
+  EXPECT_TRUE(video_channel_ == nullptr);
+
+  ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+  EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id);
+  ASSERT_EQ(1u, voice_channel_->send_streams().size());
+  EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
+}
+
+// This test verifies the call setup when remote answer with video only and
+// later updates with audio.
+TEST_F(WebRtcSessionTest, TestAVOfferWithVideoOnlyAnswer) {
+  Init();
+  EXPECT_TRUE(media_engine_->GetVideoChannel(0) == NULL);
+  EXPECT_TRUE(media_engine_->GetVoiceChannel(0) == NULL);
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* offer = CreateOffer();
+
+  cricket::MediaSessionOptions options;
+  AddMediaSection(cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
+                  cricket::MD_INACTIVE, kStopped, &options);
+  AddMediaSection(cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
+                  cricket::MD_RECVONLY, kActive, &options);
+  local_recv_audio_ = false;
+  SessionDescriptionInterface* answer =
+      CreateRemoteAnswer(offer, options, cricket::SEC_ENABLED);
+
+  // SetLocalDescription and SetRemoteDescriptions takes ownership of offer
+  // and answer.
+  SetLocalDescriptionWithoutError(offer);
+  SetRemoteDescriptionWithoutError(answer);
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  ASSERT_TRUE(voice_channel_ == NULL);
+  ASSERT_TRUE(video_channel_ != NULL);
+
+  EXPECT_EQ(0u, video_channel_->recv_streams().size());
+  ASSERT_EQ(1u, video_channel_->send_streams().size());
+  EXPECT_EQ(kVideoTrack1, video_channel_->send_streams()[0].id);
+
+  // Update the session descriptions, with Audio and Video.
+  SendAudioVideoStream2();
+  local_recv_audio_ = true;
+  SessionDescriptionInterface* offer2 = CreateRemoteOffer();
+  SetRemoteDescriptionWithoutError(offer2);
+  cricket::MediaSessionOptions answer_options;
+  // Disable the bundling here. If the media is bundled on audio
+  // transport, then we can't reject the audio because switching the bundled
+  // transport is not currently supported.
+  // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
+  answer_options.bundle_enabled = false;
+  SessionDescriptionInterface* answer2 = CreateAnswer(answer_options);
+  SetLocalDescriptionWithoutError(answer2);
+
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  ASSERT_TRUE(voice_channel_ != NULL);
+  ASSERT_EQ(1u, voice_channel_->recv_streams().size());
+  ASSERT_EQ(1u, voice_channel_->send_streams().size());
+  EXPECT_EQ(kAudioTrack2, voice_channel_->recv_streams()[0].id);
+  EXPECT_EQ(kAudioTrack2, voice_channel_->send_streams()[0].id);
+
+  // Change session back to video only.
+  // The remote side doesn't send and recv audio.
+  SendVideoOnlyStream2();
+  remote_recv_audio_ = false;
+  SessionDescriptionInterface* offer3 = CreateRemoteOffer();
+  SetRemoteDescriptionWithoutError(offer3);
+  SessionDescriptionInterface* answer3 = CreateAnswer(answer_options);
+  SetLocalDescriptionWithoutError(answer3);
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  // The video is expected to be rejected.
+  EXPECT_TRUE(voice_channel_ == nullptr);
+
+  ASSERT_EQ(1u, video_channel_->recv_streams().size());
+  EXPECT_EQ(kVideoTrack2, video_channel_->recv_streams()[0].id);
+  ASSERT_EQ(1u, video_channel_->send_streams().size());
+  EXPECT_EQ(kVideoTrack2, video_channel_->send_streams()[0].id);
+}
+
 // Test that candidates sent to the "video" transport do not get pushed down to
 // the "audio" transport channel when bundling.
 TEST_F(WebRtcSessionTest, TestIgnoreCandidatesForUnusedTransportWhenBundling) {
@@ -1604,6 +2458,127 @@
   SetLocalDescriptionWithoutError(offer);
 }
 
+// This test verifies the |initial_offerer| flag when session initiates the
+// call.
+TEST_F(WebRtcSessionTest, TestInitiatorFlagAsOriginator) {
+  Init();
+  EXPECT_FALSE(session_->initial_offerer());
+  SessionDescriptionInterface* offer = CreateOffer();
+  SessionDescriptionInterface* answer = CreateRemoteAnswer(offer);
+  SetLocalDescriptionWithoutError(offer);
+  EXPECT_TRUE(session_->initial_offerer());
+  SetRemoteDescriptionWithoutError(answer);
+  EXPECT_TRUE(session_->initial_offerer());
+}
+
+// This test verifies the |initial_offerer| flag when session receives the call.
+TEST_F(WebRtcSessionTest, TestInitiatorFlagAsReceiver) {
+  Init();
+  EXPECT_FALSE(session_->initial_offerer());
+  SessionDescriptionInterface* offer = CreateRemoteOffer();
+  SetRemoteDescriptionWithoutError(offer);
+  SessionDescriptionInterface* answer = CreateAnswer();
+
+  EXPECT_FALSE(session_->initial_offerer());
+  SetLocalDescriptionWithoutError(answer);
+  EXPECT_FALSE(session_->initial_offerer());
+}
+
+// Verifing local offer and remote answer have matching m-lines as per RFC 3264.
+TEST_F(WebRtcSessionTest, TestIncorrectMLinesInRemoteAnswer) {
+  Init();
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* offer = CreateOffer();
+  SetLocalDescriptionWithoutError(offer);
+  std::unique_ptr<SessionDescriptionInterface> answer(
+      CreateRemoteAnswer(session_->local_description()));
+
+  cricket::SessionDescription* answer_copy = answer->description()->Copy();
+  answer_copy->RemoveContentByName("video");
+  JsepSessionDescription* modified_answer =
+      new JsepSessionDescription(JsepSessionDescription::kAnswer);
+
+  EXPECT_TRUE(modified_answer->Initialize(answer_copy,
+                                          answer->session_id(),
+                                          answer->session_version()));
+  SetRemoteDescriptionAnswerExpectError(kMlineMismatchInAnswer,
+                                        modified_answer);
+
+  // Different content names.
+  std::string sdp;
+  EXPECT_TRUE(answer->ToString(&sdp));
+  const std::string kAudioMid = "a=mid:audio";
+  const std::string kAudioMidReplaceStr = "a=mid:audio_content_name";
+  rtc::replace_substrs(kAudioMid.c_str(), kAudioMid.length(),
+                             kAudioMidReplaceStr.c_str(),
+                             kAudioMidReplaceStr.length(),
+                             &sdp);
+  SessionDescriptionInterface* modified_answer1 =
+      CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
+  SetRemoteDescriptionAnswerExpectError(kMlineMismatchInAnswer,
+                                        modified_answer1);
+
+  // Different media types.
+  EXPECT_TRUE(answer->ToString(&sdp));
+  const std::string kAudioMline = "m=audio";
+  const std::string kAudioMlineReplaceStr = "m=video";
+  rtc::replace_substrs(kAudioMline.c_str(), kAudioMline.length(),
+                             kAudioMlineReplaceStr.c_str(),
+                             kAudioMlineReplaceStr.length(),
+                             &sdp);
+  SessionDescriptionInterface* modified_answer2 =
+      CreateSessionDescription(JsepSessionDescription::kAnswer, sdp, NULL);
+  SetRemoteDescriptionAnswerExpectError(kMlineMismatchInAnswer,
+                                        modified_answer2);
+
+  SetRemoteDescriptionWithoutError(answer.release());
+}
+
+// Verifying remote offer and local answer have matching m-lines as per
+// RFC 3264.
+TEST_F(WebRtcSessionTest, TestIncorrectMLinesInLocalAnswer) {
+  Init();
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* offer = CreateRemoteOffer();
+  SetRemoteDescriptionWithoutError(offer);
+  SessionDescriptionInterface* answer = CreateAnswer();
+
+  cricket::SessionDescription* answer_copy = answer->description()->Copy();
+  answer_copy->RemoveContentByName("video");
+  JsepSessionDescription* modified_answer =
+      new JsepSessionDescription(JsepSessionDescription::kAnswer);
+
+  EXPECT_TRUE(modified_answer->Initialize(answer_copy,
+                                          answer->session_id(),
+                                          answer->session_version()));
+  SetLocalDescriptionAnswerExpectError(kMlineMismatchInAnswer, modified_answer);
+  SetLocalDescriptionWithoutError(answer);
+}
+
+TEST_F(WebRtcSessionTest, TestSessionContentError) {
+  Init();
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* offer = CreateOffer();
+  const std::string session_id_orig = offer->session_id();
+  const std::string session_version_orig = offer->session_version();
+  SetLocalDescriptionWithoutError(offer);
+
+  video_channel_ = media_engine_->GetVideoChannel(0);
+  video_channel_->set_fail_set_send_codecs(true);
+
+  SessionDescriptionInterface* answer =
+      CreateRemoteAnswer(session_->local_description());
+  SetRemoteDescriptionAnswerExpectError("ERROR_CONTENT", answer);
+
+  // Test that after a content error, setting any description will
+  // result in an error.
+  video_channel_->set_fail_set_send_codecs(false);
+  answer = CreateRemoteAnswer(session_->local_description());
+  SetRemoteDescriptionExpectError("", "ERROR_CONTENT", answer);
+  offer = CreateRemoteOffer();
+  SetLocalDescriptionExpectError("", "ERROR_CONTENT", offer);
+}
+
 TEST_F(WebRtcSessionTest, TestRtpDataChannel) {
   configuration_.enable_rtp_data_channel = true;
   Init();
@@ -1782,6 +2757,21 @@
             last_data_channel_config_.open_handshake_role);
 }
 
+TEST_F(WebRtcSessionTest, TestCombinedAudioVideoBweConstraint) {
+  configuration_.combined_audio_video_bwe = rtc::Optional<bool>(true);
+  Init();
+  SendAudioVideoStream1();
+  SessionDescriptionInterface* offer = CreateOffer();
+
+  SetLocalDescriptionWithoutError(offer);
+
+  voice_channel_ = media_engine_->GetVoiceChannel(0);
+
+  ASSERT_TRUE(voice_channel_ != NULL);
+  const cricket::AudioOptions& audio_options = voice_channel_->options();
+  EXPECT_EQ(rtc::Optional<bool>(true), audio_options.combined_audio_video_bwe);
+}
+
 #ifdef HAVE_QUIC
 TEST_P(WebRtcSessionTest, TestNegotiateQuic) {
   configuration_.enable_quic = true;
@@ -1801,6 +2791,33 @@
 }
 #endif  // HAVE_QUIC
 
+// Tests that RTX codec is removed from the answer when it isn't supported
+// by local side.
+TEST_F(WebRtcSessionTest, TestRtxRemovedByCreateAnswer) {
+  Init();
+  // Send video only to match the |kSdpWithRtx|.
+  SendVideoOnlyStream2();
+  std::string offer_sdp(kSdpWithRtx);
+
+  SessionDescriptionInterface* offer =
+      CreateSessionDescription(JsepSessionDescription::kOffer, offer_sdp, NULL);
+  EXPECT_TRUE(offer->ToString(&offer_sdp));
+
+  // Offer SDP contains the RTX codec.
+  EXPECT_TRUE(ContainsVideoCodecWithName(offer, "rtx"));
+  SetRemoteDescriptionWithoutError(offer);
+
+  // |offered_media_sections_| is used when creating answer.
+  offered_media_sections_.push_back(cricket::MediaDescriptionOptions(
+      cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
+      cricket::RtpTransceiverDirection(true, true), false));
+  // Don't create media section for audio in the answer.
+  SessionDescriptionInterface* answer = CreateAnswer();
+  // Answer SDP does not contain the RTX codec.
+  EXPECT_FALSE(ContainsVideoCodecWithName(answer, "rtx"));
+  SetLocalDescriptionWithoutError(answer);
+}
+
 // This verifies that the voice channel after bundle has both options from video
 // and voice channels.
 TEST_F(WebRtcSessionTest, TestSetSocketOptionBeforeBundle) {
@@ -1849,6 +2866,34 @@
   EXPECT_EQ(8000, option_val);
 }
 
+// Test creating a session, request multiple offers, destroy the session
+// and make sure we got success/failure callbacks for all of the requests.
+// Background: crbug.com/507307
+TEST_F(WebRtcSessionTest, CreateOffersAndShutdown) {
+  Init();
+
+  rtc::scoped_refptr<WebRtcSessionCreateSDPObserverForTest> observers[100];
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.offer_to_receive_audio =
+      RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
+  cricket::MediaSessionOptions session_options;
+  GetOptionsForOffer(options, &session_options);
+  for (auto& o : observers) {
+    o = new WebRtcSessionCreateSDPObserverForTest();
+    session_->CreateOffer(o, options, session_options);
+  }
+
+  session_.reset();
+
+  for (auto& o : observers) {
+    // We expect to have received a notification now even if the session was
+    // terminated.  The offer creation may or may not have succeeded, but we
+    // must have received a notification which, so the only invalid state
+    // is kInit.
+    EXPECT_NE(WebRtcSessionCreateSDPObserverForTest::kInit, o->state());
+  }
+}
+
 TEST_F(WebRtcSessionTest, TestPacketOptionsAndOnPacketSent) {
   TestPacketOptions();
 }