Reland "Reland "Split peer_connection_integrationtest.cc into pieces""

This reverts commit 89c40e246e39372390f0f843545d4e56aa657040.

Reason for revert: Added missing INSTANTIATE

Original change's description:
> Revert "Reland "Split peer_connection_integrationtest.cc into pieces""
>
> This reverts commit 772066bf16b125c1346a4d1b3e28c6e6f21cc1a7.
>
> Reason for revert: Did not catch all missing INSTANTIATE_TEST_SUITE_P
>
> Original change's description:
> > Reland "Split peer_connection_integrationtest.cc into pieces"
> >
> > This reverts commit 8644f2b7632cff5e46560c2f5cf7c0dc071aa32d.
> >
> > Reason for revert: Fixed the bugs
> >
> > Original change's description:
> > > Revert "Split peer_connection_integrationtest.cc into pieces"
> > >
> > > This reverts commit cae4656d4a7439e25160ff4d94e50949ff87cebe.
> > >
> > > Reason for revert: Breaks downstream build (missing INSTANTIATE_TEST_SUITE_P in pc/data_channel_integrationtest.cc).
> > >
> > > Original change's description:
> > > > Split peer_connection_integrationtest.cc into pieces
> > > >
> > > > This creates two integration tests: One for datachannel, the other
> > > > for every test that is not datachannel.
> > > >
> > > > It separates out the common framework to a new file in pc/test.
> > > > Also applies some fixes to IWYU.
> > > >
> > > > Bug: None
> > > > Change-Id: I919def1c360ffce205c20bec2d864aad9b179c3a
> > > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/207060
> > > > Reviewed-by: Henrik Boström <hbos@webrtc.org>
> > > > Commit-Queue: Harald Alvestrand <hta@webrtc.org>
> > > > Cr-Commit-Position: refs/heads/master@{#33244}
> > >
> > > TBR=hbos@webrtc.org,hta@webrtc.org
> > >
> > > # Not skipping CQ checks because original CL landed > 1 day ago.
> > >
> > > No-Try: True
> > > Bug: None
> > > Change-Id: I7dbedd3256cb7ff47eb5f8cd46c7c044ed0aa1e0
> > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/207283
> > > Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
> > > Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
> > > Cr-Commit-Position: refs/heads/master@{#33255}
> >
> > # Not skipping CQ checks because original CL landed > 1 day ago.
> >
> > Bug: None
> > Change-Id: I1bb6186d7f898de82d26f4cd3d8a88014140c518
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/207864
> > Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
> > Reviewed-by: Henrik Boström <hbos@webrtc.org>
> > Reviewed-by: Harald Alvestrand <hta@webrtc.org>
> > Commit-Queue: Harald Alvestrand <hta@webrtc.org>
> > Cr-Commit-Position: refs/heads/master@{#33283}
>
> Bug: None
> Change-Id: I2b09b57c2477e52301ac30ec12ed69f2555ba7f8
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/208021
> Reviewed-by: Harald Alvestrand <hta@webrtc.org>
> Commit-Queue: Harald Alvestrand <hta@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#33286}

Bug: None
Change-Id: I6e362ac2234ae6c69dc9bbf886ee7dece8484202
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/208022
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33289}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 473bc85..8a6fa3c 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -1044,6 +1044,7 @@
   rtc_test("peerconnection_unittests") {
     testonly = true
     sources = [
+      "data_channel_integrationtest.cc",
       "data_channel_unittest.cc",
       "dtmf_sender_unittest.cc",
       "ice_server_parsing_unittest.cc",
@@ -1081,6 +1082,8 @@
       "sdp_serializer_unittest.cc",
       "stats_collector_unittest.cc",
       "test/fake_audio_capture_module_unittest.cc",
+      "test/integration_test_helpers.cc",
+      "test/integration_test_helpers.h",
       "test/test_sdp_strings.h",
       "track_media_info_map_unittest.cc",
       "video_rtp_track_source_unittest.cc",
@@ -1121,7 +1124,9 @@
       "../api:libjingle_peerconnection_api",
       "../api:media_stream_interface",
       "../api:mock_rtp",
+      "../api:packet_socket_factory",
       "../api:rtc_error",
+      "../api:rtp_transceiver_direction",
       "../api:scoped_refptr",
       "../api/audio:audio_mixer_api",
       "../api/crypto:frame_decryptor_interface",
@@ -1129,11 +1134,14 @@
       "../api/crypto:options",
       "../api/rtc_event_log",
       "../api/rtc_event_log:rtc_event_log_factory",
+      "../api/task_queue",
       "../api/task_queue:default_task_queue_factory",
       "../api/transport:field_trial_based_config",
+      "../api/transport:webrtc_key_value_config",
       "../api/transport/rtp:rtp_source",
       "../api/units:time_delta",
       "../api/video:builtin_video_bitrate_allocator_factory",
+      "../api/video:video_rtp_headers",
       "../call/adaptation:resource_adaptation_test_utilities",
       "../logging:fake_rtc_event_log",
       "../media:rtc_media_config",
@@ -1144,6 +1152,7 @@
       "../modules/rtp_rtcp:rtp_rtcp_format",
       "../p2p:fake_ice_transport",
       "../p2p:fake_port_allocator",
+      "../p2p:p2p_server_utils",
       "../rtc_base:checks",
       "../rtc_base:gunit_helpers",
       "../rtc_base:ip_address",
diff --git a/pc/data_channel_integrationtest.cc b/pc/data_channel_integrationtest.cc
new file mode 100644
index 0000000..24fe232
--- /dev/null
+++ b/pc/data_channel_integrationtest.cc
@@ -0,0 +1,714 @@
+/*
+ *  Copyright 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/data_channel_interface.h"
+#include "api/dtmf_sender_interface.h"
+#include "api/peer_connection_interface.h"
+#include "api/scoped_refptr.h"
+#include "api/units/time_delta.h"
+#include "pc/test/integration_test_helpers.h"
+#include "pc/test/mock_peer_connection_observers.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/gunit.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/virtual_socket_server.h"
+
+namespace webrtc {
+
+namespace {
+
+class DataChannelIntegrationTest
+    : public PeerConnectionIntegrationBaseTest,
+      public ::testing::WithParamInterface<SdpSemantics> {
+ protected:
+  DataChannelIntegrationTest()
+      : PeerConnectionIntegrationBaseTest(GetParam()) {}
+};
+
+// Fake clock must be set before threads are started to prevent race on
+// Set/GetClockForTesting().
+// To achieve that, multiple inheritance is used as a mixin pattern
+// where order of construction is finely controlled.
+// This also ensures peerconnection is closed before switching back to non-fake
+// clock, avoiding other races and DCHECK failures such as in rtp_sender.cc.
+class FakeClockForTest : public rtc::ScopedFakeClock {
+ protected:
+  FakeClockForTest() {
+    // Some things use a time of "0" as a special value, so we need to start out
+    // the fake clock at a nonzero time.
+    // TODO(deadbeef): Fix this.
+    AdvanceTime(webrtc::TimeDelta::Seconds(1));
+  }
+
+  // Explicit handle.
+  ScopedFakeClock& FakeClock() { return *this; }
+};
+
+// Ensure FakeClockForTest is constructed first (see class for rationale).
+class DataChannelIntegrationTestWithFakeClock
+    : public FakeClockForTest,
+      public DataChannelIntegrationTest {};
+
+class DataChannelIntegrationTestPlanB
+    : public PeerConnectionIntegrationBaseTest {
+ protected:
+  DataChannelIntegrationTestPlanB()
+      : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB) {}
+};
+
+class DataChannelIntegrationTestUnifiedPlan
+    : public PeerConnectionIntegrationBaseTest {
+ protected:
+  DataChannelIntegrationTestUnifiedPlan()
+      : PeerConnectionIntegrationBaseTest(SdpSemantics::kUnifiedPlan) {}
+};
+
+class DummyDtmfObserver : public DtmfSenderObserverInterface {
+ public:
+  DummyDtmfObserver() : completed_(false) {}
+
+  // Implements DtmfSenderObserverInterface.
+  void OnToneChange(const std::string& tone) override {
+    tones_.push_back(tone);
+    if (tone.empty()) {
+      completed_ = true;
+    }
+  }
+
+  const std::vector<std::string>& tones() const { return tones_; }
+  bool completed() const { return completed_; }
+
+ private:
+  bool completed_;
+  std::vector<std::string> tones_;
+};
+
+#ifdef WEBRTC_HAVE_SCTP
+
+// This test causes a PeerConnection to enter Disconnected state, and
+// sends data on a DataChannel while disconnected.
+// The data should be surfaced when the connection reestablishes.
+TEST_P(DataChannelIntegrationTest, DataChannelWhileDisconnected) {
+  CreatePeerConnectionWrappers();
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+  std::string data1 = "hello first";
+  caller()->data_channel()->Send(DataBuffer(data1));
+  EXPECT_EQ_WAIT(data1, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+  // Cause a network outage
+  virtual_socket_server()->set_drop_probability(1.0);
+  EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
+                 caller()->standardized_ice_connection_state(),
+                 kDefaultTimeout);
+  std::string data2 = "hello second";
+  caller()->data_channel()->Send(DataBuffer(data2));
+  // Remove the network outage. The connection should reestablish.
+  virtual_socket_server()->set_drop_probability(0.0);
+  EXPECT_EQ_WAIT(data2, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+// This test causes a PeerConnection to enter Disconnected state,
+// sends data on a DataChannel while disconnected, and then triggers
+// an ICE restart.
+// The data should be surfaced when the connection reestablishes.
+TEST_P(DataChannelIntegrationTest, DataChannelWhileDisconnectedIceRestart) {
+  CreatePeerConnectionWrappers();
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+  std::string data1 = "hello first";
+  caller()->data_channel()->Send(DataBuffer(data1));
+  EXPECT_EQ_WAIT(data1, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+  // Cause a network outage
+  virtual_socket_server()->set_drop_probability(1.0);
+  ASSERT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
+                 caller()->standardized_ice_connection_state(),
+                 kDefaultTimeout);
+  std::string data2 = "hello second";
+  caller()->data_channel()->Send(DataBuffer(data2));
+
+  // Trigger an ICE restart. The signaling channel is not affected by
+  // the network outage.
+  caller()->SetOfferAnswerOptions(IceRestartOfferAnswerOptions());
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // Remove the network outage. The connection should reestablish.
+  virtual_socket_server()->set_drop_probability(0.0);
+  EXPECT_EQ_WAIT(data2, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+#endif  // WEBRTC_HAVE_SCTP
+
+// This test sets up a call between two parties with audio, video and an RTP
+// data channel.
+TEST_P(DataChannelIntegrationTest, EndToEndCallWithRtpDataChannel) {
+  PeerConnectionInterface::RTCConfiguration rtc_config;
+  rtc_config.enable_rtp_data_channel = true;
+  rtc_config.enable_dtls_srtp = false;
+  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
+  ConnectFakeSignaling();
+  // Expect that data channel created on caller side will show up for callee as
+  // well.
+  caller()->CreateDataChannel();
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // Ensure the existence of the RTP data channel didn't impede audio/video.
+  MediaExpectations media_expectations;
+  media_expectations.ExpectBidirectionalAudioAndVideo();
+  ASSERT_TRUE(ExpectNewFrames(media_expectations));
+  ASSERT_NE(nullptr, caller()->data_channel());
+  ASSERT_NE(nullptr, callee()->data_channel());
+  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+  // Ensure data can be sent in both directions.
+  std::string data = "hello world";
+  SendRtpDataWithRetries(caller()->data_channel(), data, 5);
+  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+  SendRtpDataWithRetries(callee()->data_channel(), data, 5);
+  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+TEST_P(DataChannelIntegrationTest, RtpDataChannelWorksAfterRollback) {
+  PeerConnectionInterface::RTCConfiguration rtc_config;
+  rtc_config.enable_rtp_data_channel = true;
+  rtc_config.enable_dtls_srtp = false;
+  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
+  ConnectFakeSignaling();
+  auto data_channel = caller()->pc()->CreateDataChannel("label_1", nullptr);
+  ASSERT_TRUE(data_channel.get() != nullptr);
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+
+  caller()->CreateDataChannel("label_2", nullptr);
+  rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
+      new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
+  caller()->pc()->SetLocalDescription(observer,
+                                      caller()->CreateOfferAndWait().release());
+  EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
+  caller()->Rollback();
+
+  std::string data = "hello world";
+  SendRtpDataWithRetries(data_channel, data, 5);
+  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+// Ensure that an RTP data channel is signaled as closed for the caller when
+// the callee rejects it in a subsequent offer.
+TEST_P(DataChannelIntegrationTest, RtpDataChannelSignaledClosedInCalleeOffer) {
+  // Same procedure as above test.
+  PeerConnectionInterface::RTCConfiguration rtc_config;
+  rtc_config.enable_rtp_data_channel = true;
+  rtc_config.enable_dtls_srtp = false;
+  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_NE(nullptr, caller()->data_channel());
+  ASSERT_NE(nullptr, callee()->data_channel());
+  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+  // Close the data channel on the callee, and do an updated offer/answer.
+  callee()->data_channel()->Close();
+  callee()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  EXPECT_FALSE(caller()->data_observer()->IsOpen());
+  EXPECT_FALSE(callee()->data_observer()->IsOpen());
+}
+
+#if !defined(THREAD_SANITIZER)
+// This test provokes TSAN errors. See bugs.webrtc.org/11282
+
+// Tests that data is buffered in an RTP data channel until an observer is
+// registered for it.
+//
+// NOTE: RTP data channels can receive data before the underlying
+// transport has detected that a channel is writable and thus data can be
+// received before the data channel state changes to open. That is hard to test
+// but the same buffering is expected to be used in that case.
+//
+// Use fake clock and simulated network delay so that we predictably can wait
+// until an SCTP message has been delivered without "sleep()"ing.
+TEST_P(DataChannelIntegrationTestWithFakeClock,
+       DataBufferedUntilRtpDataChannelObserverRegistered) {
+  virtual_socket_server()->set_delay_mean(5);  // 5 ms per hop.
+  virtual_socket_server()->UpdateDelayDistribution();
+
+  PeerConnectionInterface::RTCConfiguration rtc_config;
+  rtc_config.enable_rtp_data_channel = true;
+  rtc_config.enable_dtls_srtp = false;
+  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE(caller()->data_channel() != nullptr);
+  ASSERT_TRUE_SIMULATED_WAIT(callee()->data_channel() != nullptr,
+                             kDefaultTimeout, FakeClock());
+  ASSERT_TRUE_SIMULATED_WAIT(caller()->data_observer()->IsOpen(),
+                             kDefaultTimeout, FakeClock());
+  ASSERT_EQ_SIMULATED_WAIT(DataChannelInterface::kOpen,
+                           callee()->data_channel()->state(), kDefaultTimeout,
+                           FakeClock());
+
+  // Unregister the observer which is normally automatically registered.
+  callee()->data_channel()->UnregisterObserver();
+  // Send data and advance fake clock until it should have been received.
+  std::string data = "hello world";
+  caller()->data_channel()->Send(DataBuffer(data));
+  SIMULATED_WAIT(false, 50, FakeClock());
+
+  // Attach data channel and expect data to be received immediately. Note that
+  // EXPECT_EQ_WAIT is used, such that the simulated clock is not advanced any
+  // further, but data can be received even if the callback is asynchronous.
+  MockDataChannelObserver new_observer(callee()->data_channel());
+  EXPECT_EQ_SIMULATED_WAIT(data, new_observer.last_message(), kDefaultTimeout,
+                           FakeClock());
+}
+
+#endif  // !defined(THREAD_SANITIZER)
+
+// This test sets up a call between two parties with audio, video and but only
+// the caller client supports RTP data channels.
+TEST_P(DataChannelIntegrationTest, RtpDataChannelsRejectedByCallee) {
+  PeerConnectionInterface::RTCConfiguration rtc_config_1;
+  rtc_config_1.enable_rtp_data_channel = true;
+  // Must disable DTLS to make negotiation succeed.
+  rtc_config_1.enable_dtls_srtp = false;
+  PeerConnectionInterface::RTCConfiguration rtc_config_2;
+  rtc_config_2.enable_dtls_srtp = false;
+  rtc_config_2.enable_dtls_srtp = false;
+  ASSERT_TRUE(
+      CreatePeerConnectionWrappersWithConfig(rtc_config_1, rtc_config_2));
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  ASSERT_TRUE(caller()->data_channel() != nullptr);
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // The caller should still have a data channel, but it should be closed, and
+  // one should ever have been created for the callee.
+  EXPECT_TRUE(caller()->data_channel() != nullptr);
+  EXPECT_FALSE(caller()->data_observer()->IsOpen());
+  EXPECT_EQ(nullptr, callee()->data_channel());
+}
+
+// This test sets up a call between two parties with audio, and video. When
+// audio and video is setup and flowing, an RTP data channel is negotiated.
+TEST_P(DataChannelIntegrationTest, AddRtpDataChannelInSubsequentOffer) {
+  PeerConnectionInterface::RTCConfiguration rtc_config;
+  rtc_config.enable_rtp_data_channel = true;
+  rtc_config.enable_dtls_srtp = false;
+  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
+  ConnectFakeSignaling();
+  // Do initial offer/answer with audio/video.
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // Create data channel and do new offer and answer.
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_NE(nullptr, caller()->data_channel());
+  ASSERT_NE(nullptr, callee()->data_channel());
+  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+  // Ensure data can be sent in both directions.
+  std::string data = "hello world";
+  SendRtpDataWithRetries(caller()->data_channel(), data, 5);
+  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+  SendRtpDataWithRetries(callee()->data_channel(), data, 5);
+  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+#ifdef WEBRTC_HAVE_SCTP
+
+// This test sets up a call between two parties with audio, video and an SCTP
+// data channel.
+TEST_P(DataChannelIntegrationTest, EndToEndCallWithSctpDataChannel) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  // Expect that data channel created on caller side will show up for callee as
+  // well.
+  caller()->CreateDataChannel();
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // Ensure the existence of the SCTP data channel didn't impede audio/video.
+  MediaExpectations media_expectations;
+  media_expectations.ExpectBidirectionalAudioAndVideo();
+  ASSERT_TRUE(ExpectNewFrames(media_expectations));
+  // Caller data channel should already exist (it created one). Callee data
+  // channel may not exist yet, since negotiation happens in-band, not in SDP.
+  ASSERT_NE(nullptr, caller()->data_channel());
+  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+  // Ensure data can be sent in both directions.
+  std::string data = "hello world";
+  caller()->data_channel()->Send(DataBuffer(data));
+  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+  callee()->data_channel()->Send(DataBuffer(data));
+  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+// Ensure that when the callee closes an SCTP data channel, the closing
+// procedure results in the data channel being closed for the caller as well.
+TEST_P(DataChannelIntegrationTest, CalleeClosesSctpDataChannel) {
+  // Same procedure as above test.
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_NE(nullptr, caller()->data_channel());
+  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+  // Close the data channel on the callee side, and wait for it to reach the
+  // "closed" state on both sides.
+  callee()->data_channel()->Close();
+  EXPECT_TRUE_WAIT(!caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  EXPECT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
+TEST_P(DataChannelIntegrationTest, SctpDataChannelConfigSentToOtherSide) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  webrtc::DataChannelInit init;
+  init.id = 53;
+  init.maxRetransmits = 52;
+  caller()->CreateDataChannel("data-channel", &init);
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+  // Since "negotiated" is false, the "id" parameter should be ignored.
+  EXPECT_NE(init.id, callee()->data_channel()->id());
+  EXPECT_EQ("data-channel", callee()->data_channel()->label());
+  EXPECT_EQ(init.maxRetransmits, callee()->data_channel()->maxRetransmits());
+  EXPECT_FALSE(callee()->data_channel()->negotiated());
+}
+
+// Test usrsctp's ability to process unordered data stream, where data actually
+// arrives out of order using simulated delays. Previously there have been some
+// bugs in this area.
+TEST_P(DataChannelIntegrationTest, StressTestUnorderedSctpDataChannel) {
+  // Introduce random network delays.
+  // Otherwise it's not a true "unordered" test.
+  virtual_socket_server()->set_delay_mean(20);
+  virtual_socket_server()->set_delay_stddev(5);
+  virtual_socket_server()->UpdateDelayDistribution();
+  // Normal procedure, but with unordered data channel config.
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  webrtc::DataChannelInit init;
+  init.ordered = false;
+  caller()->CreateDataChannel(&init);
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_NE(nullptr, caller()->data_channel());
+  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+  static constexpr int kNumMessages = 100;
+  // Deliberately chosen to be larger than the MTU so messages get fragmented.
+  static constexpr size_t kMaxMessageSize = 4096;
+  // Create and send random messages.
+  std::vector<std::string> sent_messages;
+  for (int i = 0; i < kNumMessages; ++i) {
+    size_t length =
+        (rand() % kMaxMessageSize) + 1;  // NOLINT (rand_r instead of rand)
+    std::string message;
+    ASSERT_TRUE(rtc::CreateRandomString(length, &message));
+    caller()->data_channel()->Send(DataBuffer(message));
+    callee()->data_channel()->Send(DataBuffer(message));
+    sent_messages.push_back(message);
+  }
+
+  // Wait for all messages to be received.
+  EXPECT_EQ_WAIT(rtc::checked_cast<size_t>(kNumMessages),
+                 caller()->data_observer()->received_message_count(),
+                 kDefaultTimeout);
+  EXPECT_EQ_WAIT(rtc::checked_cast<size_t>(kNumMessages),
+                 callee()->data_observer()->received_message_count(),
+                 kDefaultTimeout);
+
+  // Sort and compare to make sure none of the messages were corrupted.
+  std::vector<std::string> caller_received_messages =
+      caller()->data_observer()->messages();
+  std::vector<std::string> callee_received_messages =
+      callee()->data_observer()->messages();
+  absl::c_sort(sent_messages);
+  absl::c_sort(caller_received_messages);
+  absl::c_sort(callee_received_messages);
+  EXPECT_EQ(sent_messages, caller_received_messages);
+  EXPECT_EQ(sent_messages, callee_received_messages);
+}
+
+// This test sets up a call between two parties with audio, and video. When
+// audio and video are setup and flowing, an SCTP data channel is negotiated.
+TEST_P(DataChannelIntegrationTest, AddSctpDataChannelInSubsequentOffer) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  // Do initial offer/answer with audio/video.
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // Create data channel and do new offer and answer.
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // Caller data channel should already exist (it created one). Callee data
+  // channel may not exist yet, since negotiation happens in-band, not in SDP.
+  ASSERT_NE(nullptr, caller()->data_channel());
+  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+  // Ensure data can be sent in both directions.
+  std::string data = "hello world";
+  caller()->data_channel()->Send(DataBuffer(data));
+  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+  callee()->data_channel()->Send(DataBuffer(data));
+  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+// Set up a connection initially just using SCTP data channels, later upgrading
+// to audio/video, ensuring frames are received end-to-end. Effectively the
+// inverse of the test above.
+// This was broken in M57; see https://crbug.com/711243
+TEST_P(DataChannelIntegrationTest, SctpDataChannelToAudioVideoUpgrade) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  // Do initial offer/answer with just data channel.
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  // Wait until data can be sent over the data channel.
+  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+  // Do subsequent offer/answer with two-way audio and video. Audio and video
+  // should end up bundled on the DTLS/ICE transport already used for data.
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  MediaExpectations media_expectations;
+  media_expectations.ExpectBidirectionalAudioAndVideo();
+  ASSERT_TRUE(ExpectNewFrames(media_expectations));
+}
+
+static void MakeSpecCompliantSctpOffer(cricket::SessionDescription* desc) {
+  cricket::SctpDataContentDescription* dcd_offer =
+      GetFirstSctpDataContentDescription(desc);
+  // See https://crbug.com/webrtc/11211 - this function is a no-op
+  ASSERT_TRUE(dcd_offer);
+  dcd_offer->set_use_sctpmap(false);
+  dcd_offer->set_protocol("UDP/DTLS/SCTP");
+}
+
+// Test that the data channel works when a spec-compliant SCTP m= section is
+// offered (using "a=sctp-port" instead of "a=sctpmap", and using
+// "UDP/DTLS/SCTP" as the protocol).
+TEST_P(DataChannelIntegrationTest,
+       DataChannelWorksWhenSpecCompliantSctpOfferReceived) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->SetGeneratedSdpMunger(MakeSpecCompliantSctpOffer);
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
+  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
+  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+
+  // Ensure data can be sent in both directions.
+  std::string data = "hello world";
+  caller()->data_channel()->Send(DataBuffer(data));
+  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
+                 kDefaultTimeout);
+  callee()->data_channel()->Send(DataBuffer(data));
+  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
+                 kDefaultTimeout);
+}
+
+#endif  // WEBRTC_HAVE_SCTP
+
+// Test that after closing PeerConnections, they stop sending any packets (ICE,
+// DTLS, RTP...).
+TEST_P(DataChannelIntegrationTest, ClosingConnectionStopsPacketFlow) {
+  // Set up audio/video/data, wait for some frames to be received.
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->AddAudioVideoTracks();
+#ifdef WEBRTC_HAVE_SCTP
+  caller()->CreateDataChannel();
+#endif
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  MediaExpectations media_expectations;
+  media_expectations.CalleeExpectsSomeAudioAndVideo();
+  ASSERT_TRUE(ExpectNewFrames(media_expectations));
+  // Close PeerConnections.
+  ClosePeerConnections();
+  // Pump messages for a second, and ensure no new packets end up sent.
+  uint32_t sent_packets_a = virtual_socket_server()->sent_packets();
+  WAIT(false, 1000);
+  uint32_t sent_packets_b = virtual_socket_server()->sent_packets();
+  EXPECT_EQ(sent_packets_a, sent_packets_b);
+}
+
+// Test that transport stats are generated by the RTCStatsCollector for a
+// connection that only involves data channels. This is a regression test for
+// crbug.com/826972.
+#ifdef WEBRTC_HAVE_SCTP
+TEST_P(DataChannelIntegrationTest,
+       TransportStatsReportedForDataChannelOnlyConnection) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
+
+  auto caller_report = caller()->NewGetStats();
+  EXPECT_EQ(1u, caller_report->GetStatsOfType<RTCTransportStats>().size());
+  auto callee_report = callee()->NewGetStats();
+  EXPECT_EQ(1u, callee_report->GetStatsOfType<RTCTransportStats>().size());
+}
+
+INSTANTIATE_TEST_SUITE_P(DataChannelIntegrationTest,
+                         DataChannelIntegrationTest,
+                         Values(SdpSemantics::kPlanB,
+                                SdpSemantics::kUnifiedPlan));
+
+INSTANTIATE_TEST_SUITE_P(DataChannelIntegrationTest,
+                         DataChannelIntegrationTestWithFakeClock,
+                         Values(SdpSemantics::kPlanB,
+                                SdpSemantics::kUnifiedPlan));
+
+TEST_F(DataChannelIntegrationTestUnifiedPlan,
+       EndToEndCallWithBundledSctpDataChannel) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->AddAudioVideoTracks();
+  callee()->AddAudioVideoTracks();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
+    ASSERT_EQ_WAIT(SctpTransportState::kConnected,
+                   caller()->pc()->GetSctpTransport()->Information().state(),
+                   kDefaultTimeout);
+  });
+  ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
+TEST_F(DataChannelIntegrationTestUnifiedPlan,
+       EndToEndCallWithDataChannelOnlyConnects) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+  ASSERT_TRUE(caller()->data_observer()->IsOpen());
+}
+
+TEST_F(DataChannelIntegrationTestUnifiedPlan, DataChannelClosesWhenClosed) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+  caller()->data_channel()->Close();
+  ASSERT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
+TEST_F(DataChannelIntegrationTestUnifiedPlan,
+       DataChannelClosesWhenClosedReverse) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+  callee()->data_channel()->Close();
+  ASSERT_TRUE_WAIT(!caller()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
+TEST_F(DataChannelIntegrationTestUnifiedPlan,
+       DataChannelClosesWhenPeerConnectionClosed) {
+  ASSERT_TRUE(CreatePeerConnectionWrappers());
+  ConnectFakeSignaling();
+  caller()->CreateDataChannel();
+  caller()->CreateAndSetAndSignalOffer();
+  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
+  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
+  caller()->pc()->Close();
+  ASSERT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
+}
+
+#endif  // WEBRTC_HAVE_SCTP
+
+}  // namespace
+
+}  // namespace webrtc
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
index 745d1f5..86b9696 100644
--- a/pc/peer_connection_integrationtest.cc
+++ b/pc/peer_connection_integrationtest.cc
@@ -8,1818 +8,89 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include <stdio.h>
+#include <stdint.h>
 
 #include <algorithm>
-#include <functional>
-#include <list>
-#include <map>
 #include <memory>
+#include <string>
+#include <tuple>
 #include <utility>
 #include <vector>
 
 #include "absl/algorithm/container.h"
+#include "absl/types/optional.h"
+#include "api/async_resolver_factory.h"
+#include "api/candidate.h"
+#include "api/crypto/crypto_options.h"
+#include "api/dtmf_sender_interface.h"
+#include "api/ice_transport_interface.h"
+#include "api/jsep.h"
 #include "api/media_stream_interface.h"
+#include "api/media_types.h"
 #include "api/peer_connection_interface.h"
-#include "api/peer_connection_proxy.h"
-#include "api/rtc_event_log/rtc_event_log_factory.h"
+#include "api/rtc_error.h"
+#include "api/rtc_event_log/rtc_event.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/rtc_event_log_output.h"
+#include "api/rtp_parameters.h"
 #include "api/rtp_receiver_interface.h"
-#include "api/task_queue/default_task_queue_factory.h"
-#include "api/transport/field_trial_based_config.h"
+#include "api/rtp_sender_interface.h"
+#include "api/rtp_transceiver_direction.h"
+#include "api/rtp_transceiver_interface.h"
+#include "api/scoped_refptr.h"
+#include "api/stats/rtc_stats.h"
+#include "api/stats/rtc_stats_report.h"
+#include "api/stats/rtcstats_objects.h"
+#include "api/transport/rtp/rtp_source.h"
 #include "api/uma_metrics.h"
-#include "api/video_codecs/sdp_video_format.h"
-#include "call/call.h"
+#include "api/units/time_delta.h"
+#include "api/video/video_rotation.h"
+#include "logging/rtc_event_log/fake_rtc_event_log.h"
 #include "logging/rtc_event_log/fake_rtc_event_log_factory.h"
-#include "media/engine/fake_webrtc_video_engine.h"
-#include "media/engine/webrtc_media_engine.h"
-#include "media/engine/webrtc_media_engine_defaults.h"
-#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
-#include "p2p/base/fake_ice_transport.h"
+#include "media/base/codec.h"
+#include "media/base/media_constants.h"
+#include "media/base/stream_params.h"
 #include "p2p/base/mock_async_resolver.h"
-#include "p2p/base/p2p_constants.h"
+#include "p2p/base/port.h"
+#include "p2p/base/port_allocator.h"
 #include "p2p/base/port_interface.h"
+#include "p2p/base/stun_server.h"
 #include "p2p/base/test_stun_server.h"
 #include "p2p/base/test_turn_customizer.h"
 #include "p2p/base/test_turn_server.h"
-#include "p2p/client/basic_port_allocator.h"
-#include "pc/dtmf_sender.h"
-#include "pc/local_audio_source.h"
+#include "p2p/base/transport_description.h"
+#include "p2p/base/transport_info.h"
 #include "pc/media_session.h"
 #include "pc/peer_connection.h"
 #include "pc/peer_connection_factory.h"
-#include "pc/rtp_media_utils.h"
 #include "pc/session_description.h"
-#include "pc/test/fake_audio_capture_module.h"
-#include "pc/test/fake_periodic_video_track_source.h"
-#include "pc/test/fake_rtc_certificate_generator.h"
-#include "pc/test/fake_video_track_renderer.h"
+#include "pc/test/fake_periodic_video_source.h"
+#include "pc/test/integration_test_helpers.h"
 #include "pc/test/mock_peer_connection_observers.h"
 #include "rtc_base/fake_clock.h"
 #include "rtc_base/fake_mdns_responder.h"
 #include "rtc_base/fake_network.h"
 #include "rtc_base/firewall_socket_server.h"
 #include "rtc_base/gunit.h"
-#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/helpers.h"
+#include "rtc_base/location.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/ssl_fingerprint.h"
+#include "rtc_base/ssl_identity.h"
+#include "rtc_base/ssl_stream_adapter.h"
 #include "rtc_base/test_certificate_verifier.h"
+#include "rtc_base/thread.h"
 #include "rtc_base/time_utils.h"
 #include "rtc_base/virtual_socket_server.h"
 #include "system_wrappers/include/metrics.h"
-#include "test/field_trial.h"
-#include "test/gmock.h"
 
 namespace webrtc {
+
 namespace {
 
-using ::cricket::ContentInfo;
-using ::cricket::StreamParams;
-using ::rtc::SocketAddress;
-using ::testing::_;
-using ::testing::Combine;
-using ::testing::Contains;
-using ::testing::DoAll;
-using ::testing::ElementsAre;
-using ::testing::NiceMock;
-using ::testing::Return;
-using ::testing::SetArgPointee;
-using ::testing::UnorderedElementsAreArray;
-using ::testing::Values;
-using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
-
-static const int kDefaultTimeout = 10000;
-static const int kMaxWaitForStatsMs = 3000;
-static const int kMaxWaitForActivationMs = 5000;
-static const int kMaxWaitForFramesMs = 10000;
-// Default number of audio/video frames to wait for before considering a test
-// successful.
-static const int kDefaultExpectedAudioFrameCount = 3;
-static const int kDefaultExpectedVideoFrameCount = 3;
-
-static const char kDataChannelLabel[] = "data_channel";
-
-// SRTP cipher name negotiated by the tests. This must be updated if the
-// default changes.
-static const int kDefaultSrtpCryptoSuite = rtc::SRTP_AES128_CM_SHA1_80;
-static const int kDefaultSrtpCryptoSuiteGcm = rtc::SRTP_AEAD_AES_256_GCM;
-
-static const SocketAddress kDefaultLocalAddress("192.168.1.1", 0);
-
-// Helper function for constructing offer/answer options to initiate an ICE
-// restart.
-PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions() {
-  PeerConnectionInterface::RTCOfferAnswerOptions options;
-  options.ice_restart = true;
-  return options;
-}
-
-// Remove all stream information (SSRCs, track IDs, etc.) and "msid-semantic"
-// attribute from received SDP, simulating a legacy endpoint.
-void RemoveSsrcsAndMsids(cricket::SessionDescription* desc) {
-  for (ContentInfo& content : desc->contents()) {
-    content.media_description()->mutable_streams().clear();
-  }
-  desc->set_msid_supported(false);
-  desc->set_msid_signaling(0);
-}
-
-// Removes all stream information besides the stream ids, simulating an
-// endpoint that only signals a=msid lines to convey stream_ids.
-void RemoveSsrcsAndKeepMsids(cricket::SessionDescription* desc) {
-  for (ContentInfo& content : desc->contents()) {
-    std::string track_id;
-    std::vector<std::string> stream_ids;
-    if (!content.media_description()->streams().empty()) {
-      const StreamParams& first_stream =
-          content.media_description()->streams()[0];
-      track_id = first_stream.id;
-      stream_ids = first_stream.stream_ids();
-    }
-    content.media_description()->mutable_streams().clear();
-    StreamParams new_stream;
-    new_stream.id = track_id;
-    new_stream.set_stream_ids(stream_ids);
-    content.media_description()->AddStream(new_stream);
-  }
-}
-
-int FindFirstMediaStatsIndexByKind(
-    const std::string& kind,
-    const std::vector<const webrtc::RTCMediaStreamTrackStats*>&
-        media_stats_vec) {
-  for (size_t i = 0; i < media_stats_vec.size(); i++) {
-    if (media_stats_vec[i]->kind.ValueToString() == kind) {
-      return i;
-    }
-  }
-  return -1;
-}
-
-class SignalingMessageReceiver {
- public:
-  virtual void ReceiveSdpMessage(SdpType type, const std::string& msg) = 0;
-  virtual void ReceiveIceMessage(const std::string& sdp_mid,
-                                 int sdp_mline_index,
-                                 const std::string& msg) = 0;
-
- protected:
-  SignalingMessageReceiver() {}
-  virtual ~SignalingMessageReceiver() {}
-};
-
-class MockRtpReceiverObserver : public webrtc::RtpReceiverObserverInterface {
- public:
-  explicit MockRtpReceiverObserver(cricket::MediaType media_type)
-      : expected_media_type_(media_type) {}
-
-  void OnFirstPacketReceived(cricket::MediaType media_type) override {
-    ASSERT_EQ(expected_media_type_, media_type);
-    first_packet_received_ = true;
-  }
-
-  bool first_packet_received() const { return first_packet_received_; }
-
-  virtual ~MockRtpReceiverObserver() {}
-
- private:
-  bool first_packet_received_ = false;
-  cricket::MediaType expected_media_type_;
-};
-
-// Helper class that wraps a peer connection, observes it, and can accept
-// signaling messages from another wrapper.
-//
-// Uses a fake network, fake A/V capture, and optionally fake
-// encoders/decoders, though they aren't used by default since they don't
-// advertise support of any codecs.
-// TODO(steveanton): See how this could become a subclass of
-// PeerConnectionWrapper defined in peerconnectionwrapper.h.
-class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
-                              public SignalingMessageReceiver {
- public:
-  // Different factory methods for convenience.
-  // TODO(deadbeef): Could use the pattern of:
-  //
-  // PeerConnectionWrapper =
-  //     WrapperBuilder.WithConfig(...).WithOptions(...).build();
-  //
-  // To reduce some code duplication.
-  static PeerConnectionWrapper* CreateWithDtlsIdentityStore(
-      const std::string& debug_name,
-      std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
-      rtc::Thread* network_thread,
-      rtc::Thread* worker_thread) {
-    PeerConnectionWrapper* client(new PeerConnectionWrapper(debug_name));
-    webrtc::PeerConnectionDependencies dependencies(nullptr);
-    dependencies.cert_generator = std::move(cert_generator);
-    if (!client->Init(nullptr, nullptr, std::move(dependencies), network_thread,
-                      worker_thread, nullptr,
-                      /*reset_encoder_factory=*/false,
-                      /*reset_decoder_factory=*/false)) {
-      delete client;
-      return nullptr;
-    }
-    return client;
-  }
-
-  webrtc::PeerConnectionFactoryInterface* pc_factory() const {
-    return peer_connection_factory_.get();
-  }
-
-  webrtc::PeerConnectionInterface* pc() const { return peer_connection_.get(); }
-
-  // If a signaling message receiver is set (via ConnectFakeSignaling), this
-  // will set the whole offer/answer exchange in motion. Just need to wait for
-  // the signaling state to reach "stable".
-  void CreateAndSetAndSignalOffer() {
-    auto offer = CreateOfferAndWait();
-    ASSERT_NE(nullptr, offer);
-    EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(offer)));
-  }
-
-  // Sets the options to be used when CreateAndSetAndSignalOffer is called, or
-  // when a remote offer is received (via fake signaling) and an answer is
-  // generated. By default, uses default options.
-  void SetOfferAnswerOptions(
-      const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
-    offer_answer_options_ = options;
-  }
-
-  // Set a callback to be invoked when SDP is received via the fake signaling
-  // channel, which provides an opportunity to munge (modify) the SDP. This is
-  // used to test SDP being applied that a PeerConnection would normally not
-  // generate, but a non-JSEP endpoint might.
-  void SetReceivedSdpMunger(
-      std::function<void(cricket::SessionDescription*)> munger) {
-    received_sdp_munger_ = std::move(munger);
-  }
-
-  // Similar to the above, but this is run on SDP immediately after it's
-  // generated.
-  void SetGeneratedSdpMunger(
-      std::function<void(cricket::SessionDescription*)> munger) {
-    generated_sdp_munger_ = std::move(munger);
-  }
-
-  // Set a callback to be invoked when a remote offer is received via the fake
-  // signaling channel. This provides an opportunity to change the
-  // PeerConnection state before an answer is created and sent to the caller.
-  void SetRemoteOfferHandler(std::function<void()> handler) {
-    remote_offer_handler_ = std::move(handler);
-  }
-
-  void SetRemoteAsyncResolver(rtc::MockAsyncResolver* resolver) {
-    remote_async_resolver_ = resolver;
-  }
-
-  // Every ICE connection state in order that has been seen by the observer.
-  std::vector<PeerConnectionInterface::IceConnectionState>
-  ice_connection_state_history() const {
-    return ice_connection_state_history_;
-  }
-  void clear_ice_connection_state_history() {
-    ice_connection_state_history_.clear();
-  }
-
-  // Every standardized ICE connection state in order that has been seen by the
-  // observer.
-  std::vector<PeerConnectionInterface::IceConnectionState>
-  standardized_ice_connection_state_history() const {
-    return standardized_ice_connection_state_history_;
-  }
-
-  // Every PeerConnection state in order that has been seen by the observer.
-  std::vector<PeerConnectionInterface::PeerConnectionState>
-  peer_connection_state_history() const {
-    return peer_connection_state_history_;
-  }
-
-  // Every ICE gathering state in order that has been seen by the observer.
-  std::vector<PeerConnectionInterface::IceGatheringState>
-  ice_gathering_state_history() const {
-    return ice_gathering_state_history_;
-  }
-  std::vector<cricket::CandidatePairChangeEvent>
-  ice_candidate_pair_change_history() const {
-    return ice_candidate_pair_change_history_;
-  }
-
-  // Every PeerConnection signaling state in order that has been seen by the
-  // observer.
-  std::vector<PeerConnectionInterface::SignalingState>
-  peer_connection_signaling_state_history() const {
-    return peer_connection_signaling_state_history_;
-  }
-
-  void AddAudioVideoTracks() {
-    AddAudioTrack();
-    AddVideoTrack();
-  }
-
-  rtc::scoped_refptr<RtpSenderInterface> AddAudioTrack() {
-    return AddTrack(CreateLocalAudioTrack());
-  }
-
-  rtc::scoped_refptr<RtpSenderInterface> AddVideoTrack() {
-    return AddTrack(CreateLocalVideoTrack());
-  }
-
-  rtc::scoped_refptr<webrtc::AudioTrackInterface> CreateLocalAudioTrack() {
-    cricket::AudioOptions options;
-    // Disable highpass filter so that we can get all the test audio frames.
-    options.highpass_filter = false;
-    rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
-        peer_connection_factory_->CreateAudioSource(options);
-    // TODO(perkj): Test audio source when it is implemented. Currently audio
-    // always use the default input.
-    return peer_connection_factory_->CreateAudioTrack(rtc::CreateRandomUuid(),
-                                                      source);
-  }
-
-  rtc::scoped_refptr<webrtc::VideoTrackInterface> CreateLocalVideoTrack() {
-    webrtc::FakePeriodicVideoSource::Config config;
-    config.timestamp_offset_ms = rtc::TimeMillis();
-    return CreateLocalVideoTrackInternal(config);
-  }
-
-  rtc::scoped_refptr<webrtc::VideoTrackInterface>
-  CreateLocalVideoTrackWithConfig(
-      webrtc::FakePeriodicVideoSource::Config config) {
-    return CreateLocalVideoTrackInternal(config);
-  }
-
-  rtc::scoped_refptr<webrtc::VideoTrackInterface>
-  CreateLocalVideoTrackWithRotation(webrtc::VideoRotation rotation) {
-    webrtc::FakePeriodicVideoSource::Config config;
-    config.rotation = rotation;
-    config.timestamp_offset_ms = rtc::TimeMillis();
-    return CreateLocalVideoTrackInternal(config);
-  }
-
-  rtc::scoped_refptr<RtpSenderInterface> AddTrack(
-      rtc::scoped_refptr<MediaStreamTrackInterface> track,
-      const std::vector<std::string>& stream_ids = {}) {
-    auto result = pc()->AddTrack(track, stream_ids);
-    EXPECT_EQ(RTCErrorType::NONE, result.error().type());
-    return result.MoveValue();
-  }
-
-  std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceiversOfType(
-      cricket::MediaType media_type) {
-    std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
-    for (const auto& receiver : pc()->GetReceivers()) {
-      if (receiver->media_type() == media_type) {
-        receivers.push_back(receiver);
-      }
-    }
-    return receivers;
-  }
-
-  rtc::scoped_refptr<RtpTransceiverInterface> GetFirstTransceiverOfType(
-      cricket::MediaType media_type) {
-    for (auto transceiver : pc()->GetTransceivers()) {
-      if (transceiver->receiver()->media_type() == media_type) {
-        return transceiver;
-      }
-    }
-    return nullptr;
-  }
-
-  bool SignalingStateStable() {
-    return pc()->signaling_state() == webrtc::PeerConnectionInterface::kStable;
-  }
-
-  void CreateDataChannel() { CreateDataChannel(nullptr); }
-
-  void CreateDataChannel(const webrtc::DataChannelInit* init) {
-    CreateDataChannel(kDataChannelLabel, init);
-  }
-
-  void CreateDataChannel(const std::string& label,
-                         const webrtc::DataChannelInit* init) {
-    data_channel_ = pc()->CreateDataChannel(label, init);
-    ASSERT_TRUE(data_channel_.get() != nullptr);
-    data_observer_.reset(new MockDataChannelObserver(data_channel_));
-  }
-
-  DataChannelInterface* data_channel() { return data_channel_; }
-  const MockDataChannelObserver* data_observer() const {
-    return data_observer_.get();
-  }
-
-  int audio_frames_received() const {
-    return fake_audio_capture_module_->frames_received();
-  }
-
-  // Takes minimum of video frames received for each track.
-  //
-  // Can be used like:
-  // EXPECT_GE(expected_frames, min_video_frames_received_per_track());
-  //
-  // To ensure that all video tracks received at least a certain number of
-  // frames.
-  int min_video_frames_received_per_track() const {
-    int min_frames = INT_MAX;
-    if (fake_video_renderers_.empty()) {
-      return 0;
-    }
-
-    for (const auto& pair : fake_video_renderers_) {
-      min_frames = std::min(min_frames, pair.second->num_rendered_frames());
-    }
-    return min_frames;
-  }
-
-  // Returns a MockStatsObserver in a state after stats gathering finished,
-  // which can be used to access the gathered stats.
-  rtc::scoped_refptr<MockStatsObserver> OldGetStatsForTrack(
-      webrtc::MediaStreamTrackInterface* track) {
-    rtc::scoped_refptr<MockStatsObserver> observer(
-        new rtc::RefCountedObject<MockStatsObserver>());
-    EXPECT_TRUE(peer_connection_->GetStats(
-        observer, nullptr, PeerConnectionInterface::kStatsOutputLevelStandard));
-    EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
-    return observer;
-  }
-
-  // Version that doesn't take a track "filter", and gathers all stats.
-  rtc::scoped_refptr<MockStatsObserver> OldGetStats() {
-    return OldGetStatsForTrack(nullptr);
-  }
-
-  // Synchronously gets stats and returns them. If it times out, fails the test
-  // and returns null.
-  rtc::scoped_refptr<const webrtc::RTCStatsReport> NewGetStats() {
-    rtc::scoped_refptr<webrtc::MockRTCStatsCollectorCallback> callback(
-        new rtc::RefCountedObject<webrtc::MockRTCStatsCollectorCallback>());
-    peer_connection_->GetStats(callback);
-    EXPECT_TRUE_WAIT(callback->called(), kDefaultTimeout);
-    return callback->report();
-  }
-
-  int rendered_width() {
-    EXPECT_FALSE(fake_video_renderers_.empty());
-    return fake_video_renderers_.empty()
-               ? 0
-               : fake_video_renderers_.begin()->second->width();
-  }
-
-  int rendered_height() {
-    EXPECT_FALSE(fake_video_renderers_.empty());
-    return fake_video_renderers_.empty()
-               ? 0
-               : fake_video_renderers_.begin()->second->height();
-  }
-
-  double rendered_aspect_ratio() {
-    if (rendered_height() == 0) {
-      return 0.0;
-    }
-    return static_cast<double>(rendered_width()) / rendered_height();
-  }
-
-  webrtc::VideoRotation rendered_rotation() {
-    EXPECT_FALSE(fake_video_renderers_.empty());
-    return fake_video_renderers_.empty()
-               ? webrtc::kVideoRotation_0
-               : fake_video_renderers_.begin()->second->rotation();
-  }
-
-  int local_rendered_width() {
-    return local_video_renderer_ ? local_video_renderer_->width() : 0;
-  }
-
-  int local_rendered_height() {
-    return local_video_renderer_ ? local_video_renderer_->height() : 0;
-  }
-
-  double local_rendered_aspect_ratio() {
-    if (local_rendered_height() == 0) {
-      return 0.0;
-    }
-    return static_cast<double>(local_rendered_width()) /
-           local_rendered_height();
-  }
-
-  size_t number_of_remote_streams() {
-    if (!pc()) {
-      return 0;
-    }
-    return pc()->remote_streams()->count();
-  }
-
-  StreamCollectionInterface* remote_streams() const {
-    if (!pc()) {
-      ADD_FAILURE();
-      return nullptr;
-    }
-    return pc()->remote_streams();
-  }
-
-  StreamCollectionInterface* local_streams() {
-    if (!pc()) {
-      ADD_FAILURE();
-      return nullptr;
-    }
-    return pc()->local_streams();
-  }
-
-  webrtc::PeerConnectionInterface::SignalingState signaling_state() {
-    return pc()->signaling_state();
-  }
-
-  webrtc::PeerConnectionInterface::IceConnectionState ice_connection_state() {
-    return pc()->ice_connection_state();
-  }
-
-  webrtc::PeerConnectionInterface::IceConnectionState
-  standardized_ice_connection_state() {
-    return pc()->standardized_ice_connection_state();
-  }
-
-  webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state() {
-    return pc()->ice_gathering_state();
-  }
-
-  // Returns a MockRtpReceiverObserver for each RtpReceiver returned by
-  // GetReceivers. They're updated automatically when a remote offer/answer
-  // from the fake signaling channel is applied, or when
-  // ResetRtpReceiverObservers below is called.
-  const std::vector<std::unique_ptr<MockRtpReceiverObserver>>&
-  rtp_receiver_observers() {
-    return rtp_receiver_observers_;
-  }
-
-  void ResetRtpReceiverObservers() {
-    rtp_receiver_observers_.clear();
-    for (const rtc::scoped_refptr<RtpReceiverInterface>& receiver :
-         pc()->GetReceivers()) {
-      std::unique_ptr<MockRtpReceiverObserver> observer(
-          new MockRtpReceiverObserver(receiver->media_type()));
-      receiver->SetObserver(observer.get());
-      rtp_receiver_observers_.push_back(std::move(observer));
-    }
-  }
-
-  rtc::FakeNetworkManager* network_manager() const {
-    return fake_network_manager_.get();
-  }
-  cricket::PortAllocator* port_allocator() const { return port_allocator_; }
-
-  webrtc::FakeRtcEventLogFactory* event_log_factory() const {
-    return event_log_factory_;
-  }
-
-  const cricket::Candidate& last_candidate_gathered() const {
-    return last_candidate_gathered_;
-  }
-  const cricket::IceCandidateErrorEvent& error_event() const {
-    return error_event_;
-  }
-
-  // Sets the mDNS responder for the owned fake network manager and keeps a
-  // reference to the responder.
-  void SetMdnsResponder(
-      std::unique_ptr<webrtc::FakeMdnsResponder> mdns_responder) {
-    RTC_DCHECK(mdns_responder != nullptr);
-    mdns_responder_ = mdns_responder.get();
-    network_manager()->set_mdns_responder(std::move(mdns_responder));
-  }
-
-  // Returns null on failure.
-  std::unique_ptr<SessionDescriptionInterface> CreateOfferAndWait() {
-    rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer(
-        new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>());
-    pc()->CreateOffer(observer, offer_answer_options_);
-    return WaitForDescriptionFromObserver(observer);
-  }
-  bool Rollback() {
-    return SetRemoteDescription(
-        webrtc::CreateSessionDescription(SdpType::kRollback, ""));
-  }
-
-  // Functions for querying stats.
-  void StartWatchingDelayStats() {
-    // Get the baseline numbers for audio_packets and audio_delay.
-    auto received_stats = NewGetStats();
-    auto track_stats =
-        received_stats->GetStatsOfType<webrtc::RTCMediaStreamTrackStats>()[0];
-    ASSERT_TRUE(track_stats->relative_packet_arrival_delay.is_defined());
-    auto rtp_stats =
-        received_stats->GetStatsOfType<webrtc::RTCInboundRTPStreamStats>()[0];
-    ASSERT_TRUE(rtp_stats->packets_received.is_defined());
-    ASSERT_TRUE(rtp_stats->track_id.is_defined());
-    audio_track_stats_id_ = track_stats->id();
-    ASSERT_TRUE(received_stats->Get(audio_track_stats_id_));
-    rtp_stats_id_ = rtp_stats->id();
-    ASSERT_EQ(audio_track_stats_id_, *rtp_stats->track_id);
-    audio_packets_stat_ = *rtp_stats->packets_received;
-    audio_delay_stat_ = *track_stats->relative_packet_arrival_delay;
-    audio_samples_stat_ = *track_stats->total_samples_received;
-    audio_concealed_stat_ = *track_stats->concealed_samples;
-  }
-
-  void UpdateDelayStats(std::string tag, int desc_size) {
-    auto report = NewGetStats();
-    auto track_stats =
-        report->GetAs<webrtc::RTCMediaStreamTrackStats>(audio_track_stats_id_);
-    ASSERT_TRUE(track_stats);
-    auto rtp_stats =
-        report->GetAs<webrtc::RTCInboundRTPStreamStats>(rtp_stats_id_);
-    ASSERT_TRUE(rtp_stats);
-    auto delta_packets = *rtp_stats->packets_received - audio_packets_stat_;
-    auto delta_rpad =
-        *track_stats->relative_packet_arrival_delay - audio_delay_stat_;
-    auto recent_delay = delta_packets > 0 ? delta_rpad / delta_packets : -1;
-    // The purpose of these checks is to sound the alarm early if we introduce
-    // serious regressions. The numbers are not acceptable for production, but
-    // occur on slow bots.
-    //
-    // An average relative packet arrival delay over the renegotiation of
-    // > 100 ms indicates that something is dramatically wrong, and will impact
-    // quality for sure.
-    // Worst bots:
-    // linux_x86_dbg at 0.206
-#if !defined(NDEBUG)
-    EXPECT_GT(0.25, recent_delay) << tag << " size " << desc_size;
-#else
-    EXPECT_GT(0.1, recent_delay) << tag << " size " << desc_size;
-#endif
-    auto delta_samples =
-        *track_stats->total_samples_received - audio_samples_stat_;
-    auto delta_concealed =
-        *track_stats->concealed_samples - audio_concealed_stat_;
-    // These limits should be adjusted down as we improve:
-    //
-    // Concealing more than 4000 samples during a renegotiation is unacceptable.
-    // But some bots are slow.
-
-    // Worst bots:
-    // linux_more_configs bot at conceal count 5184
-    // android_arm_rel at conceal count 9241
-    // linux_x86_dbg at 15174
-#if !defined(NDEBUG)
-    EXPECT_GT(18000U, delta_concealed) << "Concealed " << delta_concealed
-                                       << " of " << delta_samples << " samples";
-#else
-    EXPECT_GT(15000U, delta_concealed) << "Concealed " << delta_concealed
-                                       << " of " << delta_samples << " samples";
-#endif
-    // Concealing more than 20% of samples during a renegotiation is
-    // unacceptable.
-    // Worst bots:
-    // linux_more_configs bot at conceal rate 0.516
-    // linux_x86_dbg bot at conceal rate 0.854
-    if (delta_samples > 0) {
-#if !defined(NDEBUG)
-      EXPECT_GT(0.95, 1.0 * delta_concealed / delta_samples)
-          << "Concealed " << delta_concealed << " of " << delta_samples
-          << " samples";
-#else
-      EXPECT_GT(0.6, 1.0 * delta_concealed / delta_samples)
-          << "Concealed " << delta_concealed << " of " << delta_samples
-          << " samples";
-#endif
-    }
-    // Increment trailing counters
-    audio_packets_stat_ = *rtp_stats->packets_received;
-    audio_delay_stat_ = *track_stats->relative_packet_arrival_delay;
-    audio_samples_stat_ = *track_stats->total_samples_received;
-    audio_concealed_stat_ = *track_stats->concealed_samples;
-  }
-
- private:
-  explicit PeerConnectionWrapper(const std::string& debug_name)
-      : debug_name_(debug_name) {}
-
-  bool Init(
-      const PeerConnectionFactory::Options* options,
-      const PeerConnectionInterface::RTCConfiguration* config,
-      webrtc::PeerConnectionDependencies dependencies,
-      rtc::Thread* network_thread,
-      rtc::Thread* worker_thread,
-      std::unique_ptr<webrtc::FakeRtcEventLogFactory> event_log_factory,
-      bool reset_encoder_factory,
-      bool reset_decoder_factory) {
-    // There's an error in this test code if Init ends up being called twice.
-    RTC_DCHECK(!peer_connection_);
-    RTC_DCHECK(!peer_connection_factory_);
-
-    fake_network_manager_.reset(new rtc::FakeNetworkManager());
-    fake_network_manager_->AddInterface(kDefaultLocalAddress);
-
-    std::unique_ptr<cricket::PortAllocator> port_allocator(
-        new cricket::BasicPortAllocator(fake_network_manager_.get()));
-    port_allocator_ = port_allocator.get();
-    fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
-    if (!fake_audio_capture_module_) {
-      return false;
-    }
-    rtc::Thread* const signaling_thread = rtc::Thread::Current();
-
-    webrtc::PeerConnectionFactoryDependencies pc_factory_dependencies;
-    pc_factory_dependencies.network_thread = network_thread;
-    pc_factory_dependencies.worker_thread = worker_thread;
-    pc_factory_dependencies.signaling_thread = signaling_thread;
-    pc_factory_dependencies.task_queue_factory =
-        webrtc::CreateDefaultTaskQueueFactory();
-    pc_factory_dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
-    cricket::MediaEngineDependencies media_deps;
-    media_deps.task_queue_factory =
-        pc_factory_dependencies.task_queue_factory.get();
-    media_deps.adm = fake_audio_capture_module_;
-    webrtc::SetMediaEngineDefaults(&media_deps);
-
-    if (reset_encoder_factory) {
-      media_deps.video_encoder_factory.reset();
-    }
-    if (reset_decoder_factory) {
-      media_deps.video_decoder_factory.reset();
-    }
-
-    if (!media_deps.audio_processing) {
-      // If the standard Creation method for APM returns a null pointer, instead
-      // use the builder for testing to create an APM object.
-      media_deps.audio_processing = AudioProcessingBuilderForTesting().Create();
-    }
-
-    media_deps.trials = pc_factory_dependencies.trials.get();
-
-    pc_factory_dependencies.media_engine =
-        cricket::CreateMediaEngine(std::move(media_deps));
-    pc_factory_dependencies.call_factory = webrtc::CreateCallFactory();
-    if (event_log_factory) {
-      event_log_factory_ = event_log_factory.get();
-      pc_factory_dependencies.event_log_factory = std::move(event_log_factory);
-    } else {
-      pc_factory_dependencies.event_log_factory =
-          std::make_unique<webrtc::RtcEventLogFactory>(
-              pc_factory_dependencies.task_queue_factory.get());
-    }
-    peer_connection_factory_ = webrtc::CreateModularPeerConnectionFactory(
-        std::move(pc_factory_dependencies));
-
-    if (!peer_connection_factory_) {
-      return false;
-    }
-    if (options) {
-      peer_connection_factory_->SetOptions(*options);
-    }
-    if (config) {
-      sdp_semantics_ = config->sdp_semantics;
-    }
-
-    dependencies.allocator = std::move(port_allocator);
-    peer_connection_ = CreatePeerConnection(config, std::move(dependencies));
-    return peer_connection_.get() != nullptr;
-  }
-
-  rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
-      const PeerConnectionInterface::RTCConfiguration* config,
-      webrtc::PeerConnectionDependencies dependencies) {
-    PeerConnectionInterface::RTCConfiguration modified_config;
-    // If |config| is null, this will result in a default configuration being
-    // used.
-    if (config) {
-      modified_config = *config;
-    }
-    // Disable resolution adaptation; we don't want it interfering with the
-    // test results.
-    // TODO(deadbeef): Do something more robust. Since we're testing for aspect
-    // ratios and not specific resolutions, is this even necessary?
-    modified_config.set_cpu_adaptation(false);
-
-    dependencies.observer = this;
-    return peer_connection_factory_->CreatePeerConnection(
-        modified_config, std::move(dependencies));
-  }
-
-  void set_signaling_message_receiver(
-      SignalingMessageReceiver* signaling_message_receiver) {
-    signaling_message_receiver_ = signaling_message_receiver;
-  }
-
-  void set_signaling_delay_ms(int delay_ms) { signaling_delay_ms_ = delay_ms; }
-
-  void set_signal_ice_candidates(bool signal) {
-    signal_ice_candidates_ = signal;
-  }
-
-  rtc::scoped_refptr<webrtc::VideoTrackInterface> CreateLocalVideoTrackInternal(
-      webrtc::FakePeriodicVideoSource::Config config) {
-    // Set max frame rate to 10fps to reduce the risk of test flakiness.
-    // TODO(deadbeef): Do something more robust.
-    config.frame_interval_ms = 100;
-
-    video_track_sources_.emplace_back(
-        new rtc::RefCountedObject<webrtc::FakePeriodicVideoTrackSource>(
-            config, false /* remote */));
-    rtc::scoped_refptr<webrtc::VideoTrackInterface> track(
-        peer_connection_factory_->CreateVideoTrack(
-            rtc::CreateRandomUuid(), video_track_sources_.back()));
-    if (!local_video_renderer_) {
-      local_video_renderer_.reset(new webrtc::FakeVideoTrackRenderer(track));
-    }
-    return track;
-  }
-
-  void HandleIncomingOffer(const std::string& msg) {
-    RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingOffer";
-    std::unique_ptr<SessionDescriptionInterface> desc =
-        webrtc::CreateSessionDescription(SdpType::kOffer, msg);
-    if (received_sdp_munger_) {
-      received_sdp_munger_(desc->description());
-    }
-
-    EXPECT_TRUE(SetRemoteDescription(std::move(desc)));
-    // Setting a remote description may have changed the number of receivers,
-    // so reset the receiver observers.
-    ResetRtpReceiverObservers();
-    if (remote_offer_handler_) {
-      remote_offer_handler_();
-    }
-    auto answer = CreateAnswer();
-    ASSERT_NE(nullptr, answer);
-    EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(answer)));
-  }
-
-  void HandleIncomingAnswer(const std::string& msg) {
-    RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingAnswer";
-    std::unique_ptr<SessionDescriptionInterface> desc =
-        webrtc::CreateSessionDescription(SdpType::kAnswer, msg);
-    if (received_sdp_munger_) {
-      received_sdp_munger_(desc->description());
-    }
-
-    EXPECT_TRUE(SetRemoteDescription(std::move(desc)));
-    // Set the RtpReceiverObserver after receivers are created.
-    ResetRtpReceiverObservers();
-  }
-
-  // Returns null on failure.
-  std::unique_ptr<SessionDescriptionInterface> CreateAnswer() {
-    rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer(
-        new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>());
-    pc()->CreateAnswer(observer, offer_answer_options_);
-    return WaitForDescriptionFromObserver(observer);
-  }
-
-  std::unique_ptr<SessionDescriptionInterface> WaitForDescriptionFromObserver(
-      MockCreateSessionDescriptionObserver* observer) {
-    EXPECT_EQ_WAIT(true, observer->called(), kDefaultTimeout);
-    if (!observer->result()) {
-      return nullptr;
-    }
-    auto description = observer->MoveDescription();
-    if (generated_sdp_munger_) {
-      generated_sdp_munger_(description->description());
-    }
-    return description;
-  }
-
-  // Setting the local description and sending the SDP message over the fake
-  // signaling channel are combined into the same method because the SDP
-  // message needs to be sent as soon as SetLocalDescription finishes, without
-  // waiting for the observer to be called. This ensures that ICE candidates
-  // don't outrace the description.
-  bool SetLocalDescriptionAndSendSdpMessage(
-      std::unique_ptr<SessionDescriptionInterface> desc) {
-    rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
-        new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
-    RTC_LOG(LS_INFO) << debug_name_ << ": SetLocalDescriptionAndSendSdpMessage";
-    SdpType type = desc->GetType();
-    std::string sdp;
-    EXPECT_TRUE(desc->ToString(&sdp));
-    RTC_LOG(LS_INFO) << debug_name_ << ": local SDP contents=\n" << sdp;
-    pc()->SetLocalDescription(observer, desc.release());
-    RemoveUnusedVideoRenderers();
-    // As mentioned above, we need to send the message immediately after
-    // SetLocalDescription.
-    SendSdpMessage(type, sdp);
-    EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
-    return true;
-  }
-
-  bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc) {
-    rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
-        new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
-    RTC_LOG(LS_INFO) << debug_name_ << ": SetRemoteDescription";
-    pc()->SetRemoteDescription(observer, desc.release());
-    RemoveUnusedVideoRenderers();
-    EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
-    return observer->result();
-  }
-
-  // This is a work around to remove unused fake_video_renderers from
-  // transceivers that have either stopped or are no longer receiving.
-  void RemoveUnusedVideoRenderers() {
-    if (sdp_semantics_ != SdpSemantics::kUnifiedPlan) {
-      return;
-    }
-    auto transceivers = pc()->GetTransceivers();
-    std::set<std::string> active_renderers;
-    for (auto& transceiver : transceivers) {
-      // Note - we don't check for direction here. This function is called
-      // before direction is set, and in that case, we should not remove
-      // the renderer.
-      if (transceiver->receiver()->media_type() == cricket::MEDIA_TYPE_VIDEO) {
-        active_renderers.insert(transceiver->receiver()->track()->id());
-      }
-    }
-    for (auto it = fake_video_renderers_.begin();
-         it != fake_video_renderers_.end();) {
-      // Remove fake video renderers belonging to any non-active transceivers.
-      if (!active_renderers.count(it->first)) {
-        it = fake_video_renderers_.erase(it);
-      } else {
-        it++;
-      }
-    }
-  }
-
-  // Simulate sending a blob of SDP with delay |signaling_delay_ms_| (0 by
-  // default).
-  void SendSdpMessage(SdpType type, const std::string& msg) {
-    if (signaling_delay_ms_ == 0) {
-      RelaySdpMessageIfReceiverExists(type, msg);
-    } else {
-      invoker_.AsyncInvokeDelayed<void>(
-          RTC_FROM_HERE, rtc::Thread::Current(),
-          [this, type, msg] { RelaySdpMessageIfReceiverExists(type, msg); },
-          signaling_delay_ms_);
-    }
-  }
-
-  void RelaySdpMessageIfReceiverExists(SdpType type, const std::string& msg) {
-    if (signaling_message_receiver_) {
-      signaling_message_receiver_->ReceiveSdpMessage(type, msg);
-    }
-  }
-
-  // Simulate trickling an ICE candidate with delay |signaling_delay_ms_| (0 by
-  // default).
-  void SendIceMessage(const std::string& sdp_mid,
-                      int sdp_mline_index,
-                      const std::string& msg) {
-    if (signaling_delay_ms_ == 0) {
-      RelayIceMessageIfReceiverExists(sdp_mid, sdp_mline_index, msg);
-    } else {
-      invoker_.AsyncInvokeDelayed<void>(
-          RTC_FROM_HERE, rtc::Thread::Current(),
-          [this, sdp_mid, sdp_mline_index, msg] {
-            RelayIceMessageIfReceiverExists(sdp_mid, sdp_mline_index, msg);
-          },
-          signaling_delay_ms_);
-    }
-  }
-
-  void RelayIceMessageIfReceiverExists(const std::string& sdp_mid,
-                                       int sdp_mline_index,
-                                       const std::string& msg) {
-    if (signaling_message_receiver_) {
-      signaling_message_receiver_->ReceiveIceMessage(sdp_mid, sdp_mline_index,
-                                                     msg);
-    }
-  }
-
-  // SignalingMessageReceiver callbacks.
-  void ReceiveSdpMessage(SdpType type, const std::string& msg) override {
-    if (type == SdpType::kOffer) {
-      HandleIncomingOffer(msg);
-    } else {
-      HandleIncomingAnswer(msg);
-    }
-  }
-
-  void ReceiveIceMessage(const std::string& sdp_mid,
-                         int sdp_mline_index,
-                         const std::string& msg) override {
-    RTC_LOG(LS_INFO) << debug_name_ << ": ReceiveIceMessage";
-    std::unique_ptr<webrtc::IceCandidateInterface> candidate(
-        webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, msg, nullptr));
-    EXPECT_TRUE(pc()->AddIceCandidate(candidate.get()));
-  }
-
-  // PeerConnectionObserver callbacks.
-  void OnSignalingChange(
-      webrtc::PeerConnectionInterface::SignalingState new_state) override {
-    EXPECT_EQ(pc()->signaling_state(), new_state);
-    peer_connection_signaling_state_history_.push_back(new_state);
-  }
-  void OnAddTrack(rtc::scoped_refptr<RtpReceiverInterface> receiver,
-                  const std::vector<rtc::scoped_refptr<MediaStreamInterface>>&
-                      streams) override {
-    if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
-      rtc::scoped_refptr<VideoTrackInterface> video_track(
-          static_cast<VideoTrackInterface*>(receiver->track().get()));
-      ASSERT_TRUE(fake_video_renderers_.find(video_track->id()) ==
-                  fake_video_renderers_.end());
-      fake_video_renderers_[video_track->id()] =
-          std::make_unique<FakeVideoTrackRenderer>(video_track);
-    }
-  }
-  void OnRemoveTrack(
-      rtc::scoped_refptr<RtpReceiverInterface> receiver) override {
-    if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
-      auto it = fake_video_renderers_.find(receiver->track()->id());
-      if (it != fake_video_renderers_.end()) {
-        fake_video_renderers_.erase(it);
-      } else {
-        RTC_LOG(LS_ERROR) << "OnRemoveTrack called for non-active renderer";
-      }
-    }
-  }
-  void OnRenegotiationNeeded() override {}
-  void OnIceConnectionChange(
-      webrtc::PeerConnectionInterface::IceConnectionState new_state) override {
-    EXPECT_EQ(pc()->ice_connection_state(), new_state);
-    ice_connection_state_history_.push_back(new_state);
-  }
-  void OnStandardizedIceConnectionChange(
-      webrtc::PeerConnectionInterface::IceConnectionState new_state) override {
-    standardized_ice_connection_state_history_.push_back(new_state);
-  }
-  void OnConnectionChange(
-      webrtc::PeerConnectionInterface::PeerConnectionState new_state) override {
-    peer_connection_state_history_.push_back(new_state);
-  }
-
-  void OnIceGatheringChange(
-      webrtc::PeerConnectionInterface::IceGatheringState new_state) override {
-    EXPECT_EQ(pc()->ice_gathering_state(), new_state);
-    ice_gathering_state_history_.push_back(new_state);
-  }
-
-  void OnIceSelectedCandidatePairChanged(
-      const cricket::CandidatePairChangeEvent& event) {
-    ice_candidate_pair_change_history_.push_back(event);
-  }
-
-  void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override {
-    RTC_LOG(LS_INFO) << debug_name_ << ": OnIceCandidate";
-
-    if (remote_async_resolver_) {
-      const auto& local_candidate = candidate->candidate();
-      if (local_candidate.address().IsUnresolvedIP()) {
-        RTC_DCHECK(local_candidate.type() == cricket::LOCAL_PORT_TYPE);
-        rtc::SocketAddress resolved_addr(local_candidate.address());
-        const auto resolved_ip = mdns_responder_->GetMappedAddressForName(
-            local_candidate.address().hostname());
-        RTC_DCHECK(!resolved_ip.IsNil());
-        resolved_addr.SetResolvedIP(resolved_ip);
-        EXPECT_CALL(*remote_async_resolver_, GetResolvedAddress(_, _))
-            .WillOnce(DoAll(SetArgPointee<1>(resolved_addr), Return(true)));
-        EXPECT_CALL(*remote_async_resolver_, Destroy(_));
-      }
-    }
-
-    std::string ice_sdp;
-    EXPECT_TRUE(candidate->ToString(&ice_sdp));
-    if (signaling_message_receiver_ == nullptr || !signal_ice_candidates_) {
-      // Remote party may be deleted.
-      return;
-    }
-    SendIceMessage(candidate->sdp_mid(), candidate->sdp_mline_index(), ice_sdp);
-    last_candidate_gathered_ = candidate->candidate();
-  }
-  void OnIceCandidateError(const std::string& address,
-                           int port,
-                           const std::string& url,
-                           int error_code,
-                           const std::string& error_text) override {
-    error_event_ = cricket::IceCandidateErrorEvent(address, port, url,
-                                                   error_code, error_text);
-  }
-  void OnDataChannel(
-      rtc::scoped_refptr<DataChannelInterface> data_channel) override {
-    RTC_LOG(LS_INFO) << debug_name_ << ": OnDataChannel";
-    data_channel_ = data_channel;
-    data_observer_.reset(new MockDataChannelObserver(data_channel));
-  }
-
-  std::string debug_name_;
-
-  std::unique_ptr<rtc::FakeNetworkManager> fake_network_manager_;
-  // Reference to the mDNS responder owned by |fake_network_manager_| after set.
-  webrtc::FakeMdnsResponder* mdns_responder_ = nullptr;
-
-  rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
-  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
-      peer_connection_factory_;
-
-  cricket::PortAllocator* port_allocator_;
-  // Needed to keep track of number of frames sent.
-  rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
-  // Needed to keep track of number of frames received.
-  std::map<std::string, std::unique_ptr<webrtc::FakeVideoTrackRenderer>>
-      fake_video_renderers_;
-  // Needed to ensure frames aren't received for removed tracks.
-  std::vector<std::unique_ptr<webrtc::FakeVideoTrackRenderer>>
-      removed_fake_video_renderers_;
-
-  // For remote peer communication.
-  SignalingMessageReceiver* signaling_message_receiver_ = nullptr;
-  int signaling_delay_ms_ = 0;
-  bool signal_ice_candidates_ = true;
-  cricket::Candidate last_candidate_gathered_;
-  cricket::IceCandidateErrorEvent error_event_;
-
-  // Store references to the video sources we've created, so that we can stop
-  // them, if required.
-  std::vector<rtc::scoped_refptr<webrtc::VideoTrackSource>>
-      video_track_sources_;
-  // |local_video_renderer_| attached to the first created local video track.
-  std::unique_ptr<webrtc::FakeVideoTrackRenderer> local_video_renderer_;
-
-  SdpSemantics sdp_semantics_;
-  PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options_;
-  std::function<void(cricket::SessionDescription*)> received_sdp_munger_;
-  std::function<void(cricket::SessionDescription*)> generated_sdp_munger_;
-  std::function<void()> remote_offer_handler_;
-  rtc::MockAsyncResolver* remote_async_resolver_ = nullptr;
-  rtc::scoped_refptr<DataChannelInterface> data_channel_;
-  std::unique_ptr<MockDataChannelObserver> data_observer_;
-
-  std::vector<std::unique_ptr<MockRtpReceiverObserver>> rtp_receiver_observers_;
-
-  std::vector<PeerConnectionInterface::IceConnectionState>
-      ice_connection_state_history_;
-  std::vector<PeerConnectionInterface::IceConnectionState>
-      standardized_ice_connection_state_history_;
-  std::vector<PeerConnectionInterface::PeerConnectionState>
-      peer_connection_state_history_;
-  std::vector<PeerConnectionInterface::IceGatheringState>
-      ice_gathering_state_history_;
-  std::vector<cricket::CandidatePairChangeEvent>
-      ice_candidate_pair_change_history_;
-  std::vector<PeerConnectionInterface::SignalingState>
-      peer_connection_signaling_state_history_;
-  webrtc::FakeRtcEventLogFactory* event_log_factory_;
-
-  // Variables for tracking delay stats on an audio track
-  int audio_packets_stat_ = 0;
-  double audio_delay_stat_ = 0.0;
-  uint64_t audio_samples_stat_ = 0;
-  uint64_t audio_concealed_stat_ = 0;
-  std::string rtp_stats_id_;
-  std::string audio_track_stats_id_;
-
-  rtc::AsyncInvoker invoker_;
-
-  friend class PeerConnectionIntegrationBaseTest;
-};
-
-class MockRtcEventLogOutput : public webrtc::RtcEventLogOutput {
- public:
-  virtual ~MockRtcEventLogOutput() = default;
-  MOCK_METHOD(bool, IsActive, (), (const, override));
-  MOCK_METHOD(bool, Write, (const std::string&), (override));
-};
-
-// This helper object is used for both specifying how many audio/video frames
-// are expected to be received for a caller/callee. It provides helper functions
-// to specify these expectations. The object initially starts in a state of no
-// expectations.
-class MediaExpectations {
- public:
-  enum ExpectFrames {
-    kExpectSomeFrames,
-    kExpectNoFrames,
-    kNoExpectation,
-  };
-
-  void ExpectBidirectionalAudioAndVideo() {
-    ExpectBidirectionalAudio();
-    ExpectBidirectionalVideo();
-  }
-
-  void ExpectBidirectionalAudio() {
-    CallerExpectsSomeAudio();
-    CalleeExpectsSomeAudio();
-  }
-
-  void ExpectNoAudio() {
-    CallerExpectsNoAudio();
-    CalleeExpectsNoAudio();
-  }
-
-  void ExpectBidirectionalVideo() {
-    CallerExpectsSomeVideo();
-    CalleeExpectsSomeVideo();
-  }
-
-  void ExpectNoVideo() {
-    CallerExpectsNoVideo();
-    CalleeExpectsNoVideo();
-  }
-
-  void CallerExpectsSomeAudioAndVideo() {
-    CallerExpectsSomeAudio();
-    CallerExpectsSomeVideo();
-  }
-
-  void CalleeExpectsSomeAudioAndVideo() {
-    CalleeExpectsSomeAudio();
-    CalleeExpectsSomeVideo();
-  }
-
-  // Caller's audio functions.
-  void CallerExpectsSomeAudio(
-      int expected_audio_frames = kDefaultExpectedAudioFrameCount) {
-    caller_audio_expectation_ = kExpectSomeFrames;
-    caller_audio_frames_expected_ = expected_audio_frames;
-  }
-
-  void CallerExpectsNoAudio() {
-    caller_audio_expectation_ = kExpectNoFrames;
-    caller_audio_frames_expected_ = 0;
-  }
-
-  // Caller's video functions.
-  void CallerExpectsSomeVideo(
-      int expected_video_frames = kDefaultExpectedVideoFrameCount) {
-    caller_video_expectation_ = kExpectSomeFrames;
-    caller_video_frames_expected_ = expected_video_frames;
-  }
-
-  void CallerExpectsNoVideo() {
-    caller_video_expectation_ = kExpectNoFrames;
-    caller_video_frames_expected_ = 0;
-  }
-
-  // Callee's audio functions.
-  void CalleeExpectsSomeAudio(
-      int expected_audio_frames = kDefaultExpectedAudioFrameCount) {
-    callee_audio_expectation_ = kExpectSomeFrames;
-    callee_audio_frames_expected_ = expected_audio_frames;
-  }
-
-  void CalleeExpectsNoAudio() {
-    callee_audio_expectation_ = kExpectNoFrames;
-    callee_audio_frames_expected_ = 0;
-  }
-
-  // Callee's video functions.
-  void CalleeExpectsSomeVideo(
-      int expected_video_frames = kDefaultExpectedVideoFrameCount) {
-    callee_video_expectation_ = kExpectSomeFrames;
-    callee_video_frames_expected_ = expected_video_frames;
-  }
-
-  void CalleeExpectsNoVideo() {
-    callee_video_expectation_ = kExpectNoFrames;
-    callee_video_frames_expected_ = 0;
-  }
-
-  ExpectFrames caller_audio_expectation_ = kNoExpectation;
-  ExpectFrames caller_video_expectation_ = kNoExpectation;
-  ExpectFrames callee_audio_expectation_ = kNoExpectation;
-  ExpectFrames callee_video_expectation_ = kNoExpectation;
-  int caller_audio_frames_expected_ = 0;
-  int caller_video_frames_expected_ = 0;
-  int callee_audio_frames_expected_ = 0;
-  int callee_video_frames_expected_ = 0;
-};
-
-class MockIceTransport : public webrtc::IceTransportInterface {
- public:
-  MockIceTransport(const std::string& name, int component)
-      : internal_(std::make_unique<cricket::FakeIceTransport>(
-            name,
-            component,
-            nullptr /* network_thread */)) {}
-  ~MockIceTransport() = default;
-  cricket::IceTransportInternal* internal() { return internal_.get(); }
-
- private:
-  std::unique_ptr<cricket::FakeIceTransport> internal_;
-};
-
-class MockIceTransportFactory : public IceTransportFactory {
- public:
-  ~MockIceTransportFactory() override = default;
-  rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
-      const std::string& transport_name,
-      int component,
-      IceTransportInit init) {
-    RecordIceTransportCreated();
-    return new rtc::RefCountedObject<MockIceTransport>(transport_name,
-                                                       component);
-  }
-  MOCK_METHOD(void, RecordIceTransportCreated, ());
-};
-
-// Tests two PeerConnections connecting to each other end-to-end, using a
-// virtual network, fake A/V capture and fake encoder/decoders. The
-// PeerConnections share the threads/socket servers, but use separate versions
-// of everything else (including "PeerConnectionFactory"s).
-class PeerConnectionIntegrationBaseTest : public ::testing::Test {
- public:
-  explicit PeerConnectionIntegrationBaseTest(SdpSemantics sdp_semantics)
-      : sdp_semantics_(sdp_semantics),
-        ss_(new rtc::VirtualSocketServer()),
-        fss_(new rtc::FirewallSocketServer(ss_.get())),
-        network_thread_(new rtc::Thread(fss_.get())),
-        worker_thread_(rtc::Thread::Create()) {
-    network_thread_->SetName("PCNetworkThread", this);
-    worker_thread_->SetName("PCWorkerThread", this);
-    RTC_CHECK(network_thread_->Start());
-    RTC_CHECK(worker_thread_->Start());
-    webrtc::metrics::Reset();
-  }
-
-  ~PeerConnectionIntegrationBaseTest() {
-    // The PeerConnections should be deleted before the TurnCustomizers.
-    // A TurnPort is created with a raw pointer to a TurnCustomizer. The
-    // TurnPort has the same lifetime as the PeerConnection, so it's expected
-    // that the TurnCustomizer outlives the life of the PeerConnection or else
-    // when Send() is called it will hit a seg fault.
-    if (caller_) {
-      caller_->set_signaling_message_receiver(nullptr);
-      delete SetCallerPcWrapperAndReturnCurrent(nullptr);
-    }
-    if (callee_) {
-      callee_->set_signaling_message_receiver(nullptr);
-      delete SetCalleePcWrapperAndReturnCurrent(nullptr);
-    }
-
-    // If turn servers were created for the test they need to be destroyed on
-    // the network thread.
-    network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
-      turn_servers_.clear();
-      turn_customizers_.clear();
-    });
-  }
-
-  bool SignalingStateStable() {
-    return caller_->SignalingStateStable() && callee_->SignalingStateStable();
-  }
-
-  bool DtlsConnected() {
-    // TODO(deadbeef): kIceConnectionConnected currently means both ICE and DTLS
-    // are connected. This is an important distinction. Once we have separate
-    // ICE and DTLS state, this check needs to use the DTLS state.
-    return (callee()->ice_connection_state() ==
-                webrtc::PeerConnectionInterface::kIceConnectionConnected ||
-            callee()->ice_connection_state() ==
-                webrtc::PeerConnectionInterface::kIceConnectionCompleted) &&
-           (caller()->ice_connection_state() ==
-                webrtc::PeerConnectionInterface::kIceConnectionConnected ||
-            caller()->ice_connection_state() ==
-                webrtc::PeerConnectionInterface::kIceConnectionCompleted);
-  }
-
-  // When |event_log_factory| is null, the default implementation of the event
-  // log factory will be used.
-  std::unique_ptr<PeerConnectionWrapper> CreatePeerConnectionWrapper(
-      const std::string& debug_name,
-      const PeerConnectionFactory::Options* options,
-      const RTCConfiguration* config,
-      webrtc::PeerConnectionDependencies dependencies,
-      std::unique_ptr<webrtc::FakeRtcEventLogFactory> event_log_factory,
-      bool reset_encoder_factory,
-      bool reset_decoder_factory) {
-    RTCConfiguration modified_config;
-    if (config) {
-      modified_config = *config;
-    }
-    modified_config.sdp_semantics = sdp_semantics_;
-    if (!dependencies.cert_generator) {
-      dependencies.cert_generator =
-          std::make_unique<FakeRTCCertificateGenerator>();
-    }
-    std::unique_ptr<PeerConnectionWrapper> client(
-        new PeerConnectionWrapper(debug_name));
-
-    if (!client->Init(options, &modified_config, std::move(dependencies),
-                      network_thread_.get(), worker_thread_.get(),
-                      std::move(event_log_factory), reset_encoder_factory,
-                      reset_decoder_factory)) {
-      return nullptr;
-    }
-    return client;
-  }
-
-  std::unique_ptr<PeerConnectionWrapper>
-  CreatePeerConnectionWrapperWithFakeRtcEventLog(
-      const std::string& debug_name,
-      const PeerConnectionFactory::Options* options,
-      const RTCConfiguration* config,
-      webrtc::PeerConnectionDependencies dependencies) {
-    return CreatePeerConnectionWrapper(
-        debug_name, options, config, std::move(dependencies),
-        std::make_unique<webrtc::FakeRtcEventLogFactory>(),
-        /*reset_encoder_factory=*/false,
-        /*reset_decoder_factory=*/false);
-  }
-
-  bool CreatePeerConnectionWrappers() {
-    return CreatePeerConnectionWrappersWithConfig(
-        PeerConnectionInterface::RTCConfiguration(),
-        PeerConnectionInterface::RTCConfiguration());
-  }
-
-  bool CreatePeerConnectionWrappersWithSdpSemantics(
-      SdpSemantics caller_semantics,
-      SdpSemantics callee_semantics) {
-    // Can't specify the sdp_semantics in the passed-in configuration since it
-    // will be overwritten by CreatePeerConnectionWrapper with whatever is
-    // stored in sdp_semantics_. So get around this by modifying the instance
-    // variable before calling CreatePeerConnectionWrapper for the caller and
-    // callee PeerConnections.
-    SdpSemantics original_semantics = sdp_semantics_;
-    sdp_semantics_ = caller_semantics;
-    caller_ = CreatePeerConnectionWrapper(
-        "Caller", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
-        nullptr,
-        /*reset_encoder_factory=*/false,
-        /*reset_decoder_factory=*/false);
-    sdp_semantics_ = callee_semantics;
-    callee_ = CreatePeerConnectionWrapper(
-        "Callee", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
-        nullptr,
-        /*reset_encoder_factory=*/false,
-        /*reset_decoder_factory=*/false);
-    sdp_semantics_ = original_semantics;
-    return caller_ && callee_;
-  }
-
-  bool CreatePeerConnectionWrappersWithConfig(
-      const PeerConnectionInterface::RTCConfiguration& caller_config,
-      const PeerConnectionInterface::RTCConfiguration& callee_config) {
-    caller_ = CreatePeerConnectionWrapper(
-        "Caller", nullptr, &caller_config,
-        webrtc::PeerConnectionDependencies(nullptr), nullptr,
-        /*reset_encoder_factory=*/false,
-        /*reset_decoder_factory=*/false);
-    callee_ = CreatePeerConnectionWrapper(
-        "Callee", nullptr, &callee_config,
-        webrtc::PeerConnectionDependencies(nullptr), nullptr,
-        /*reset_encoder_factory=*/false,
-        /*reset_decoder_factory=*/false);
-    return caller_ && callee_;
-  }
-
-  bool CreatePeerConnectionWrappersWithConfigAndDeps(
-      const PeerConnectionInterface::RTCConfiguration& caller_config,
-      webrtc::PeerConnectionDependencies caller_dependencies,
-      const PeerConnectionInterface::RTCConfiguration& callee_config,
-      webrtc::PeerConnectionDependencies callee_dependencies) {
-    caller_ =
-        CreatePeerConnectionWrapper("Caller", nullptr, &caller_config,
-                                    std::move(caller_dependencies), nullptr,
-                                    /*reset_encoder_factory=*/false,
-                                    /*reset_decoder_factory=*/false);
-    callee_ =
-        CreatePeerConnectionWrapper("Callee", nullptr, &callee_config,
-                                    std::move(callee_dependencies), nullptr,
-                                    /*reset_encoder_factory=*/false,
-                                    /*reset_decoder_factory=*/false);
-    return caller_ && callee_;
-  }
-
-  bool CreatePeerConnectionWrappersWithOptions(
-      const PeerConnectionFactory::Options& caller_options,
-      const PeerConnectionFactory::Options& callee_options) {
-    caller_ = CreatePeerConnectionWrapper(
-        "Caller", &caller_options, nullptr,
-        webrtc::PeerConnectionDependencies(nullptr), nullptr,
-        /*reset_encoder_factory=*/false,
-        /*reset_decoder_factory=*/false);
-    callee_ = CreatePeerConnectionWrapper(
-        "Callee", &callee_options, nullptr,
-        webrtc::PeerConnectionDependencies(nullptr), nullptr,
-        /*reset_encoder_factory=*/false,
-        /*reset_decoder_factory=*/false);
-    return caller_ && callee_;
-  }
-
-  bool CreatePeerConnectionWrappersWithFakeRtcEventLog() {
-    PeerConnectionInterface::RTCConfiguration default_config;
-    caller_ = CreatePeerConnectionWrapperWithFakeRtcEventLog(
-        "Caller", nullptr, &default_config,
-        webrtc::PeerConnectionDependencies(nullptr));
-    callee_ = CreatePeerConnectionWrapperWithFakeRtcEventLog(
-        "Callee", nullptr, &default_config,
-        webrtc::PeerConnectionDependencies(nullptr));
-    return caller_ && callee_;
-  }
-
-  std::unique_ptr<PeerConnectionWrapper>
-  CreatePeerConnectionWrapperWithAlternateKey() {
-    std::unique_ptr<FakeRTCCertificateGenerator> cert_generator(
-        new FakeRTCCertificateGenerator());
-    cert_generator->use_alternate_key();
-
-    webrtc::PeerConnectionDependencies dependencies(nullptr);
-    dependencies.cert_generator = std::move(cert_generator);
-    return CreatePeerConnectionWrapper("New Peer", nullptr, nullptr,
-                                       std::move(dependencies), nullptr,
-                                       /*reset_encoder_factory=*/false,
-                                       /*reset_decoder_factory=*/false);
-  }
-
-  bool CreateOneDirectionalPeerConnectionWrappers(bool caller_to_callee) {
-    caller_ = CreatePeerConnectionWrapper(
-        "Caller", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
-        nullptr,
-        /*reset_encoder_factory=*/!caller_to_callee,
-        /*reset_decoder_factory=*/caller_to_callee);
-    callee_ = CreatePeerConnectionWrapper(
-        "Callee", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
-        nullptr,
-        /*reset_encoder_factory=*/caller_to_callee,
-        /*reset_decoder_factory=*/!caller_to_callee);
-    return caller_ && callee_;
-  }
-
-  cricket::TestTurnServer* CreateTurnServer(
-      rtc::SocketAddress internal_address,
-      rtc::SocketAddress external_address,
-      cricket::ProtocolType type = cricket::ProtocolType::PROTO_UDP,
-      const std::string& common_name = "test turn server") {
-    rtc::Thread* thread = network_thread();
-    std::unique_ptr<cricket::TestTurnServer> turn_server =
-        network_thread()->Invoke<std::unique_ptr<cricket::TestTurnServer>>(
-            RTC_FROM_HERE,
-            [thread, internal_address, external_address, type, common_name] {
-              return std::make_unique<cricket::TestTurnServer>(
-                  thread, internal_address, external_address, type,
-                  /*ignore_bad_certs=*/true, common_name);
-            });
-    turn_servers_.push_back(std::move(turn_server));
-    // Interactions with the turn server should be done on the network thread.
-    return turn_servers_.back().get();
-  }
-
-  cricket::TestTurnCustomizer* CreateTurnCustomizer() {
-    std::unique_ptr<cricket::TestTurnCustomizer> turn_customizer =
-        network_thread()->Invoke<std::unique_ptr<cricket::TestTurnCustomizer>>(
-            RTC_FROM_HERE,
-            [] { return std::make_unique<cricket::TestTurnCustomizer>(); });
-    turn_customizers_.push_back(std::move(turn_customizer));
-    // Interactions with the turn customizer should be done on the network
-    // thread.
-    return turn_customizers_.back().get();
-  }
-
-  // Checks that the function counters for a TestTurnCustomizer are greater than
-  // 0.
-  void ExpectTurnCustomizerCountersIncremented(
-      cricket::TestTurnCustomizer* turn_customizer) {
-    unsigned int allow_channel_data_counter =
-        network_thread()->Invoke<unsigned int>(
-            RTC_FROM_HERE, [turn_customizer] {
-              return turn_customizer->allow_channel_data_cnt_;
-            });
-    EXPECT_GT(allow_channel_data_counter, 0u);
-    unsigned int modify_counter = network_thread()->Invoke<unsigned int>(
-        RTC_FROM_HERE,
-        [turn_customizer] { return turn_customizer->modify_cnt_; });
-    EXPECT_GT(modify_counter, 0u);
-  }
-
-  // Once called, SDP blobs and ICE candidates will be automatically signaled
-  // between PeerConnections.
-  void ConnectFakeSignaling() {
-    caller_->set_signaling_message_receiver(callee_.get());
-    callee_->set_signaling_message_receiver(caller_.get());
-  }
-
-  // Once called, SDP blobs will be automatically signaled between
-  // PeerConnections. Note that ICE candidates will not be signaled unless they
-  // are in the exchanged SDP blobs.
-  void ConnectFakeSignalingForSdpOnly() {
-    ConnectFakeSignaling();
-    SetSignalIceCandidates(false);
-  }
-
-  void SetSignalingDelayMs(int delay_ms) {
-    caller_->set_signaling_delay_ms(delay_ms);
-    callee_->set_signaling_delay_ms(delay_ms);
-  }
-
-  void SetSignalIceCandidates(bool signal) {
-    caller_->set_signal_ice_candidates(signal);
-    callee_->set_signal_ice_candidates(signal);
-  }
-
-  // Messages may get lost on the unreliable DataChannel, so we send multiple
-  // times to avoid test flakiness.
-  void SendRtpDataWithRetries(webrtc::DataChannelInterface* dc,
-                              const std::string& data,
-                              int retries) {
-    for (int i = 0; i < retries; ++i) {
-      dc->Send(DataBuffer(data));
-    }
-  }
-
-  rtc::Thread* network_thread() { return network_thread_.get(); }
-
-  rtc::VirtualSocketServer* virtual_socket_server() { return ss_.get(); }
-
-  PeerConnectionWrapper* caller() { return caller_.get(); }
-
-  // Set the |caller_| to the |wrapper| passed in and return the
-  // original |caller_|.
-  PeerConnectionWrapper* SetCallerPcWrapperAndReturnCurrent(
-      PeerConnectionWrapper* wrapper) {
-    PeerConnectionWrapper* old = caller_.release();
-    caller_.reset(wrapper);
-    return old;
-  }
-
-  PeerConnectionWrapper* callee() { return callee_.get(); }
-
-  // Set the |callee_| to the |wrapper| passed in and return the
-  // original |callee_|.
-  PeerConnectionWrapper* SetCalleePcWrapperAndReturnCurrent(
-      PeerConnectionWrapper* wrapper) {
-    PeerConnectionWrapper* old = callee_.release();
-    callee_.reset(wrapper);
-    return old;
-  }
-
-  void SetPortAllocatorFlags(uint32_t caller_flags, uint32_t callee_flags) {
-    network_thread()->Invoke<void>(RTC_FROM_HERE, [this, caller_flags] {
-      caller()->port_allocator()->set_flags(caller_flags);
-    });
-    network_thread()->Invoke<void>(RTC_FROM_HERE, [this, callee_flags] {
-      callee()->port_allocator()->set_flags(callee_flags);
-    });
-  }
-
-  rtc::FirewallSocketServer* firewall() const { return fss_.get(); }
-
-  // Expects the provided number of new frames to be received within
-  // kMaxWaitForFramesMs. The new expected frames are specified in
-  // |media_expectations|. Returns false if any of the expectations were
-  // not met.
-  bool ExpectNewFrames(const MediaExpectations& media_expectations) {
-    // Make sure there are no bogus tracks confusing the issue.
-    caller()->RemoveUnusedVideoRenderers();
-    callee()->RemoveUnusedVideoRenderers();
-    // First initialize the expected frame counts based upon the current
-    // frame count.
-    int total_caller_audio_frames_expected = caller()->audio_frames_received();
-    if (media_expectations.caller_audio_expectation_ ==
-        MediaExpectations::kExpectSomeFrames) {
-      total_caller_audio_frames_expected +=
-          media_expectations.caller_audio_frames_expected_;
-    }
-    int total_caller_video_frames_expected =
-        caller()->min_video_frames_received_per_track();
-    if (media_expectations.caller_video_expectation_ ==
-        MediaExpectations::kExpectSomeFrames) {
-      total_caller_video_frames_expected +=
-          media_expectations.caller_video_frames_expected_;
-    }
-    int total_callee_audio_frames_expected = callee()->audio_frames_received();
-    if (media_expectations.callee_audio_expectation_ ==
-        MediaExpectations::kExpectSomeFrames) {
-      total_callee_audio_frames_expected +=
-          media_expectations.callee_audio_frames_expected_;
-    }
-    int total_callee_video_frames_expected =
-        callee()->min_video_frames_received_per_track();
-    if (media_expectations.callee_video_expectation_ ==
-        MediaExpectations::kExpectSomeFrames) {
-      total_callee_video_frames_expected +=
-          media_expectations.callee_video_frames_expected_;
-    }
-
-    // Wait for the expected frames.
-    EXPECT_TRUE_WAIT(caller()->audio_frames_received() >=
-                             total_caller_audio_frames_expected &&
-                         caller()->min_video_frames_received_per_track() >=
-                             total_caller_video_frames_expected &&
-                         callee()->audio_frames_received() >=
-                             total_callee_audio_frames_expected &&
-                         callee()->min_video_frames_received_per_track() >=
-                             total_callee_video_frames_expected,
-                     kMaxWaitForFramesMs);
-    bool expectations_correct =
-        caller()->audio_frames_received() >=
-            total_caller_audio_frames_expected &&
-        caller()->min_video_frames_received_per_track() >=
-            total_caller_video_frames_expected &&
-        callee()->audio_frames_received() >=
-            total_callee_audio_frames_expected &&
-        callee()->min_video_frames_received_per_track() >=
-            total_callee_video_frames_expected;
-
-    // After the combined wait, print out a more detailed message upon
-    // failure.
-    EXPECT_GE(caller()->audio_frames_received(),
-              total_caller_audio_frames_expected);
-    EXPECT_GE(caller()->min_video_frames_received_per_track(),
-              total_caller_video_frames_expected);
-    EXPECT_GE(callee()->audio_frames_received(),
-              total_callee_audio_frames_expected);
-    EXPECT_GE(callee()->min_video_frames_received_per_track(),
-              total_callee_video_frames_expected);
-
-    // We want to make sure nothing unexpected was received.
-    if (media_expectations.caller_audio_expectation_ ==
-        MediaExpectations::kExpectNoFrames) {
-      EXPECT_EQ(caller()->audio_frames_received(),
-                total_caller_audio_frames_expected);
-      if (caller()->audio_frames_received() !=
-          total_caller_audio_frames_expected) {
-        expectations_correct = false;
-      }
-    }
-    if (media_expectations.caller_video_expectation_ ==
-        MediaExpectations::kExpectNoFrames) {
-      EXPECT_EQ(caller()->min_video_frames_received_per_track(),
-                total_caller_video_frames_expected);
-      if (caller()->min_video_frames_received_per_track() !=
-          total_caller_video_frames_expected) {
-        expectations_correct = false;
-      }
-    }
-    if (media_expectations.callee_audio_expectation_ ==
-        MediaExpectations::kExpectNoFrames) {
-      EXPECT_EQ(callee()->audio_frames_received(),
-                total_callee_audio_frames_expected);
-      if (callee()->audio_frames_received() !=
-          total_callee_audio_frames_expected) {
-        expectations_correct = false;
-      }
-    }
-    if (media_expectations.callee_video_expectation_ ==
-        MediaExpectations::kExpectNoFrames) {
-      EXPECT_EQ(callee()->min_video_frames_received_per_track(),
-                total_callee_video_frames_expected);
-      if (callee()->min_video_frames_received_per_track() !=
-          total_callee_video_frames_expected) {
-        expectations_correct = false;
-      }
-    }
-    return expectations_correct;
-  }
-
-  void ClosePeerConnections() {
-    caller()->pc()->Close();
-    callee()->pc()->Close();
-  }
-
-  void TestNegotiatedCipherSuite(
-      const PeerConnectionFactory::Options& caller_options,
-      const PeerConnectionFactory::Options& callee_options,
-      int expected_cipher_suite) {
-    ASSERT_TRUE(CreatePeerConnectionWrappersWithOptions(caller_options,
-                                                        callee_options));
-    ConnectFakeSignaling();
-    caller()->AddAudioVideoTracks();
-    callee()->AddAudioVideoTracks();
-    caller()->CreateAndSetAndSignalOffer();
-    ASSERT_TRUE_WAIT(DtlsConnected(), kDefaultTimeout);
-    EXPECT_EQ_WAIT(rtc::SrtpCryptoSuiteToName(expected_cipher_suite),
-                   caller()->OldGetStats()->SrtpCipher(), kDefaultTimeout);
-    // TODO(bugs.webrtc.org/9456): Fix it.
-    EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(
-                            "WebRTC.PeerConnection.SrtpCryptoSuite.Audio",
-                            expected_cipher_suite));
-  }
-
-  void TestGcmNegotiationUsesCipherSuite(bool local_gcm_enabled,
-                                         bool remote_gcm_enabled,
-                                         bool aes_ctr_enabled,
-                                         int expected_cipher_suite) {
-    PeerConnectionFactory::Options caller_options;
-    caller_options.crypto_options.srtp.enable_gcm_crypto_suites =
-        local_gcm_enabled;
-    caller_options.crypto_options.srtp.enable_aes128_sha1_80_crypto_cipher =
-        aes_ctr_enabled;
-    PeerConnectionFactory::Options callee_options;
-    callee_options.crypto_options.srtp.enable_gcm_crypto_suites =
-        remote_gcm_enabled;
-    callee_options.crypto_options.srtp.enable_aes128_sha1_80_crypto_cipher =
-        aes_ctr_enabled;
-    TestNegotiatedCipherSuite(caller_options, callee_options,
-                              expected_cipher_suite);
-  }
-
- protected:
-  SdpSemantics sdp_semantics_;
-
- private:
-  // |ss_| is used by |network_thread_| so it must be destroyed later.
-  std::unique_ptr<rtc::VirtualSocketServer> ss_;
-  std::unique_ptr<rtc::FirewallSocketServer> fss_;
-  // |network_thread_| and |worker_thread_| are used by both
-  // |caller_| and |callee_| so they must be destroyed
-  // later.
-  std::unique_ptr<rtc::Thread> network_thread_;
-  std::unique_ptr<rtc::Thread> worker_thread_;
-  // The turn servers and turn customizers should be accessed & deleted on the
-  // network thread to avoid a race with the socket read/write that occurs
-  // on the network thread.
-  std::vector<std::unique_ptr<cricket::TestTurnServer>> turn_servers_;
-  std::vector<std::unique_ptr<cricket::TestTurnCustomizer>> turn_customizers_;
-  std::unique_ptr<PeerConnectionWrapper> caller_;
-  std::unique_ptr<PeerConnectionWrapper> callee_;
-};
-
 class PeerConnectionIntegrationTest
     : public PeerConnectionIntegrationBaseTest,
       public ::testing::WithParamInterface<SdpSemantics> {
@@ -1934,8 +205,8 @@
 
 // Assumes |sender| already has an audio track added and the offer/answer
 // exchange is done.
-void TestDtmfFromSenderToReceiver(PeerConnectionWrapper* sender,
-                                  PeerConnectionWrapper* receiver) {
+void TestDtmfFromSenderToReceiver(PeerConnectionIntegrationWrapper* sender,
+                                  PeerConnectionIntegrationWrapper* receiver) {
   // We should be able to get a DTMF sender from the local sender.
   rtc::scoped_refptr<DtmfSenderInterface> dtmf_sender =
       sender->pc()->GetSenders().at(0)->GetDtmfSender();
@@ -2348,7 +619,7 @@
 
   // Keep the original peer around which will still send packets to the
   // receiving client. These SRTP packets will be dropped.
-  std::unique_ptr<PeerConnectionWrapper> original_peer(
+  std::unique_ptr<PeerConnectionIntegrationWrapper> original_peer(
       SetCallerPcWrapperAndReturnCurrent(
           CreatePeerConnectionWrapperWithAlternateKey().release()));
   // TODO(deadbeef): Why do we call Close here? That goes against the comment
@@ -2377,7 +648,7 @@
 
   // Keep the original peer around which will still send packets to the
   // receiving client. These SRTP packets will be dropped.
-  std::unique_ptr<PeerConnectionWrapper> original_peer(
+  std::unique_ptr<PeerConnectionIntegrationWrapper> original_peer(
       SetCalleePcWrapperAndReturnCurrent(
           CreatePeerConnectionWrapperWithAlternateKey().release()));
   // TODO(deadbeef): Why do we call Close here? That goes against the comment
@@ -2395,71 +666,6 @@
   ASSERT_TRUE(ExpectNewFrames(media_expectations));
 }
 
-#ifdef WEBRTC_HAVE_SCTP
-
-// This test causes a PeerConnection to enter Disconnected state, and
-// sends data on a DataChannel while disconnected.
-// The data should be surfaced when the connection reestablishes.
-TEST_P(PeerConnectionIntegrationTest, DataChannelWhileDisconnected) {
-  CreatePeerConnectionWrappers();
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
-  std::string data1 = "hello first";
-  caller()->data_channel()->Send(DataBuffer(data1));
-  EXPECT_EQ_WAIT(data1, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-  // Cause a network outage
-  virtual_socket_server()->set_drop_probability(1.0);
-  EXPECT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
-                 caller()->standardized_ice_connection_state(),
-                 kDefaultTimeout);
-  std::string data2 = "hello second";
-  caller()->data_channel()->Send(DataBuffer(data2));
-  // Remove the network outage. The connection should reestablish.
-  virtual_socket_server()->set_drop_probability(0.0);
-  EXPECT_EQ_WAIT(data2, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-// This test causes a PeerConnection to enter Disconnected state,
-// sends data on a DataChannel while disconnected, and then triggers
-// an ICE restart.
-// The data should be surfaced when the connection reestablishes.
-TEST_P(PeerConnectionIntegrationTest, DataChannelWhileDisconnectedIceRestart) {
-  CreatePeerConnectionWrappers();
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
-  std::string data1 = "hello first";
-  caller()->data_channel()->Send(DataBuffer(data1));
-  EXPECT_EQ_WAIT(data1, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-  // Cause a network outage
-  virtual_socket_server()->set_drop_probability(1.0);
-  ASSERT_EQ_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
-                 caller()->standardized_ice_connection_state(),
-                 kDefaultTimeout);
-  std::string data2 = "hello second";
-  caller()->data_channel()->Send(DataBuffer(data2));
-
-  // Trigger an ICE restart. The signaling channel is not affected by
-  // the network outage.
-  caller()->SetOfferAnswerOptions(IceRestartOfferAnswerOptions());
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // Remove the network outage. The connection should reestablish.
-  virtual_socket_server()->set_drop_probability(0.0);
-  EXPECT_EQ_WAIT(data2, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-#endif  // WEBRTC_HAVE_SCTP
-
 // This test sets up a non-bundled call and negotiates bundling at the same
 // time as starting an ICE restart. When bundling is in effect in the restart,
 // the DTLS-SRTP context should be successfully reset.
@@ -3626,429 +1832,6 @@
   ASSERT_TRUE(ExpectNewFrames(media_expectations));
 }
 
-// This test sets up a call between two parties with audio, video and an RTP
-// data channel.
-TEST_P(PeerConnectionIntegrationTest, EndToEndCallWithRtpDataChannel) {
-  PeerConnectionInterface::RTCConfiguration rtc_config;
-  rtc_config.enable_rtp_data_channel = true;
-  rtc_config.enable_dtls_srtp = false;
-  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
-  ConnectFakeSignaling();
-  // Expect that data channel created on caller side will show up for callee as
-  // well.
-  caller()->CreateDataChannel();
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // Ensure the existence of the RTP data channel didn't impede audio/video.
-  MediaExpectations media_expectations;
-  media_expectations.ExpectBidirectionalAudioAndVideo();
-  ASSERT_TRUE(ExpectNewFrames(media_expectations));
-  ASSERT_NE(nullptr, caller()->data_channel());
-  ASSERT_NE(nullptr, callee()->data_channel());
-  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-
-  // Ensure data can be sent in both directions.
-  std::string data = "hello world";
-  SendRtpDataWithRetries(caller()->data_channel(), data, 5);
-  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-  SendRtpDataWithRetries(callee()->data_channel(), data, 5);
-  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-TEST_P(PeerConnectionIntegrationTest, RtpDataChannelWorksAfterRollback) {
-  PeerConnectionInterface::RTCConfiguration rtc_config;
-  rtc_config.enable_rtp_data_channel = true;
-  rtc_config.enable_dtls_srtp = false;
-  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
-  ConnectFakeSignaling();
-  auto data_channel = caller()->pc()->CreateDataChannel("label_1", nullptr);
-  ASSERT_TRUE(data_channel.get() != nullptr);
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-
-  caller()->CreateDataChannel("label_2", nullptr);
-  rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
-      new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
-  caller()->pc()->SetLocalDescription(observer,
-                                      caller()->CreateOfferAndWait().release());
-  EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
-  caller()->Rollback();
-
-  std::string data = "hello world";
-  SendRtpDataWithRetries(data_channel, data, 5);
-  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-// Ensure that an RTP data channel is signaled as closed for the caller when
-// the callee rejects it in a subsequent offer.
-TEST_P(PeerConnectionIntegrationTest,
-       RtpDataChannelSignaledClosedInCalleeOffer) {
-  // Same procedure as above test.
-  PeerConnectionInterface::RTCConfiguration rtc_config;
-  rtc_config.enable_rtp_data_channel = true;
-  rtc_config.enable_dtls_srtp = false;
-  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_NE(nullptr, caller()->data_channel());
-  ASSERT_NE(nullptr, callee()->data_channel());
-  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-
-  // Close the data channel on the callee, and do an updated offer/answer.
-  callee()->data_channel()->Close();
-  callee()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  EXPECT_FALSE(caller()->data_observer()->IsOpen());
-  EXPECT_FALSE(callee()->data_observer()->IsOpen());
-}
-
-#if !defined(THREAD_SANITIZER)
-// This test provokes TSAN errors. See bugs.webrtc.org/11282
-
-// Tests that data is buffered in an RTP data channel until an observer is
-// registered for it.
-//
-// NOTE: RTP data channels can receive data before the underlying
-// transport has detected that a channel is writable and thus data can be
-// received before the data channel state changes to open. That is hard to test
-// but the same buffering is expected to be used in that case.
-//
-// Use fake clock and simulated network delay so that we predictably can wait
-// until an SCTP message has been delivered without "sleep()"ing.
-TEST_P(PeerConnectionIntegrationTestWithFakeClock,
-       DataBufferedUntilRtpDataChannelObserverRegistered) {
-  virtual_socket_server()->set_delay_mean(5);  // 5 ms per hop.
-  virtual_socket_server()->UpdateDelayDistribution();
-
-  PeerConnectionInterface::RTCConfiguration rtc_config;
-  rtc_config.enable_rtp_data_channel = true;
-  rtc_config.enable_dtls_srtp = false;
-  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE(caller()->data_channel() != nullptr);
-  ASSERT_TRUE_SIMULATED_WAIT(callee()->data_channel() != nullptr,
-                             kDefaultTimeout, FakeClock());
-  ASSERT_TRUE_SIMULATED_WAIT(caller()->data_observer()->IsOpen(),
-                             kDefaultTimeout, FakeClock());
-  ASSERT_EQ_SIMULATED_WAIT(DataChannelInterface::kOpen,
-                           callee()->data_channel()->state(), kDefaultTimeout,
-                           FakeClock());
-
-  // Unregister the observer which is normally automatically registered.
-  callee()->data_channel()->UnregisterObserver();
-  // Send data and advance fake clock until it should have been received.
-  std::string data = "hello world";
-  caller()->data_channel()->Send(DataBuffer(data));
-  SIMULATED_WAIT(false, 50, FakeClock());
-
-  // Attach data channel and expect data to be received immediately. Note that
-  // EXPECT_EQ_WAIT is used, such that the simulated clock is not advanced any
-  // further, but data can be received even if the callback is asynchronous.
-  MockDataChannelObserver new_observer(callee()->data_channel());
-  EXPECT_EQ_SIMULATED_WAIT(data, new_observer.last_message(), kDefaultTimeout,
-                           FakeClock());
-}
-
-#endif  // !defined(THREAD_SANITIZER)
-
-// This test sets up a call between two parties with audio, video and but only
-// the caller client supports RTP data channels.
-TEST_P(PeerConnectionIntegrationTest, RtpDataChannelsRejectedByCallee) {
-  PeerConnectionInterface::RTCConfiguration rtc_config_1;
-  rtc_config_1.enable_rtp_data_channel = true;
-  // Must disable DTLS to make negotiation succeed.
-  rtc_config_1.enable_dtls_srtp = false;
-  PeerConnectionInterface::RTCConfiguration rtc_config_2;
-  rtc_config_2.enable_dtls_srtp = false;
-  rtc_config_2.enable_dtls_srtp = false;
-  ASSERT_TRUE(
-      CreatePeerConnectionWrappersWithConfig(rtc_config_1, rtc_config_2));
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  ASSERT_TRUE(caller()->data_channel() != nullptr);
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // The caller should still have a data channel, but it should be closed, and
-  // one should ever have been created for the callee.
-  EXPECT_TRUE(caller()->data_channel() != nullptr);
-  EXPECT_FALSE(caller()->data_observer()->IsOpen());
-  EXPECT_EQ(nullptr, callee()->data_channel());
-}
-
-// This test sets up a call between two parties with audio, and video. When
-// audio and video is setup and flowing, an RTP data channel is negotiated.
-TEST_P(PeerConnectionIntegrationTest, AddRtpDataChannelInSubsequentOffer) {
-  PeerConnectionInterface::RTCConfiguration rtc_config;
-  rtc_config.enable_rtp_data_channel = true;
-  rtc_config.enable_dtls_srtp = false;
-  ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(rtc_config, rtc_config));
-  ConnectFakeSignaling();
-  // Do initial offer/answer with audio/video.
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // Create data channel and do new offer and answer.
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_NE(nullptr, caller()->data_channel());
-  ASSERT_NE(nullptr, callee()->data_channel());
-  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-  // Ensure data can be sent in both directions.
-  std::string data = "hello world";
-  SendRtpDataWithRetries(caller()->data_channel(), data, 5);
-  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-  SendRtpDataWithRetries(callee()->data_channel(), data, 5);
-  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-#ifdef WEBRTC_HAVE_SCTP
-
-// This test sets up a call between two parties with audio, video and an SCTP
-// data channel.
-TEST_P(PeerConnectionIntegrationTest, EndToEndCallWithSctpDataChannel) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  // Expect that data channel created on caller side will show up for callee as
-  // well.
-  caller()->CreateDataChannel();
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // Ensure the existence of the SCTP data channel didn't impede audio/video.
-  MediaExpectations media_expectations;
-  media_expectations.ExpectBidirectionalAudioAndVideo();
-  ASSERT_TRUE(ExpectNewFrames(media_expectations));
-  // Caller data channel should already exist (it created one). Callee data
-  // channel may not exist yet, since negotiation happens in-band, not in SDP.
-  ASSERT_NE(nullptr, caller()->data_channel());
-  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
-  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-
-  // Ensure data can be sent in both directions.
-  std::string data = "hello world";
-  caller()->data_channel()->Send(DataBuffer(data));
-  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-  callee()->data_channel()->Send(DataBuffer(data));
-  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-// Ensure that when the callee closes an SCTP data channel, the closing
-// procedure results in the data channel being closed for the caller as well.
-TEST_P(PeerConnectionIntegrationTest, CalleeClosesSctpDataChannel) {
-  // Same procedure as above test.
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_NE(nullptr, caller()->data_channel());
-  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
-  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-
-  // Close the data channel on the callee side, and wait for it to reach the
-  // "closed" state on both sides.
-  callee()->data_channel()->Close();
-  EXPECT_TRUE_WAIT(!caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  EXPECT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
-}
-
-TEST_P(PeerConnectionIntegrationTest, SctpDataChannelConfigSentToOtherSide) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  webrtc::DataChannelInit init;
-  init.id = 53;
-  init.maxRetransmits = 52;
-  caller()->CreateDataChannel("data-channel", &init);
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-  // Since "negotiated" is false, the "id" parameter should be ignored.
-  EXPECT_NE(init.id, callee()->data_channel()->id());
-  EXPECT_EQ("data-channel", callee()->data_channel()->label());
-  EXPECT_EQ(init.maxRetransmits, callee()->data_channel()->maxRetransmits());
-  EXPECT_FALSE(callee()->data_channel()->negotiated());
-}
-
-// Test usrsctp's ability to process unordered data stream, where data actually
-// arrives out of order using simulated delays. Previously there have been some
-// bugs in this area.
-TEST_P(PeerConnectionIntegrationTest, StressTestUnorderedSctpDataChannel) {
-  // Introduce random network delays.
-  // Otherwise it's not a true "unordered" test.
-  virtual_socket_server()->set_delay_mean(20);
-  virtual_socket_server()->set_delay_stddev(5);
-  virtual_socket_server()->UpdateDelayDistribution();
-  // Normal procedure, but with unordered data channel config.
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  webrtc::DataChannelInit init;
-  init.ordered = false;
-  caller()->CreateDataChannel(&init);
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_NE(nullptr, caller()->data_channel());
-  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
-  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-
-  static constexpr int kNumMessages = 100;
-  // Deliberately chosen to be larger than the MTU so messages get fragmented.
-  static constexpr size_t kMaxMessageSize = 4096;
-  // Create and send random messages.
-  std::vector<std::string> sent_messages;
-  for (int i = 0; i < kNumMessages; ++i) {
-    size_t length =
-        (rand() % kMaxMessageSize) + 1;  // NOLINT (rand_r instead of rand)
-    std::string message;
-    ASSERT_TRUE(rtc::CreateRandomString(length, &message));
-    caller()->data_channel()->Send(DataBuffer(message));
-    callee()->data_channel()->Send(DataBuffer(message));
-    sent_messages.push_back(message);
-  }
-
-  // Wait for all messages to be received.
-  EXPECT_EQ_WAIT(rtc::checked_cast<size_t>(kNumMessages),
-                 caller()->data_observer()->received_message_count(),
-                 kDefaultTimeout);
-  EXPECT_EQ_WAIT(rtc::checked_cast<size_t>(kNumMessages),
-                 callee()->data_observer()->received_message_count(),
-                 kDefaultTimeout);
-
-  // Sort and compare to make sure none of the messages were corrupted.
-  std::vector<std::string> caller_received_messages =
-      caller()->data_observer()->messages();
-  std::vector<std::string> callee_received_messages =
-      callee()->data_observer()->messages();
-  absl::c_sort(sent_messages);
-  absl::c_sort(caller_received_messages);
-  absl::c_sort(callee_received_messages);
-  EXPECT_EQ(sent_messages, caller_received_messages);
-  EXPECT_EQ(sent_messages, callee_received_messages);
-}
-
-// This test sets up a call between two parties with audio, and video. When
-// audio and video are setup and flowing, an SCTP data channel is negotiated.
-TEST_P(PeerConnectionIntegrationTest, AddSctpDataChannelInSubsequentOffer) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  // Do initial offer/answer with audio/video.
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // Create data channel and do new offer and answer.
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // Caller data channel should already exist (it created one). Callee data
-  // channel may not exist yet, since negotiation happens in-band, not in SDP.
-  ASSERT_NE(nullptr, caller()->data_channel());
-  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
-  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-  // Ensure data can be sent in both directions.
-  std::string data = "hello world";
-  caller()->data_channel()->Send(DataBuffer(data));
-  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-  callee()->data_channel()->Send(DataBuffer(data));
-  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-// Set up a connection initially just using SCTP data channels, later upgrading
-// to audio/video, ensuring frames are received end-to-end. Effectively the
-// inverse of the test above.
-// This was broken in M57; see https://crbug.com/711243
-TEST_P(PeerConnectionIntegrationTest, SctpDataChannelToAudioVideoUpgrade) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  // Do initial offer/answer with just data channel.
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  // Wait until data can be sent over the data channel.
-  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
-  ASSERT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-
-  // Do subsequent offer/answer with two-way audio and video. Audio and video
-  // should end up bundled on the DTLS/ICE transport already used for data.
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  MediaExpectations media_expectations;
-  media_expectations.ExpectBidirectionalAudioAndVideo();
-  ASSERT_TRUE(ExpectNewFrames(media_expectations));
-}
-
-static void MakeSpecCompliantSctpOffer(cricket::SessionDescription* desc) {
-  cricket::SctpDataContentDescription* dcd_offer =
-      GetFirstSctpDataContentDescription(desc);
-  // See https://crbug.com/webrtc/11211 - this function is a no-op
-  ASSERT_TRUE(dcd_offer);
-  dcd_offer->set_use_sctpmap(false);
-  dcd_offer->set_protocol("UDP/DTLS/SCTP");
-}
-
-// Test that the data channel works when a spec-compliant SCTP m= section is
-// offered (using "a=sctp-port" instead of "a=sctpmap", and using
-// "UDP/DTLS/SCTP" as the protocol).
-TEST_P(PeerConnectionIntegrationTest,
-       DataChannelWorksWhenSpecCompliantSctpOfferReceived) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->SetGeneratedSdpMunger(MakeSpecCompliantSctpOffer);
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
-  EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
-  EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-
-  // Ensure data can be sent in both directions.
-  std::string data = "hello world";
-  caller()->data_channel()->Send(DataBuffer(data));
-  EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
-                 kDefaultTimeout);
-  callee()->data_channel()->Send(DataBuffer(data));
-  EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
-                 kDefaultTimeout);
-}
-
-#endif  // WEBRTC_HAVE_SCTP
-
 // Test that the ICE connection and gathering states eventually reach
 // "complete".
 TEST_P(PeerConnectionIntegrationTest, IceStatesReachCompletion) {
@@ -5245,7 +3028,7 @@
   ASSERT_TRUE(ExpectNewFrames(media_expectations));
 }
 
-double GetAudioEnergyStat(PeerConnectionWrapper* pc) {
+double GetAudioEnergyStat(PeerConnectionIntegrationWrapper* pc) {
   auto report = pc->NewGetStats();
   auto track_stats_list =
       report->GetStatsOfType<webrtc::RTCMediaStreamTrackStats>();
@@ -5317,51 +3100,6 @@
   ASSERT_TRUE(ExpectNewFrames(media_expectations));
 }
 
-// Test that after closing PeerConnections, they stop sending any packets (ICE,
-// DTLS, RTP...).
-TEST_P(PeerConnectionIntegrationTest, ClosingConnectionStopsPacketFlow) {
-  // Set up audio/video/data, wait for some frames to be received.
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->AddAudioVideoTracks();
-#ifdef WEBRTC_HAVE_SCTP
-  caller()->CreateDataChannel();
-#endif
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  MediaExpectations media_expectations;
-  media_expectations.CalleeExpectsSomeAudioAndVideo();
-  ASSERT_TRUE(ExpectNewFrames(media_expectations));
-  // Close PeerConnections.
-  ClosePeerConnections();
-  // Pump messages for a second, and ensure no new packets end up sent.
-  uint32_t sent_packets_a = virtual_socket_server()->sent_packets();
-  WAIT(false, 1000);
-  uint32_t sent_packets_b = virtual_socket_server()->sent_packets();
-  EXPECT_EQ(sent_packets_a, sent_packets_b);
-}
-
-// Test that transport stats are generated by the RTCStatsCollector for a
-// connection that only involves data channels. This is a regression test for
-// crbug.com/826972.
-#ifdef WEBRTC_HAVE_SCTP
-TEST_P(PeerConnectionIntegrationTest,
-       TransportStatsReportedForDataChannelOnlyConnection) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
-
-  auto caller_report = caller()->NewGetStats();
-  EXPECT_EQ(1u, caller_report->GetStatsOfType<RTCTransportStats>().size());
-  auto callee_report = callee()->NewGetStats();
-  EXPECT_EQ(1u, callee_report->GetStatsOfType<RTCTransportStats>().size());
-}
-#endif  // WEBRTC_HAVE_SCTP
-
 TEST_P(PeerConnectionIntegrationTest,
        IceEventsGeneratedAndLoggedInRtcEventLog) {
   ASSERT_TRUE(CreatePeerConnectionWrappersWithFakeRtcEventLog());
@@ -5773,7 +3511,7 @@
  protected:
   // Setting the SdpSemantics for the base test to kDefault does not matter
   // because we specify not to use the test semantics when creating
-  // PeerConnectionWrappers.
+  // PeerConnectionIntegrationWrappers.
   PeerConnectionIntegrationInteropTest()
       : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB),
         caller_semantics_(std::get<0>(GetParam())),
@@ -6044,77 +3782,6 @@
             callee_track->state());
 }
 
-#ifdef WEBRTC_HAVE_SCTP
-
-TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
-       EndToEndCallWithBundledSctpDataChannel) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->AddAudioVideoTracks();
-  callee()->AddAudioVideoTracks();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
-    ASSERT_EQ_WAIT(SctpTransportState::kConnected,
-                   caller()->pc()->GetSctpTransport()->Information().state(),
-                   kDefaultTimeout);
-  });
-  ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-}
-
-TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
-       EndToEndCallWithDataChannelOnlyConnects) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_channel(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-  ASSERT_TRUE(caller()->data_observer()->IsOpen());
-}
-
-TEST_F(PeerConnectionIntegrationTestUnifiedPlan, DataChannelClosesWhenClosed) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-  caller()->data_channel()->Close();
-  ASSERT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
-}
-
-TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
-       DataChannelClosesWhenClosedReverse) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-  callee()->data_channel()->Close();
-  ASSERT_TRUE_WAIT(!caller()->data_observer()->IsOpen(), kDefaultTimeout);
-}
-
-TEST_F(PeerConnectionIntegrationTestUnifiedPlan,
-       DataChannelClosesWhenPeerConnectionClosed) {
-  ASSERT_TRUE(CreatePeerConnectionWrappers());
-  ConnectFakeSignaling();
-  caller()->CreateDataChannel();
-  caller()->CreateAndSetAndSignalOffer();
-  ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer(), kDefaultTimeout);
-  ASSERT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
-  caller()->pc()->Close();
-  ASSERT_TRUE_WAIT(!callee()->data_observer()->IsOpen(), kDefaultTimeout);
-}
-
-#endif  // WEBRTC_HAVE_SCTP
-
 }  // namespace
+
 }  // namespace webrtc
diff --git a/pc/test/integration_test_helpers.cc b/pc/test/integration_test_helpers.cc
new file mode 100644
index 0000000..10e4f45
--- /dev/null
+++ b/pc/test/integration_test_helpers.cc
@@ -0,0 +1,59 @@
+/*
+ *  Copyright 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "pc/test/integration_test_helpers.h"
+
+namespace webrtc {
+
+PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions() {
+  PeerConnectionInterface::RTCOfferAnswerOptions options;
+  options.ice_restart = true;
+  return options;
+}
+
+void RemoveSsrcsAndMsids(cricket::SessionDescription* desc) {
+  for (ContentInfo& content : desc->contents()) {
+    content.media_description()->mutable_streams().clear();
+  }
+  desc->set_msid_supported(false);
+  desc->set_msid_signaling(0);
+}
+
+void RemoveSsrcsAndKeepMsids(cricket::SessionDescription* desc) {
+  for (ContentInfo& content : desc->contents()) {
+    std::string track_id;
+    std::vector<std::string> stream_ids;
+    if (!content.media_description()->streams().empty()) {
+      const StreamParams& first_stream =
+          content.media_description()->streams()[0];
+      track_id = first_stream.id;
+      stream_ids = first_stream.stream_ids();
+    }
+    content.media_description()->mutable_streams().clear();
+    StreamParams new_stream;
+    new_stream.id = track_id;
+    new_stream.set_stream_ids(stream_ids);
+    content.media_description()->AddStream(new_stream);
+  }
+}
+
+int FindFirstMediaStatsIndexByKind(
+    const std::string& kind,
+    const std::vector<const webrtc::RTCMediaStreamTrackStats*>&
+        media_stats_vec) {
+  for (size_t i = 0; i < media_stats_vec.size(); i++) {
+    if (media_stats_vec[i]->kind.ValueToString() == kind) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+}  // namespace webrtc
diff --git a/pc/test/integration_test_helpers.h b/pc/test/integration_test_helpers.h
new file mode 100644
index 0000000..85d2f34
--- /dev/null
+++ b/pc/test/integration_test_helpers.h
@@ -0,0 +1,1842 @@
+/*
+ *  Copyright 2012 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.
+ */
+
+#ifndef PC_TEST_INTEGRATION_TEST_HELPERS_H_
+#define PC_TEST_INTEGRATION_TEST_HELPERS_H_
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/container.h"
+#include "absl/types/optional.h"
+#include "api/audio_options.h"
+#include "api/call/call_factory_interface.h"
+#include "api/candidate.h"
+#include "api/crypto/crypto_options.h"
+#include "api/data_channel_interface.h"
+#include "api/ice_transport_interface.h"
+#include "api/jsep.h"
+#include "api/media_stream_interface.h"
+#include "api/media_types.h"
+#include "api/peer_connection_interface.h"
+#include "api/peer_connection_proxy.h"
+#include "api/rtc_error.h"
+#include "api/rtc_event_log/rtc_event_log_factory.h"
+#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
+#include "api/rtc_event_log_output.h"
+#include "api/rtp_receiver_interface.h"
+#include "api/rtp_sender_interface.h"
+#include "api/rtp_transceiver_interface.h"
+#include "api/scoped_refptr.h"
+#include "api/stats/rtc_stats.h"
+#include "api/stats/rtc_stats_report.h"
+#include "api/stats/rtcstats_objects.h"
+#include "api/task_queue/default_task_queue_factory.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/transport/field_trial_based_config.h"
+#include "api/transport/webrtc_key_value_config.h"
+#include "api/uma_metrics.h"
+#include "api/video/video_rotation.h"
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "call/call.h"
+#include "logging/rtc_event_log/fake_rtc_event_log_factory.h"
+#include "media/base/media_engine.h"
+#include "media/base/stream_params.h"
+#include "media/engine/fake_webrtc_video_engine.h"
+#include "media/engine/webrtc_media_engine.h"
+#include "media/engine/webrtc_media_engine_defaults.h"
+#include "modules/audio_device/include/audio_device.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
+#include "p2p/base/fake_ice_transport.h"
+#include "p2p/base/ice_transport_internal.h"
+#include "p2p/base/mock_async_resolver.h"
+#include "p2p/base/p2p_constants.h"
+#include "p2p/base/port.h"
+#include "p2p/base/port_allocator.h"
+#include "p2p/base/port_interface.h"
+#include "p2p/base/test_stun_server.h"
+#include "p2p/base/test_turn_customizer.h"
+#include "p2p/base/test_turn_server.h"
+#include "p2p/client/basic_port_allocator.h"
+#include "pc/dtmf_sender.h"
+#include "pc/local_audio_source.h"
+#include "pc/media_session.h"
+#include "pc/peer_connection.h"
+#include "pc/peer_connection_factory.h"
+#include "pc/rtp_media_utils.h"
+#include "pc/session_description.h"
+#include "pc/test/fake_audio_capture_module.h"
+#include "pc/test/fake_periodic_video_source.h"
+#include "pc/test/fake_periodic_video_track_source.h"
+#include "pc/test/fake_rtc_certificate_generator.h"
+#include "pc/test/fake_video_track_renderer.h"
+#include "pc/test/mock_peer_connection_observers.h"
+#include "pc/video_track_source.h"
+#include "rtc_base/async_invoker.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/fake_mdns_responder.h"
+#include "rtc_base/fake_network.h"
+#include "rtc_base/firewall_socket_server.h"
+#include "rtc_base/gunit.h"
+#include "rtc_base/helpers.h"
+#include "rtc_base/ip_address.h"
+#include "rtc_base/location.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/mdns_responder_interface.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/ref_counted_object.h"
+#include "rtc_base/rtc_certificate_generator.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/ssl_stream_adapter.h"
+#include "rtc_base/test_certificate_verifier.h"
+#include "rtc_base/thread.h"
+#include "rtc_base/time_utils.h"
+#include "rtc_base/virtual_socket_server.h"
+#include "system_wrappers/include/metrics.h"
+#include "test/field_trial.h"
+#include "test/gmock.h"
+
+namespace webrtc {
+
+using ::cricket::ContentInfo;
+using ::cricket::StreamParams;
+using ::rtc::SocketAddress;
+using ::testing::_;
+using ::testing::Combine;
+using ::testing::Contains;
+using ::testing::DoAll;
+using ::testing::ElementsAre;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::UnorderedElementsAreArray;
+using ::testing::Values;
+using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
+
+static const int kDefaultTimeout = 10000;
+static const int kMaxWaitForStatsMs = 3000;
+static const int kMaxWaitForActivationMs = 5000;
+static const int kMaxWaitForFramesMs = 10000;
+// Default number of audio/video frames to wait for before considering a test
+// successful.
+static const int kDefaultExpectedAudioFrameCount = 3;
+static const int kDefaultExpectedVideoFrameCount = 3;
+
+static const char kDataChannelLabel[] = "data_channel";
+
+// SRTP cipher name negotiated by the tests. This must be updated if the
+// default changes.
+static const int kDefaultSrtpCryptoSuite = rtc::SRTP_AES128_CM_SHA1_80;
+static const int kDefaultSrtpCryptoSuiteGcm = rtc::SRTP_AEAD_AES_256_GCM;
+
+static const SocketAddress kDefaultLocalAddress("192.168.1.1", 0);
+
+// Helper function for constructing offer/answer options to initiate an ICE
+// restart.
+PeerConnectionInterface::RTCOfferAnswerOptions IceRestartOfferAnswerOptions();
+
+// Remove all stream information (SSRCs, track IDs, etc.) and "msid-semantic"
+// attribute from received SDP, simulating a legacy endpoint.
+void RemoveSsrcsAndMsids(cricket::SessionDescription* desc);
+
+// Removes all stream information besides the stream ids, simulating an
+// endpoint that only signals a=msid lines to convey stream_ids.
+void RemoveSsrcsAndKeepMsids(cricket::SessionDescription* desc);
+
+int FindFirstMediaStatsIndexByKind(
+    const std::string& kind,
+    const std::vector<const webrtc::RTCMediaStreamTrackStats*>&
+        media_stats_vec);
+
+class SignalingMessageReceiver {
+ public:
+  virtual void ReceiveSdpMessage(SdpType type, const std::string& msg) = 0;
+  virtual void ReceiveIceMessage(const std::string& sdp_mid,
+                                 int sdp_mline_index,
+                                 const std::string& msg) = 0;
+
+ protected:
+  SignalingMessageReceiver() {}
+  virtual ~SignalingMessageReceiver() {}
+};
+
+class MockRtpReceiverObserver : public webrtc::RtpReceiverObserverInterface {
+ public:
+  explicit MockRtpReceiverObserver(cricket::MediaType media_type)
+      : expected_media_type_(media_type) {}
+
+  void OnFirstPacketReceived(cricket::MediaType media_type) override {
+    ASSERT_EQ(expected_media_type_, media_type);
+    first_packet_received_ = true;
+  }
+
+  bool first_packet_received() const { return first_packet_received_; }
+
+  virtual ~MockRtpReceiverObserver() {}
+
+ private:
+  bool first_packet_received_ = false;
+  cricket::MediaType expected_media_type_;
+};
+
+// Helper class that wraps a peer connection, observes it, and can accept
+// signaling messages from another wrapper.
+//
+// Uses a fake network, fake A/V capture, and optionally fake
+// encoders/decoders, though they aren't used by default since they don't
+// advertise support of any codecs.
+// TODO(steveanton): See how this could become a subclass of
+// PeerConnectionWrapper defined in peerconnectionwrapper.h.
+class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver,
+                                         public SignalingMessageReceiver {
+ public:
+  // Different factory methods for convenience.
+  // TODO(deadbeef): Could use the pattern of:
+  //
+  // PeerConnectionIntegrationWrapper =
+  //     WrapperBuilder.WithConfig(...).WithOptions(...).build();
+  //
+  // To reduce some code duplication.
+  static PeerConnectionIntegrationWrapper* CreateWithDtlsIdentityStore(
+      const std::string& debug_name,
+      std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
+      rtc::Thread* network_thread,
+      rtc::Thread* worker_thread) {
+    PeerConnectionIntegrationWrapper* client(
+        new PeerConnectionIntegrationWrapper(debug_name));
+    webrtc::PeerConnectionDependencies dependencies(nullptr);
+    dependencies.cert_generator = std::move(cert_generator);
+    if (!client->Init(nullptr, nullptr, std::move(dependencies), network_thread,
+                      worker_thread, nullptr,
+                      /*reset_encoder_factory=*/false,
+                      /*reset_decoder_factory=*/false)) {
+      delete client;
+      return nullptr;
+    }
+    return client;
+  }
+
+  webrtc::PeerConnectionFactoryInterface* pc_factory() const {
+    return peer_connection_factory_.get();
+  }
+
+  webrtc::PeerConnectionInterface* pc() const { return peer_connection_.get(); }
+
+  // If a signaling message receiver is set (via ConnectFakeSignaling), this
+  // will set the whole offer/answer exchange in motion. Just need to wait for
+  // the signaling state to reach "stable".
+  void CreateAndSetAndSignalOffer() {
+    auto offer = CreateOfferAndWait();
+    ASSERT_NE(nullptr, offer);
+    EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(offer)));
+  }
+
+  // Sets the options to be used when CreateAndSetAndSignalOffer is called, or
+  // when a remote offer is received (via fake signaling) and an answer is
+  // generated. By default, uses default options.
+  void SetOfferAnswerOptions(
+      const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
+    offer_answer_options_ = options;
+  }
+
+  // Set a callback to be invoked when SDP is received via the fake signaling
+  // channel, which provides an opportunity to munge (modify) the SDP. This is
+  // used to test SDP being applied that a PeerConnection would normally not
+  // generate, but a non-JSEP endpoint might.
+  void SetReceivedSdpMunger(
+      std::function<void(cricket::SessionDescription*)> munger) {
+    received_sdp_munger_ = std::move(munger);
+  }
+
+  // Similar to the above, but this is run on SDP immediately after it's
+  // generated.
+  void SetGeneratedSdpMunger(
+      std::function<void(cricket::SessionDescription*)> munger) {
+    generated_sdp_munger_ = std::move(munger);
+  }
+
+  // Set a callback to be invoked when a remote offer is received via the fake
+  // signaling channel. This provides an opportunity to change the
+  // PeerConnection state before an answer is created and sent to the caller.
+  void SetRemoteOfferHandler(std::function<void()> handler) {
+    remote_offer_handler_ = std::move(handler);
+  }
+
+  void SetRemoteAsyncResolver(rtc::MockAsyncResolver* resolver) {
+    remote_async_resolver_ = resolver;
+  }
+
+  // Every ICE connection state in order that has been seen by the observer.
+  std::vector<PeerConnectionInterface::IceConnectionState>
+  ice_connection_state_history() const {
+    return ice_connection_state_history_;
+  }
+  void clear_ice_connection_state_history() {
+    ice_connection_state_history_.clear();
+  }
+
+  // Every standardized ICE connection state in order that has been seen by the
+  // observer.
+  std::vector<PeerConnectionInterface::IceConnectionState>
+  standardized_ice_connection_state_history() const {
+    return standardized_ice_connection_state_history_;
+  }
+
+  // Every PeerConnection state in order that has been seen by the observer.
+  std::vector<PeerConnectionInterface::PeerConnectionState>
+  peer_connection_state_history() const {
+    return peer_connection_state_history_;
+  }
+
+  // Every ICE gathering state in order that has been seen by the observer.
+  std::vector<PeerConnectionInterface::IceGatheringState>
+  ice_gathering_state_history() const {
+    return ice_gathering_state_history_;
+  }
+  std::vector<cricket::CandidatePairChangeEvent>
+  ice_candidate_pair_change_history() const {
+    return ice_candidate_pair_change_history_;
+  }
+
+  // Every PeerConnection signaling state in order that has been seen by the
+  // observer.
+  std::vector<PeerConnectionInterface::SignalingState>
+  peer_connection_signaling_state_history() const {
+    return peer_connection_signaling_state_history_;
+  }
+
+  void AddAudioVideoTracks() {
+    AddAudioTrack();
+    AddVideoTrack();
+  }
+
+  rtc::scoped_refptr<RtpSenderInterface> AddAudioTrack() {
+    return AddTrack(CreateLocalAudioTrack());
+  }
+
+  rtc::scoped_refptr<RtpSenderInterface> AddVideoTrack() {
+    return AddTrack(CreateLocalVideoTrack());
+  }
+
+  rtc::scoped_refptr<webrtc::AudioTrackInterface> CreateLocalAudioTrack() {
+    cricket::AudioOptions options;
+    // Disable highpass filter so that we can get all the test audio frames.
+    options.highpass_filter = false;
+    rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
+        peer_connection_factory_->CreateAudioSource(options);
+    // TODO(perkj): Test audio source when it is implemented. Currently audio
+    // always use the default input.
+    return peer_connection_factory_->CreateAudioTrack(rtc::CreateRandomUuid(),
+                                                      source);
+  }
+
+  rtc::scoped_refptr<webrtc::VideoTrackInterface> CreateLocalVideoTrack() {
+    webrtc::FakePeriodicVideoSource::Config config;
+    config.timestamp_offset_ms = rtc::TimeMillis();
+    return CreateLocalVideoTrackInternal(config);
+  }
+
+  rtc::scoped_refptr<webrtc::VideoTrackInterface>
+  CreateLocalVideoTrackWithConfig(
+      webrtc::FakePeriodicVideoSource::Config config) {
+    return CreateLocalVideoTrackInternal(config);
+  }
+
+  rtc::scoped_refptr<webrtc::VideoTrackInterface>
+  CreateLocalVideoTrackWithRotation(webrtc::VideoRotation rotation) {
+    webrtc::FakePeriodicVideoSource::Config config;
+    config.rotation = rotation;
+    config.timestamp_offset_ms = rtc::TimeMillis();
+    return CreateLocalVideoTrackInternal(config);
+  }
+
+  rtc::scoped_refptr<RtpSenderInterface> AddTrack(
+      rtc::scoped_refptr<MediaStreamTrackInterface> track,
+      const std::vector<std::string>& stream_ids = {}) {
+    auto result = pc()->AddTrack(track, stream_ids);
+    EXPECT_EQ(RTCErrorType::NONE, result.error().type());
+    return result.MoveValue();
+  }
+
+  std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceiversOfType(
+      cricket::MediaType media_type) {
+    std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
+    for (const auto& receiver : pc()->GetReceivers()) {
+      if (receiver->media_type() == media_type) {
+        receivers.push_back(receiver);
+      }
+    }
+    return receivers;
+  }
+
+  rtc::scoped_refptr<RtpTransceiverInterface> GetFirstTransceiverOfType(
+      cricket::MediaType media_type) {
+    for (auto transceiver : pc()->GetTransceivers()) {
+      if (transceiver->receiver()->media_type() == media_type) {
+        return transceiver;
+      }
+    }
+    return nullptr;
+  }
+
+  bool SignalingStateStable() {
+    return pc()->signaling_state() == webrtc::PeerConnectionInterface::kStable;
+  }
+
+  void CreateDataChannel() { CreateDataChannel(nullptr); }
+
+  void CreateDataChannel(const webrtc::DataChannelInit* init) {
+    CreateDataChannel(kDataChannelLabel, init);
+  }
+
+  void CreateDataChannel(const std::string& label,
+                         const webrtc::DataChannelInit* init) {
+    data_channel_ = pc()->CreateDataChannel(label, init);
+    ASSERT_TRUE(data_channel_.get() != nullptr);
+    data_observer_.reset(new MockDataChannelObserver(data_channel_));
+  }
+
+  DataChannelInterface* data_channel() { return data_channel_; }
+  const MockDataChannelObserver* data_observer() const {
+    return data_observer_.get();
+  }
+
+  int audio_frames_received() const {
+    return fake_audio_capture_module_->frames_received();
+  }
+
+  // Takes minimum of video frames received for each track.
+  //
+  // Can be used like:
+  // EXPECT_GE(expected_frames, min_video_frames_received_per_track());
+  //
+  // To ensure that all video tracks received at least a certain number of
+  // frames.
+  int min_video_frames_received_per_track() const {
+    int min_frames = INT_MAX;
+    if (fake_video_renderers_.empty()) {
+      return 0;
+    }
+
+    for (const auto& pair : fake_video_renderers_) {
+      min_frames = std::min(min_frames, pair.second->num_rendered_frames());
+    }
+    return min_frames;
+  }
+
+  // Returns a MockStatsObserver in a state after stats gathering finished,
+  // which can be used to access the gathered stats.
+  rtc::scoped_refptr<MockStatsObserver> OldGetStatsForTrack(
+      webrtc::MediaStreamTrackInterface* track) {
+    rtc::scoped_refptr<MockStatsObserver> observer(
+        new rtc::RefCountedObject<MockStatsObserver>());
+    EXPECT_TRUE(peer_connection_->GetStats(
+        observer, nullptr, PeerConnectionInterface::kStatsOutputLevelStandard));
+    EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
+    return observer;
+  }
+
+  // Version that doesn't take a track "filter", and gathers all stats.
+  rtc::scoped_refptr<MockStatsObserver> OldGetStats() {
+    return OldGetStatsForTrack(nullptr);
+  }
+
+  // Synchronously gets stats and returns them. If it times out, fails the test
+  // and returns null.
+  rtc::scoped_refptr<const webrtc::RTCStatsReport> NewGetStats() {
+    rtc::scoped_refptr<webrtc::MockRTCStatsCollectorCallback> callback(
+        new rtc::RefCountedObject<webrtc::MockRTCStatsCollectorCallback>());
+    peer_connection_->GetStats(callback);
+    EXPECT_TRUE_WAIT(callback->called(), kDefaultTimeout);
+    return callback->report();
+  }
+
+  int rendered_width() {
+    EXPECT_FALSE(fake_video_renderers_.empty());
+    return fake_video_renderers_.empty()
+               ? 0
+               : fake_video_renderers_.begin()->second->width();
+  }
+
+  int rendered_height() {
+    EXPECT_FALSE(fake_video_renderers_.empty());
+    return fake_video_renderers_.empty()
+               ? 0
+               : fake_video_renderers_.begin()->second->height();
+  }
+
+  double rendered_aspect_ratio() {
+    if (rendered_height() == 0) {
+      return 0.0;
+    }
+    return static_cast<double>(rendered_width()) / rendered_height();
+  }
+
+  webrtc::VideoRotation rendered_rotation() {
+    EXPECT_FALSE(fake_video_renderers_.empty());
+    return fake_video_renderers_.empty()
+               ? webrtc::kVideoRotation_0
+               : fake_video_renderers_.begin()->second->rotation();
+  }
+
+  int local_rendered_width() {
+    return local_video_renderer_ ? local_video_renderer_->width() : 0;
+  }
+
+  int local_rendered_height() {
+    return local_video_renderer_ ? local_video_renderer_->height() : 0;
+  }
+
+  double local_rendered_aspect_ratio() {
+    if (local_rendered_height() == 0) {
+      return 0.0;
+    }
+    return static_cast<double>(local_rendered_width()) /
+           local_rendered_height();
+  }
+
+  size_t number_of_remote_streams() {
+    if (!pc()) {
+      return 0;
+    }
+    return pc()->remote_streams()->count();
+  }
+
+  StreamCollectionInterface* remote_streams() const {
+    if (!pc()) {
+      ADD_FAILURE();
+      return nullptr;
+    }
+    return pc()->remote_streams();
+  }
+
+  StreamCollectionInterface* local_streams() {
+    if (!pc()) {
+      ADD_FAILURE();
+      return nullptr;
+    }
+    return pc()->local_streams();
+  }
+
+  webrtc::PeerConnectionInterface::SignalingState signaling_state() {
+    return pc()->signaling_state();
+  }
+
+  webrtc::PeerConnectionInterface::IceConnectionState ice_connection_state() {
+    return pc()->ice_connection_state();
+  }
+
+  webrtc::PeerConnectionInterface::IceConnectionState
+  standardized_ice_connection_state() {
+    return pc()->standardized_ice_connection_state();
+  }
+
+  webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state() {
+    return pc()->ice_gathering_state();
+  }
+
+  // Returns a MockRtpReceiverObserver for each RtpReceiver returned by
+  // GetReceivers. They're updated automatically when a remote offer/answer
+  // from the fake signaling channel is applied, or when
+  // ResetRtpReceiverObservers below is called.
+  const std::vector<std::unique_ptr<MockRtpReceiverObserver>>&
+  rtp_receiver_observers() {
+    return rtp_receiver_observers_;
+  }
+
+  void ResetRtpReceiverObservers() {
+    rtp_receiver_observers_.clear();
+    for (const rtc::scoped_refptr<RtpReceiverInterface>& receiver :
+         pc()->GetReceivers()) {
+      std::unique_ptr<MockRtpReceiverObserver> observer(
+          new MockRtpReceiverObserver(receiver->media_type()));
+      receiver->SetObserver(observer.get());
+      rtp_receiver_observers_.push_back(std::move(observer));
+    }
+  }
+
+  rtc::FakeNetworkManager* network_manager() const {
+    return fake_network_manager_.get();
+  }
+  cricket::PortAllocator* port_allocator() const { return port_allocator_; }
+
+  webrtc::FakeRtcEventLogFactory* event_log_factory() const {
+    return event_log_factory_;
+  }
+
+  const cricket::Candidate& last_candidate_gathered() const {
+    return last_candidate_gathered_;
+  }
+  const cricket::IceCandidateErrorEvent& error_event() const {
+    return error_event_;
+  }
+
+  // Sets the mDNS responder for the owned fake network manager and keeps a
+  // reference to the responder.
+  void SetMdnsResponder(
+      std::unique_ptr<webrtc::FakeMdnsResponder> mdns_responder) {
+    RTC_DCHECK(mdns_responder != nullptr);
+    mdns_responder_ = mdns_responder.get();
+    network_manager()->set_mdns_responder(std::move(mdns_responder));
+  }
+
+  // Returns null on failure.
+  std::unique_ptr<SessionDescriptionInterface> CreateOfferAndWait() {
+    rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer(
+        new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>());
+    pc()->CreateOffer(observer, offer_answer_options_);
+    return WaitForDescriptionFromObserver(observer);
+  }
+  bool Rollback() {
+    return SetRemoteDescription(
+        webrtc::CreateSessionDescription(SdpType::kRollback, ""));
+  }
+
+  // Functions for querying stats.
+  void StartWatchingDelayStats() {
+    // Get the baseline numbers for audio_packets and audio_delay.
+    auto received_stats = NewGetStats();
+    auto track_stats =
+        received_stats->GetStatsOfType<webrtc::RTCMediaStreamTrackStats>()[0];
+    ASSERT_TRUE(track_stats->relative_packet_arrival_delay.is_defined());
+    auto rtp_stats =
+        received_stats->GetStatsOfType<webrtc::RTCInboundRTPStreamStats>()[0];
+    ASSERT_TRUE(rtp_stats->packets_received.is_defined());
+    ASSERT_TRUE(rtp_stats->track_id.is_defined());
+    audio_track_stats_id_ = track_stats->id();
+    ASSERT_TRUE(received_stats->Get(audio_track_stats_id_));
+    rtp_stats_id_ = rtp_stats->id();
+    ASSERT_EQ(audio_track_stats_id_, *rtp_stats->track_id);
+    audio_packets_stat_ = *rtp_stats->packets_received;
+    audio_delay_stat_ = *track_stats->relative_packet_arrival_delay;
+    audio_samples_stat_ = *track_stats->total_samples_received;
+    audio_concealed_stat_ = *track_stats->concealed_samples;
+  }
+
+  void UpdateDelayStats(std::string tag, int desc_size) {
+    auto report = NewGetStats();
+    auto track_stats =
+        report->GetAs<webrtc::RTCMediaStreamTrackStats>(audio_track_stats_id_);
+    ASSERT_TRUE(track_stats);
+    auto rtp_stats =
+        report->GetAs<webrtc::RTCInboundRTPStreamStats>(rtp_stats_id_);
+    ASSERT_TRUE(rtp_stats);
+    auto delta_packets = *rtp_stats->packets_received - audio_packets_stat_;
+    auto delta_rpad =
+        *track_stats->relative_packet_arrival_delay - audio_delay_stat_;
+    auto recent_delay = delta_packets > 0 ? delta_rpad / delta_packets : -1;
+    // The purpose of these checks is to sound the alarm early if we introduce
+    // serious regressions. The numbers are not acceptable for production, but
+    // occur on slow bots.
+    //
+    // An average relative packet arrival delay over the renegotiation of
+    // > 100 ms indicates that something is dramatically wrong, and will impact
+    // quality for sure.
+    // Worst bots:
+    // linux_x86_dbg at 0.206
+#if !defined(NDEBUG)
+    EXPECT_GT(0.25, recent_delay) << tag << " size " << desc_size;
+#else
+    EXPECT_GT(0.1, recent_delay) << tag << " size " << desc_size;
+#endif
+    auto delta_samples =
+        *track_stats->total_samples_received - audio_samples_stat_;
+    auto delta_concealed =
+        *track_stats->concealed_samples - audio_concealed_stat_;
+    // These limits should be adjusted down as we improve:
+    //
+    // Concealing more than 4000 samples during a renegotiation is unacceptable.
+    // But some bots are slow.
+
+    // Worst bots:
+    // linux_more_configs bot at conceal count 5184
+    // android_arm_rel at conceal count 9241
+    // linux_x86_dbg at 15174
+#if !defined(NDEBUG)
+    EXPECT_GT(18000U, delta_concealed) << "Concealed " << delta_concealed
+                                       << " of " << delta_samples << " samples";
+#else
+    EXPECT_GT(15000U, delta_concealed) << "Concealed " << delta_concealed
+                                       << " of " << delta_samples << " samples";
+#endif
+    // Concealing more than 20% of samples during a renegotiation is
+    // unacceptable.
+    // Worst bots:
+    // linux_more_configs bot at conceal rate 0.516
+    // linux_x86_dbg bot at conceal rate 0.854
+    if (delta_samples > 0) {
+#if !defined(NDEBUG)
+      EXPECT_GT(0.95, 1.0 * delta_concealed / delta_samples)
+          << "Concealed " << delta_concealed << " of " << delta_samples
+          << " samples";
+#else
+      EXPECT_GT(0.6, 1.0 * delta_concealed / delta_samples)
+          << "Concealed " << delta_concealed << " of " << delta_samples
+          << " samples";
+#endif
+    }
+    // Increment trailing counters
+    audio_packets_stat_ = *rtp_stats->packets_received;
+    audio_delay_stat_ = *track_stats->relative_packet_arrival_delay;
+    audio_samples_stat_ = *track_stats->total_samples_received;
+    audio_concealed_stat_ = *track_stats->concealed_samples;
+  }
+
+ private:
+  explicit PeerConnectionIntegrationWrapper(const std::string& debug_name)
+      : debug_name_(debug_name) {}
+
+  bool Init(const PeerConnectionFactory::Options* options,
+            const PeerConnectionInterface::RTCConfiguration* config,
+            webrtc::PeerConnectionDependencies dependencies,
+            rtc::Thread* network_thread,
+            rtc::Thread* worker_thread,
+            std::unique_ptr<webrtc::FakeRtcEventLogFactory> event_log_factory,
+            bool reset_encoder_factory,
+            bool reset_decoder_factory) {
+    // There's an error in this test code if Init ends up being called twice.
+    RTC_DCHECK(!peer_connection_);
+    RTC_DCHECK(!peer_connection_factory_);
+
+    fake_network_manager_.reset(new rtc::FakeNetworkManager());
+    fake_network_manager_->AddInterface(kDefaultLocalAddress);
+
+    std::unique_ptr<cricket::PortAllocator> port_allocator(
+        new cricket::BasicPortAllocator(fake_network_manager_.get()));
+    port_allocator_ = port_allocator.get();
+    fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
+    if (!fake_audio_capture_module_) {
+      return false;
+    }
+    rtc::Thread* const signaling_thread = rtc::Thread::Current();
+
+    webrtc::PeerConnectionFactoryDependencies pc_factory_dependencies;
+    pc_factory_dependencies.network_thread = network_thread;
+    pc_factory_dependencies.worker_thread = worker_thread;
+    pc_factory_dependencies.signaling_thread = signaling_thread;
+    pc_factory_dependencies.task_queue_factory =
+        webrtc::CreateDefaultTaskQueueFactory();
+    pc_factory_dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
+    cricket::MediaEngineDependencies media_deps;
+    media_deps.task_queue_factory =
+        pc_factory_dependencies.task_queue_factory.get();
+    media_deps.adm = fake_audio_capture_module_;
+    webrtc::SetMediaEngineDefaults(&media_deps);
+
+    if (reset_encoder_factory) {
+      media_deps.video_encoder_factory.reset();
+    }
+    if (reset_decoder_factory) {
+      media_deps.video_decoder_factory.reset();
+    }
+
+    if (!media_deps.audio_processing) {
+      // If the standard Creation method for APM returns a null pointer, instead
+      // use the builder for testing to create an APM object.
+      media_deps.audio_processing = AudioProcessingBuilderForTesting().Create();
+    }
+
+    media_deps.trials = pc_factory_dependencies.trials.get();
+
+    pc_factory_dependencies.media_engine =
+        cricket::CreateMediaEngine(std::move(media_deps));
+    pc_factory_dependencies.call_factory = webrtc::CreateCallFactory();
+    if (event_log_factory) {
+      event_log_factory_ = event_log_factory.get();
+      pc_factory_dependencies.event_log_factory = std::move(event_log_factory);
+    } else {
+      pc_factory_dependencies.event_log_factory =
+          std::make_unique<webrtc::RtcEventLogFactory>(
+              pc_factory_dependencies.task_queue_factory.get());
+    }
+    peer_connection_factory_ = webrtc::CreateModularPeerConnectionFactory(
+        std::move(pc_factory_dependencies));
+
+    if (!peer_connection_factory_) {
+      return false;
+    }
+    if (options) {
+      peer_connection_factory_->SetOptions(*options);
+    }
+    if (config) {
+      sdp_semantics_ = config->sdp_semantics;
+    }
+
+    dependencies.allocator = std::move(port_allocator);
+    peer_connection_ = CreatePeerConnection(config, std::move(dependencies));
+    return peer_connection_.get() != nullptr;
+  }
+
+  rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
+      const PeerConnectionInterface::RTCConfiguration* config,
+      webrtc::PeerConnectionDependencies dependencies) {
+    PeerConnectionInterface::RTCConfiguration modified_config;
+    // If |config| is null, this will result in a default configuration being
+    // used.
+    if (config) {
+      modified_config = *config;
+    }
+    // Disable resolution adaptation; we don't want it interfering with the
+    // test results.
+    // TODO(deadbeef): Do something more robust. Since we're testing for aspect
+    // ratios and not specific resolutions, is this even necessary?
+    modified_config.set_cpu_adaptation(false);
+
+    dependencies.observer = this;
+    return peer_connection_factory_->CreatePeerConnection(
+        modified_config, std::move(dependencies));
+  }
+
+  void set_signaling_message_receiver(
+      SignalingMessageReceiver* signaling_message_receiver) {
+    signaling_message_receiver_ = signaling_message_receiver;
+  }
+
+  void set_signaling_delay_ms(int delay_ms) { signaling_delay_ms_ = delay_ms; }
+
+  void set_signal_ice_candidates(bool signal) {
+    signal_ice_candidates_ = signal;
+  }
+
+  rtc::scoped_refptr<webrtc::VideoTrackInterface> CreateLocalVideoTrackInternal(
+      webrtc::FakePeriodicVideoSource::Config config) {
+    // Set max frame rate to 10fps to reduce the risk of test flakiness.
+    // TODO(deadbeef): Do something more robust.
+    config.frame_interval_ms = 100;
+
+    video_track_sources_.emplace_back(
+        new rtc::RefCountedObject<webrtc::FakePeriodicVideoTrackSource>(
+            config, false /* remote */));
+    rtc::scoped_refptr<webrtc::VideoTrackInterface> track(
+        peer_connection_factory_->CreateVideoTrack(
+            rtc::CreateRandomUuid(), video_track_sources_.back()));
+    if (!local_video_renderer_) {
+      local_video_renderer_.reset(new webrtc::FakeVideoTrackRenderer(track));
+    }
+    return track;
+  }
+
+  void HandleIncomingOffer(const std::string& msg) {
+    RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingOffer";
+    std::unique_ptr<SessionDescriptionInterface> desc =
+        webrtc::CreateSessionDescription(SdpType::kOffer, msg);
+    if (received_sdp_munger_) {
+      received_sdp_munger_(desc->description());
+    }
+
+    EXPECT_TRUE(SetRemoteDescription(std::move(desc)));
+    // Setting a remote description may have changed the number of receivers,
+    // so reset the receiver observers.
+    ResetRtpReceiverObservers();
+    if (remote_offer_handler_) {
+      remote_offer_handler_();
+    }
+    auto answer = CreateAnswer();
+    ASSERT_NE(nullptr, answer);
+    EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(answer)));
+  }
+
+  void HandleIncomingAnswer(const std::string& msg) {
+    RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingAnswer";
+    std::unique_ptr<SessionDescriptionInterface> desc =
+        webrtc::CreateSessionDescription(SdpType::kAnswer, msg);
+    if (received_sdp_munger_) {
+      received_sdp_munger_(desc->description());
+    }
+
+    EXPECT_TRUE(SetRemoteDescription(std::move(desc)));
+    // Set the RtpReceiverObserver after receivers are created.
+    ResetRtpReceiverObservers();
+  }
+
+  // Returns null on failure.
+  std::unique_ptr<SessionDescriptionInterface> CreateAnswer() {
+    rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observer(
+        new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>());
+    pc()->CreateAnswer(observer, offer_answer_options_);
+    return WaitForDescriptionFromObserver(observer);
+  }
+
+  std::unique_ptr<SessionDescriptionInterface> WaitForDescriptionFromObserver(
+      MockCreateSessionDescriptionObserver* observer) {
+    EXPECT_EQ_WAIT(true, observer->called(), kDefaultTimeout);
+    if (!observer->result()) {
+      return nullptr;
+    }
+    auto description = observer->MoveDescription();
+    if (generated_sdp_munger_) {
+      generated_sdp_munger_(description->description());
+    }
+    return description;
+  }
+
+  // Setting the local description and sending the SDP message over the fake
+  // signaling channel are combined into the same method because the SDP
+  // message needs to be sent as soon as SetLocalDescription finishes, without
+  // waiting for the observer to be called. This ensures that ICE candidates
+  // don't outrace the description.
+  bool SetLocalDescriptionAndSendSdpMessage(
+      std::unique_ptr<SessionDescriptionInterface> desc) {
+    rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
+        new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
+    RTC_LOG(LS_INFO) << debug_name_ << ": SetLocalDescriptionAndSendSdpMessage";
+    SdpType type = desc->GetType();
+    std::string sdp;
+    EXPECT_TRUE(desc->ToString(&sdp));
+    RTC_LOG(LS_INFO) << debug_name_ << ": local SDP contents=\n" << sdp;
+    pc()->SetLocalDescription(observer, desc.release());
+    RemoveUnusedVideoRenderers();
+    // As mentioned above, we need to send the message immediately after
+    // SetLocalDescription.
+    SendSdpMessage(type, sdp);
+    EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
+    return true;
+  }
+
+  bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc) {
+    rtc::scoped_refptr<MockSetSessionDescriptionObserver> observer(
+        new rtc::RefCountedObject<MockSetSessionDescriptionObserver>());
+    RTC_LOG(LS_INFO) << debug_name_ << ": SetRemoteDescription";
+    pc()->SetRemoteDescription(observer, desc.release());
+    RemoveUnusedVideoRenderers();
+    EXPECT_TRUE_WAIT(observer->called(), kDefaultTimeout);
+    return observer->result();
+  }
+
+  // This is a work around to remove unused fake_video_renderers from
+  // transceivers that have either stopped or are no longer receiving.
+  void RemoveUnusedVideoRenderers() {
+    if (sdp_semantics_ != SdpSemantics::kUnifiedPlan) {
+      return;
+    }
+    auto transceivers = pc()->GetTransceivers();
+    std::set<std::string> active_renderers;
+    for (auto& transceiver : transceivers) {
+      // Note - we don't check for direction here. This function is called
+      // before direction is set, and in that case, we should not remove
+      // the renderer.
+      if (transceiver->receiver()->media_type() == cricket::MEDIA_TYPE_VIDEO) {
+        active_renderers.insert(transceiver->receiver()->track()->id());
+      }
+    }
+    for (auto it = fake_video_renderers_.begin();
+         it != fake_video_renderers_.end();) {
+      // Remove fake video renderers belonging to any non-active transceivers.
+      if (!active_renderers.count(it->first)) {
+        it = fake_video_renderers_.erase(it);
+      } else {
+        it++;
+      }
+    }
+  }
+
+  // Simulate sending a blob of SDP with delay |signaling_delay_ms_| (0 by
+  // default).
+  void SendSdpMessage(SdpType type, const std::string& msg) {
+    if (signaling_delay_ms_ == 0) {
+      RelaySdpMessageIfReceiverExists(type, msg);
+    } else {
+      invoker_.AsyncInvokeDelayed<void>(
+          RTC_FROM_HERE, rtc::Thread::Current(),
+          [this, type, msg] { RelaySdpMessageIfReceiverExists(type, msg); },
+          signaling_delay_ms_);
+    }
+  }
+
+  void RelaySdpMessageIfReceiverExists(SdpType type, const std::string& msg) {
+    if (signaling_message_receiver_) {
+      signaling_message_receiver_->ReceiveSdpMessage(type, msg);
+    }
+  }
+
+  // Simulate trickling an ICE candidate with delay |signaling_delay_ms_| (0 by
+  // default).
+  void SendIceMessage(const std::string& sdp_mid,
+                      int sdp_mline_index,
+                      const std::string& msg) {
+    if (signaling_delay_ms_ == 0) {
+      RelayIceMessageIfReceiverExists(sdp_mid, sdp_mline_index, msg);
+    } else {
+      invoker_.AsyncInvokeDelayed<void>(
+          RTC_FROM_HERE, rtc::Thread::Current(),
+          [this, sdp_mid, sdp_mline_index, msg] {
+            RelayIceMessageIfReceiverExists(sdp_mid, sdp_mline_index, msg);
+          },
+          signaling_delay_ms_);
+    }
+  }
+
+  void RelayIceMessageIfReceiverExists(const std::string& sdp_mid,
+                                       int sdp_mline_index,
+                                       const std::string& msg) {
+    if (signaling_message_receiver_) {
+      signaling_message_receiver_->ReceiveIceMessage(sdp_mid, sdp_mline_index,
+                                                     msg);
+    }
+  }
+
+  // SignalingMessageReceiver callbacks.
+  void ReceiveSdpMessage(SdpType type, const std::string& msg) override {
+    if (type == SdpType::kOffer) {
+      HandleIncomingOffer(msg);
+    } else {
+      HandleIncomingAnswer(msg);
+    }
+  }
+
+  void ReceiveIceMessage(const std::string& sdp_mid,
+                         int sdp_mline_index,
+                         const std::string& msg) override {
+    RTC_LOG(LS_INFO) << debug_name_ << ": ReceiveIceMessage";
+    std::unique_ptr<webrtc::IceCandidateInterface> candidate(
+        webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, msg, nullptr));
+    EXPECT_TRUE(pc()->AddIceCandidate(candidate.get()));
+  }
+
+  // PeerConnectionObserver callbacks.
+  void OnSignalingChange(
+      webrtc::PeerConnectionInterface::SignalingState new_state) override {
+    EXPECT_EQ(pc()->signaling_state(), new_state);
+    peer_connection_signaling_state_history_.push_back(new_state);
+  }
+  void OnAddTrack(rtc::scoped_refptr<RtpReceiverInterface> receiver,
+                  const std::vector<rtc::scoped_refptr<MediaStreamInterface>>&
+                      streams) override {
+    if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
+      rtc::scoped_refptr<VideoTrackInterface> video_track(
+          static_cast<VideoTrackInterface*>(receiver->track().get()));
+      ASSERT_TRUE(fake_video_renderers_.find(video_track->id()) ==
+                  fake_video_renderers_.end());
+      fake_video_renderers_[video_track->id()] =
+          std::make_unique<FakeVideoTrackRenderer>(video_track);
+    }
+  }
+  void OnRemoveTrack(
+      rtc::scoped_refptr<RtpReceiverInterface> receiver) override {
+    if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
+      auto it = fake_video_renderers_.find(receiver->track()->id());
+      if (it != fake_video_renderers_.end()) {
+        fake_video_renderers_.erase(it);
+      } else {
+        RTC_LOG(LS_ERROR) << "OnRemoveTrack called for non-active renderer";
+      }
+    }
+  }
+  void OnRenegotiationNeeded() override {}
+  void OnIceConnectionChange(
+      webrtc::PeerConnectionInterface::IceConnectionState new_state) override {
+    EXPECT_EQ(pc()->ice_connection_state(), new_state);
+    ice_connection_state_history_.push_back(new_state);
+  }
+  void OnStandardizedIceConnectionChange(
+      webrtc::PeerConnectionInterface::IceConnectionState new_state) override {
+    standardized_ice_connection_state_history_.push_back(new_state);
+  }
+  void OnConnectionChange(
+      webrtc::PeerConnectionInterface::PeerConnectionState new_state) override {
+    peer_connection_state_history_.push_back(new_state);
+  }
+
+  void OnIceGatheringChange(
+      webrtc::PeerConnectionInterface::IceGatheringState new_state) override {
+    EXPECT_EQ(pc()->ice_gathering_state(), new_state);
+    ice_gathering_state_history_.push_back(new_state);
+  }
+
+  void OnIceSelectedCandidatePairChanged(
+      const cricket::CandidatePairChangeEvent& event) {
+    ice_candidate_pair_change_history_.push_back(event);
+  }
+
+  void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override {
+    RTC_LOG(LS_INFO) << debug_name_ << ": OnIceCandidate";
+
+    if (remote_async_resolver_) {
+      const auto& local_candidate = candidate->candidate();
+      if (local_candidate.address().IsUnresolvedIP()) {
+        RTC_DCHECK(local_candidate.type() == cricket::LOCAL_PORT_TYPE);
+        rtc::SocketAddress resolved_addr(local_candidate.address());
+        const auto resolved_ip = mdns_responder_->GetMappedAddressForName(
+            local_candidate.address().hostname());
+        RTC_DCHECK(!resolved_ip.IsNil());
+        resolved_addr.SetResolvedIP(resolved_ip);
+        EXPECT_CALL(*remote_async_resolver_, GetResolvedAddress(_, _))
+            .WillOnce(DoAll(SetArgPointee<1>(resolved_addr), Return(true)));
+        EXPECT_CALL(*remote_async_resolver_, Destroy(_));
+      }
+    }
+
+    std::string ice_sdp;
+    EXPECT_TRUE(candidate->ToString(&ice_sdp));
+    if (signaling_message_receiver_ == nullptr || !signal_ice_candidates_) {
+      // Remote party may be deleted.
+      return;
+    }
+    SendIceMessage(candidate->sdp_mid(), candidate->sdp_mline_index(), ice_sdp);
+    last_candidate_gathered_ = candidate->candidate();
+  }
+  void OnIceCandidateError(const std::string& address,
+                           int port,
+                           const std::string& url,
+                           int error_code,
+                           const std::string& error_text) override {
+    error_event_ = cricket::IceCandidateErrorEvent(address, port, url,
+                                                   error_code, error_text);
+  }
+  void OnDataChannel(
+      rtc::scoped_refptr<DataChannelInterface> data_channel) override {
+    RTC_LOG(LS_INFO) << debug_name_ << ": OnDataChannel";
+    data_channel_ = data_channel;
+    data_observer_.reset(new MockDataChannelObserver(data_channel));
+  }
+
+  std::string debug_name_;
+
+  std::unique_ptr<rtc::FakeNetworkManager> fake_network_manager_;
+  // Reference to the mDNS responder owned by |fake_network_manager_| after set.
+  webrtc::FakeMdnsResponder* mdns_responder_ = nullptr;
+
+  rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
+  rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
+      peer_connection_factory_;
+
+  cricket::PortAllocator* port_allocator_;
+  // Needed to keep track of number of frames sent.
+  rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
+  // Needed to keep track of number of frames received.
+  std::map<std::string, std::unique_ptr<webrtc::FakeVideoTrackRenderer>>
+      fake_video_renderers_;
+  // Needed to ensure frames aren't received for removed tracks.
+  std::vector<std::unique_ptr<webrtc::FakeVideoTrackRenderer>>
+      removed_fake_video_renderers_;
+
+  // For remote peer communication.
+  SignalingMessageReceiver* signaling_message_receiver_ = nullptr;
+  int signaling_delay_ms_ = 0;
+  bool signal_ice_candidates_ = true;
+  cricket::Candidate last_candidate_gathered_;
+  cricket::IceCandidateErrorEvent error_event_;
+
+  // Store references to the video sources we've created, so that we can stop
+  // them, if required.
+  std::vector<rtc::scoped_refptr<webrtc::VideoTrackSource>>
+      video_track_sources_;
+  // |local_video_renderer_| attached to the first created local video track.
+  std::unique_ptr<webrtc::FakeVideoTrackRenderer> local_video_renderer_;
+
+  SdpSemantics sdp_semantics_;
+  PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options_;
+  std::function<void(cricket::SessionDescription*)> received_sdp_munger_;
+  std::function<void(cricket::SessionDescription*)> generated_sdp_munger_;
+  std::function<void()> remote_offer_handler_;
+  rtc::MockAsyncResolver* remote_async_resolver_ = nullptr;
+  rtc::scoped_refptr<DataChannelInterface> data_channel_;
+  std::unique_ptr<MockDataChannelObserver> data_observer_;
+
+  std::vector<std::unique_ptr<MockRtpReceiverObserver>> rtp_receiver_observers_;
+
+  std::vector<PeerConnectionInterface::IceConnectionState>
+      ice_connection_state_history_;
+  std::vector<PeerConnectionInterface::IceConnectionState>
+      standardized_ice_connection_state_history_;
+  std::vector<PeerConnectionInterface::PeerConnectionState>
+      peer_connection_state_history_;
+  std::vector<PeerConnectionInterface::IceGatheringState>
+      ice_gathering_state_history_;
+  std::vector<cricket::CandidatePairChangeEvent>
+      ice_candidate_pair_change_history_;
+  std::vector<PeerConnectionInterface::SignalingState>
+      peer_connection_signaling_state_history_;
+  webrtc::FakeRtcEventLogFactory* event_log_factory_;
+
+  // Variables for tracking delay stats on an audio track
+  int audio_packets_stat_ = 0;
+  double audio_delay_stat_ = 0.0;
+  uint64_t audio_samples_stat_ = 0;
+  uint64_t audio_concealed_stat_ = 0;
+  std::string rtp_stats_id_;
+  std::string audio_track_stats_id_;
+
+  rtc::AsyncInvoker invoker_;
+
+  friend class PeerConnectionIntegrationBaseTest;
+};
+
+class MockRtcEventLogOutput : public webrtc::RtcEventLogOutput {
+ public:
+  virtual ~MockRtcEventLogOutput() = default;
+  MOCK_METHOD(bool, IsActive, (), (const, override));
+  MOCK_METHOD(bool, Write, (const std::string&), (override));
+};
+
+// This helper object is used for both specifying how many audio/video frames
+// are expected to be received for a caller/callee. It provides helper functions
+// to specify these expectations. The object initially starts in a state of no
+// expectations.
+class MediaExpectations {
+ public:
+  enum ExpectFrames {
+    kExpectSomeFrames,
+    kExpectNoFrames,
+    kNoExpectation,
+  };
+
+  void ExpectBidirectionalAudioAndVideo() {
+    ExpectBidirectionalAudio();
+    ExpectBidirectionalVideo();
+  }
+
+  void ExpectBidirectionalAudio() {
+    CallerExpectsSomeAudio();
+    CalleeExpectsSomeAudio();
+  }
+
+  void ExpectNoAudio() {
+    CallerExpectsNoAudio();
+    CalleeExpectsNoAudio();
+  }
+
+  void ExpectBidirectionalVideo() {
+    CallerExpectsSomeVideo();
+    CalleeExpectsSomeVideo();
+  }
+
+  void ExpectNoVideo() {
+    CallerExpectsNoVideo();
+    CalleeExpectsNoVideo();
+  }
+
+  void CallerExpectsSomeAudioAndVideo() {
+    CallerExpectsSomeAudio();
+    CallerExpectsSomeVideo();
+  }
+
+  void CalleeExpectsSomeAudioAndVideo() {
+    CalleeExpectsSomeAudio();
+    CalleeExpectsSomeVideo();
+  }
+
+  // Caller's audio functions.
+  void CallerExpectsSomeAudio(
+      int expected_audio_frames = kDefaultExpectedAudioFrameCount) {
+    caller_audio_expectation_ = kExpectSomeFrames;
+    caller_audio_frames_expected_ = expected_audio_frames;
+  }
+
+  void CallerExpectsNoAudio() {
+    caller_audio_expectation_ = kExpectNoFrames;
+    caller_audio_frames_expected_ = 0;
+  }
+
+  // Caller's video functions.
+  void CallerExpectsSomeVideo(
+      int expected_video_frames = kDefaultExpectedVideoFrameCount) {
+    caller_video_expectation_ = kExpectSomeFrames;
+    caller_video_frames_expected_ = expected_video_frames;
+  }
+
+  void CallerExpectsNoVideo() {
+    caller_video_expectation_ = kExpectNoFrames;
+    caller_video_frames_expected_ = 0;
+  }
+
+  // Callee's audio functions.
+  void CalleeExpectsSomeAudio(
+      int expected_audio_frames = kDefaultExpectedAudioFrameCount) {
+    callee_audio_expectation_ = kExpectSomeFrames;
+    callee_audio_frames_expected_ = expected_audio_frames;
+  }
+
+  void CalleeExpectsNoAudio() {
+    callee_audio_expectation_ = kExpectNoFrames;
+    callee_audio_frames_expected_ = 0;
+  }
+
+  // Callee's video functions.
+  void CalleeExpectsSomeVideo(
+      int expected_video_frames = kDefaultExpectedVideoFrameCount) {
+    callee_video_expectation_ = kExpectSomeFrames;
+    callee_video_frames_expected_ = expected_video_frames;
+  }
+
+  void CalleeExpectsNoVideo() {
+    callee_video_expectation_ = kExpectNoFrames;
+    callee_video_frames_expected_ = 0;
+  }
+
+  ExpectFrames caller_audio_expectation_ = kNoExpectation;
+  ExpectFrames caller_video_expectation_ = kNoExpectation;
+  ExpectFrames callee_audio_expectation_ = kNoExpectation;
+  ExpectFrames callee_video_expectation_ = kNoExpectation;
+  int caller_audio_frames_expected_ = 0;
+  int caller_video_frames_expected_ = 0;
+  int callee_audio_frames_expected_ = 0;
+  int callee_video_frames_expected_ = 0;
+};
+
+class MockIceTransport : public webrtc::IceTransportInterface {
+ public:
+  MockIceTransport(const std::string& name, int component)
+      : internal_(std::make_unique<cricket::FakeIceTransport>(
+            name,
+            component,
+            nullptr /* network_thread */)) {}
+  ~MockIceTransport() = default;
+  cricket::IceTransportInternal* internal() { return internal_.get(); }
+
+ private:
+  std::unique_ptr<cricket::FakeIceTransport> internal_;
+};
+
+class MockIceTransportFactory : public IceTransportFactory {
+ public:
+  ~MockIceTransportFactory() override = default;
+  rtc::scoped_refptr<IceTransportInterface> CreateIceTransport(
+      const std::string& transport_name,
+      int component,
+      IceTransportInit init) {
+    RecordIceTransportCreated();
+    return new rtc::RefCountedObject<MockIceTransport>(transport_name,
+                                                       component);
+  }
+  MOCK_METHOD(void, RecordIceTransportCreated, ());
+};
+
+// Tests two PeerConnections connecting to each other end-to-end, using a
+// virtual network, fake A/V capture and fake encoder/decoders. The
+// PeerConnections share the threads/socket servers, but use separate versions
+// of everything else (including "PeerConnectionFactory"s).
+class PeerConnectionIntegrationBaseTest : public ::testing::Test {
+ public:
+  explicit PeerConnectionIntegrationBaseTest(SdpSemantics sdp_semantics)
+      : sdp_semantics_(sdp_semantics),
+        ss_(new rtc::VirtualSocketServer()),
+        fss_(new rtc::FirewallSocketServer(ss_.get())),
+        network_thread_(new rtc::Thread(fss_.get())),
+        worker_thread_(rtc::Thread::Create()) {
+    network_thread_->SetName("PCNetworkThread", this);
+    worker_thread_->SetName("PCWorkerThread", this);
+    RTC_CHECK(network_thread_->Start());
+    RTC_CHECK(worker_thread_->Start());
+    webrtc::metrics::Reset();
+  }
+
+  ~PeerConnectionIntegrationBaseTest() {
+    // The PeerConnections should be deleted before the TurnCustomizers.
+    // A TurnPort is created with a raw pointer to a TurnCustomizer. The
+    // TurnPort has the same lifetime as the PeerConnection, so it's expected
+    // that the TurnCustomizer outlives the life of the PeerConnection or else
+    // when Send() is called it will hit a seg fault.
+    if (caller_) {
+      caller_->set_signaling_message_receiver(nullptr);
+      delete SetCallerPcWrapperAndReturnCurrent(nullptr);
+    }
+    if (callee_) {
+      callee_->set_signaling_message_receiver(nullptr);
+      delete SetCalleePcWrapperAndReturnCurrent(nullptr);
+    }
+
+    // If turn servers were created for the test they need to be destroyed on
+    // the network thread.
+    network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
+      turn_servers_.clear();
+      turn_customizers_.clear();
+    });
+  }
+
+  bool SignalingStateStable() {
+    return caller_->SignalingStateStable() && callee_->SignalingStateStable();
+  }
+
+  bool DtlsConnected() {
+    // TODO(deadbeef): kIceConnectionConnected currently means both ICE and DTLS
+    // are connected. This is an important distinction. Once we have separate
+    // ICE and DTLS state, this check needs to use the DTLS state.
+    return (callee()->ice_connection_state() ==
+                webrtc::PeerConnectionInterface::kIceConnectionConnected ||
+            callee()->ice_connection_state() ==
+                webrtc::PeerConnectionInterface::kIceConnectionCompleted) &&
+           (caller()->ice_connection_state() ==
+                webrtc::PeerConnectionInterface::kIceConnectionConnected ||
+            caller()->ice_connection_state() ==
+                webrtc::PeerConnectionInterface::kIceConnectionCompleted);
+  }
+
+  // When |event_log_factory| is null, the default implementation of the event
+  // log factory will be used.
+  std::unique_ptr<PeerConnectionIntegrationWrapper> CreatePeerConnectionWrapper(
+      const std::string& debug_name,
+      const PeerConnectionFactory::Options* options,
+      const RTCConfiguration* config,
+      webrtc::PeerConnectionDependencies dependencies,
+      std::unique_ptr<webrtc::FakeRtcEventLogFactory> event_log_factory,
+      bool reset_encoder_factory,
+      bool reset_decoder_factory) {
+    RTCConfiguration modified_config;
+    if (config) {
+      modified_config = *config;
+    }
+    modified_config.sdp_semantics = sdp_semantics_;
+    if (!dependencies.cert_generator) {
+      dependencies.cert_generator =
+          std::make_unique<FakeRTCCertificateGenerator>();
+    }
+    std::unique_ptr<PeerConnectionIntegrationWrapper> client(
+        new PeerConnectionIntegrationWrapper(debug_name));
+
+    if (!client->Init(options, &modified_config, std::move(dependencies),
+                      network_thread_.get(), worker_thread_.get(),
+                      std::move(event_log_factory), reset_encoder_factory,
+                      reset_decoder_factory)) {
+      return nullptr;
+    }
+    return client;
+  }
+
+  std::unique_ptr<PeerConnectionIntegrationWrapper>
+  CreatePeerConnectionWrapperWithFakeRtcEventLog(
+      const std::string& debug_name,
+      const PeerConnectionFactory::Options* options,
+      const RTCConfiguration* config,
+      webrtc::PeerConnectionDependencies dependencies) {
+    return CreatePeerConnectionWrapper(
+        debug_name, options, config, std::move(dependencies),
+        std::make_unique<webrtc::FakeRtcEventLogFactory>(),
+        /*reset_encoder_factory=*/false,
+        /*reset_decoder_factory=*/false);
+  }
+
+  bool CreatePeerConnectionWrappers() {
+    return CreatePeerConnectionWrappersWithConfig(
+        PeerConnectionInterface::RTCConfiguration(),
+        PeerConnectionInterface::RTCConfiguration());
+  }
+
+  bool CreatePeerConnectionWrappersWithSdpSemantics(
+      SdpSemantics caller_semantics,
+      SdpSemantics callee_semantics) {
+    // Can't specify the sdp_semantics in the passed-in configuration since it
+    // will be overwritten by CreatePeerConnectionWrapper with whatever is
+    // stored in sdp_semantics_. So get around this by modifying the instance
+    // variable before calling CreatePeerConnectionWrapper for the caller and
+    // callee PeerConnections.
+    SdpSemantics original_semantics = sdp_semantics_;
+    sdp_semantics_ = caller_semantics;
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
+        nullptr,
+        /*reset_encoder_factory=*/false,
+        /*reset_decoder_factory=*/false);
+    sdp_semantics_ = callee_semantics;
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
+        nullptr,
+        /*reset_encoder_factory=*/false,
+        /*reset_decoder_factory=*/false);
+    sdp_semantics_ = original_semantics;
+    return caller_ && callee_;
+  }
+
+  bool CreatePeerConnectionWrappersWithConfig(
+      const PeerConnectionInterface::RTCConfiguration& caller_config,
+      const PeerConnectionInterface::RTCConfiguration& callee_config) {
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", nullptr, &caller_config,
+        webrtc::PeerConnectionDependencies(nullptr), nullptr,
+        /*reset_encoder_factory=*/false,
+        /*reset_decoder_factory=*/false);
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", nullptr, &callee_config,
+        webrtc::PeerConnectionDependencies(nullptr), nullptr,
+        /*reset_encoder_factory=*/false,
+        /*reset_decoder_factory=*/false);
+    return caller_ && callee_;
+  }
+
+  bool CreatePeerConnectionWrappersWithConfigAndDeps(
+      const PeerConnectionInterface::RTCConfiguration& caller_config,
+      webrtc::PeerConnectionDependencies caller_dependencies,
+      const PeerConnectionInterface::RTCConfiguration& callee_config,
+      webrtc::PeerConnectionDependencies callee_dependencies) {
+    caller_ =
+        CreatePeerConnectionWrapper("Caller", nullptr, &caller_config,
+                                    std::move(caller_dependencies), nullptr,
+                                    /*reset_encoder_factory=*/false,
+                                    /*reset_decoder_factory=*/false);
+    callee_ =
+        CreatePeerConnectionWrapper("Callee", nullptr, &callee_config,
+                                    std::move(callee_dependencies), nullptr,
+                                    /*reset_encoder_factory=*/false,
+                                    /*reset_decoder_factory=*/false);
+    return caller_ && callee_;
+  }
+
+  bool CreatePeerConnectionWrappersWithOptions(
+      const PeerConnectionFactory::Options& caller_options,
+      const PeerConnectionFactory::Options& callee_options) {
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", &caller_options, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr), nullptr,
+        /*reset_encoder_factory=*/false,
+        /*reset_decoder_factory=*/false);
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", &callee_options, nullptr,
+        webrtc::PeerConnectionDependencies(nullptr), nullptr,
+        /*reset_encoder_factory=*/false,
+        /*reset_decoder_factory=*/false);
+    return caller_ && callee_;
+  }
+
+  bool CreatePeerConnectionWrappersWithFakeRtcEventLog() {
+    PeerConnectionInterface::RTCConfiguration default_config;
+    caller_ = CreatePeerConnectionWrapperWithFakeRtcEventLog(
+        "Caller", nullptr, &default_config,
+        webrtc::PeerConnectionDependencies(nullptr));
+    callee_ = CreatePeerConnectionWrapperWithFakeRtcEventLog(
+        "Callee", nullptr, &default_config,
+        webrtc::PeerConnectionDependencies(nullptr));
+    return caller_ && callee_;
+  }
+
+  std::unique_ptr<PeerConnectionIntegrationWrapper>
+  CreatePeerConnectionWrapperWithAlternateKey() {
+    std::unique_ptr<FakeRTCCertificateGenerator> cert_generator(
+        new FakeRTCCertificateGenerator());
+    cert_generator->use_alternate_key();
+
+    webrtc::PeerConnectionDependencies dependencies(nullptr);
+    dependencies.cert_generator = std::move(cert_generator);
+    return CreatePeerConnectionWrapper("New Peer", nullptr, nullptr,
+                                       std::move(dependencies), nullptr,
+                                       /*reset_encoder_factory=*/false,
+                                       /*reset_decoder_factory=*/false);
+  }
+
+  bool CreateOneDirectionalPeerConnectionWrappers(bool caller_to_callee) {
+    caller_ = CreatePeerConnectionWrapper(
+        "Caller", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
+        nullptr,
+        /*reset_encoder_factory=*/!caller_to_callee,
+        /*reset_decoder_factory=*/caller_to_callee);
+    callee_ = CreatePeerConnectionWrapper(
+        "Callee", nullptr, nullptr, webrtc::PeerConnectionDependencies(nullptr),
+        nullptr,
+        /*reset_encoder_factory=*/caller_to_callee,
+        /*reset_decoder_factory=*/!caller_to_callee);
+    return caller_ && callee_;
+  }
+
+  cricket::TestTurnServer* CreateTurnServer(
+      rtc::SocketAddress internal_address,
+      rtc::SocketAddress external_address,
+      cricket::ProtocolType type = cricket::ProtocolType::PROTO_UDP,
+      const std::string& common_name = "test turn server") {
+    rtc::Thread* thread = network_thread();
+    std::unique_ptr<cricket::TestTurnServer> turn_server =
+        network_thread()->Invoke<std::unique_ptr<cricket::TestTurnServer>>(
+            RTC_FROM_HERE,
+            [thread, internal_address, external_address, type, common_name] {
+              return std::make_unique<cricket::TestTurnServer>(
+                  thread, internal_address, external_address, type,
+                  /*ignore_bad_certs=*/true, common_name);
+            });
+    turn_servers_.push_back(std::move(turn_server));
+    // Interactions with the turn server should be done on the network thread.
+    return turn_servers_.back().get();
+  }
+
+  cricket::TestTurnCustomizer* CreateTurnCustomizer() {
+    std::unique_ptr<cricket::TestTurnCustomizer> turn_customizer =
+        network_thread()->Invoke<std::unique_ptr<cricket::TestTurnCustomizer>>(
+            RTC_FROM_HERE,
+            [] { return std::make_unique<cricket::TestTurnCustomizer>(); });
+    turn_customizers_.push_back(std::move(turn_customizer));
+    // Interactions with the turn customizer should be done on the network
+    // thread.
+    return turn_customizers_.back().get();
+  }
+
+  // Checks that the function counters for a TestTurnCustomizer are greater than
+  // 0.
+  void ExpectTurnCustomizerCountersIncremented(
+      cricket::TestTurnCustomizer* turn_customizer) {
+    unsigned int allow_channel_data_counter =
+        network_thread()->Invoke<unsigned int>(
+            RTC_FROM_HERE, [turn_customizer] {
+              return turn_customizer->allow_channel_data_cnt_;
+            });
+    EXPECT_GT(allow_channel_data_counter, 0u);
+    unsigned int modify_counter = network_thread()->Invoke<unsigned int>(
+        RTC_FROM_HERE,
+        [turn_customizer] { return turn_customizer->modify_cnt_; });
+    EXPECT_GT(modify_counter, 0u);
+  }
+
+  // Once called, SDP blobs and ICE candidates will be automatically signaled
+  // between PeerConnections.
+  void ConnectFakeSignaling() {
+    caller_->set_signaling_message_receiver(callee_.get());
+    callee_->set_signaling_message_receiver(caller_.get());
+  }
+
+  // Once called, SDP blobs will be automatically signaled between
+  // PeerConnections. Note that ICE candidates will not be signaled unless they
+  // are in the exchanged SDP blobs.
+  void ConnectFakeSignalingForSdpOnly() {
+    ConnectFakeSignaling();
+    SetSignalIceCandidates(false);
+  }
+
+  void SetSignalingDelayMs(int delay_ms) {
+    caller_->set_signaling_delay_ms(delay_ms);
+    callee_->set_signaling_delay_ms(delay_ms);
+  }
+
+  void SetSignalIceCandidates(bool signal) {
+    caller_->set_signal_ice_candidates(signal);
+    callee_->set_signal_ice_candidates(signal);
+  }
+
+  // Messages may get lost on the unreliable DataChannel, so we send multiple
+  // times to avoid test flakiness.
+  void SendRtpDataWithRetries(webrtc::DataChannelInterface* dc,
+                              const std::string& data,
+                              int retries) {
+    for (int i = 0; i < retries; ++i) {
+      dc->Send(DataBuffer(data));
+    }
+  }
+
+  rtc::Thread* network_thread() { return network_thread_.get(); }
+
+  rtc::VirtualSocketServer* virtual_socket_server() { return ss_.get(); }
+
+  PeerConnectionIntegrationWrapper* caller() { return caller_.get(); }
+
+  // Set the |caller_| to the |wrapper| passed in and return the
+  // original |caller_|.
+  PeerConnectionIntegrationWrapper* SetCallerPcWrapperAndReturnCurrent(
+      PeerConnectionIntegrationWrapper* wrapper) {
+    PeerConnectionIntegrationWrapper* old = caller_.release();
+    caller_.reset(wrapper);
+    return old;
+  }
+
+  PeerConnectionIntegrationWrapper* callee() { return callee_.get(); }
+
+  // Set the |callee_| to the |wrapper| passed in and return the
+  // original |callee_|.
+  PeerConnectionIntegrationWrapper* SetCalleePcWrapperAndReturnCurrent(
+      PeerConnectionIntegrationWrapper* wrapper) {
+    PeerConnectionIntegrationWrapper* old = callee_.release();
+    callee_.reset(wrapper);
+    return old;
+  }
+
+  void SetPortAllocatorFlags(uint32_t caller_flags, uint32_t callee_flags) {
+    network_thread()->Invoke<void>(RTC_FROM_HERE, [this, caller_flags] {
+      caller()->port_allocator()->set_flags(caller_flags);
+    });
+    network_thread()->Invoke<void>(RTC_FROM_HERE, [this, callee_flags] {
+      callee()->port_allocator()->set_flags(callee_flags);
+    });
+  }
+
+  rtc::FirewallSocketServer* firewall() const { return fss_.get(); }
+
+  // Expects the provided number of new frames to be received within
+  // kMaxWaitForFramesMs. The new expected frames are specified in
+  // |media_expectations|. Returns false if any of the expectations were
+  // not met.
+  bool ExpectNewFrames(const MediaExpectations& media_expectations) {
+    // Make sure there are no bogus tracks confusing the issue.
+    caller()->RemoveUnusedVideoRenderers();
+    callee()->RemoveUnusedVideoRenderers();
+    // First initialize the expected frame counts based upon the current
+    // frame count.
+    int total_caller_audio_frames_expected = caller()->audio_frames_received();
+    if (media_expectations.caller_audio_expectation_ ==
+        MediaExpectations::kExpectSomeFrames) {
+      total_caller_audio_frames_expected +=
+          media_expectations.caller_audio_frames_expected_;
+    }
+    int total_caller_video_frames_expected =
+        caller()->min_video_frames_received_per_track();
+    if (media_expectations.caller_video_expectation_ ==
+        MediaExpectations::kExpectSomeFrames) {
+      total_caller_video_frames_expected +=
+          media_expectations.caller_video_frames_expected_;
+    }
+    int total_callee_audio_frames_expected = callee()->audio_frames_received();
+    if (media_expectations.callee_audio_expectation_ ==
+        MediaExpectations::kExpectSomeFrames) {
+      total_callee_audio_frames_expected +=
+          media_expectations.callee_audio_frames_expected_;
+    }
+    int total_callee_video_frames_expected =
+        callee()->min_video_frames_received_per_track();
+    if (media_expectations.callee_video_expectation_ ==
+        MediaExpectations::kExpectSomeFrames) {
+      total_callee_video_frames_expected +=
+          media_expectations.callee_video_frames_expected_;
+    }
+
+    // Wait for the expected frames.
+    EXPECT_TRUE_WAIT(caller()->audio_frames_received() >=
+                             total_caller_audio_frames_expected &&
+                         caller()->min_video_frames_received_per_track() >=
+                             total_caller_video_frames_expected &&
+                         callee()->audio_frames_received() >=
+                             total_callee_audio_frames_expected &&
+                         callee()->min_video_frames_received_per_track() >=
+                             total_callee_video_frames_expected,
+                     kMaxWaitForFramesMs);
+    bool expectations_correct =
+        caller()->audio_frames_received() >=
+            total_caller_audio_frames_expected &&
+        caller()->min_video_frames_received_per_track() >=
+            total_caller_video_frames_expected &&
+        callee()->audio_frames_received() >=
+            total_callee_audio_frames_expected &&
+        callee()->min_video_frames_received_per_track() >=
+            total_callee_video_frames_expected;
+
+    // After the combined wait, print out a more detailed message upon
+    // failure.
+    EXPECT_GE(caller()->audio_frames_received(),
+              total_caller_audio_frames_expected);
+    EXPECT_GE(caller()->min_video_frames_received_per_track(),
+              total_caller_video_frames_expected);
+    EXPECT_GE(callee()->audio_frames_received(),
+              total_callee_audio_frames_expected);
+    EXPECT_GE(callee()->min_video_frames_received_per_track(),
+              total_callee_video_frames_expected);
+
+    // We want to make sure nothing unexpected was received.
+    if (media_expectations.caller_audio_expectation_ ==
+        MediaExpectations::kExpectNoFrames) {
+      EXPECT_EQ(caller()->audio_frames_received(),
+                total_caller_audio_frames_expected);
+      if (caller()->audio_frames_received() !=
+          total_caller_audio_frames_expected) {
+        expectations_correct = false;
+      }
+    }
+    if (media_expectations.caller_video_expectation_ ==
+        MediaExpectations::kExpectNoFrames) {
+      EXPECT_EQ(caller()->min_video_frames_received_per_track(),
+                total_caller_video_frames_expected);
+      if (caller()->min_video_frames_received_per_track() !=
+          total_caller_video_frames_expected) {
+        expectations_correct = false;
+      }
+    }
+    if (media_expectations.callee_audio_expectation_ ==
+        MediaExpectations::kExpectNoFrames) {
+      EXPECT_EQ(callee()->audio_frames_received(),
+                total_callee_audio_frames_expected);
+      if (callee()->audio_frames_received() !=
+          total_callee_audio_frames_expected) {
+        expectations_correct = false;
+      }
+    }
+    if (media_expectations.callee_video_expectation_ ==
+        MediaExpectations::kExpectNoFrames) {
+      EXPECT_EQ(callee()->min_video_frames_received_per_track(),
+                total_callee_video_frames_expected);
+      if (callee()->min_video_frames_received_per_track() !=
+          total_callee_video_frames_expected) {
+        expectations_correct = false;
+      }
+    }
+    return expectations_correct;
+  }
+
+  void ClosePeerConnections() {
+    caller()->pc()->Close();
+    callee()->pc()->Close();
+  }
+
+  void TestNegotiatedCipherSuite(
+      const PeerConnectionFactory::Options& caller_options,
+      const PeerConnectionFactory::Options& callee_options,
+      int expected_cipher_suite) {
+    ASSERT_TRUE(CreatePeerConnectionWrappersWithOptions(caller_options,
+                                                        callee_options));
+    ConnectFakeSignaling();
+    caller()->AddAudioVideoTracks();
+    callee()->AddAudioVideoTracks();
+    caller()->CreateAndSetAndSignalOffer();
+    ASSERT_TRUE_WAIT(DtlsConnected(), kDefaultTimeout);
+    EXPECT_EQ_WAIT(rtc::SrtpCryptoSuiteToName(expected_cipher_suite),
+                   caller()->OldGetStats()->SrtpCipher(), kDefaultTimeout);
+    // TODO(bugs.webrtc.org/9456): Fix it.
+    EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(
+                            "WebRTC.PeerConnection.SrtpCryptoSuite.Audio",
+                            expected_cipher_suite));
+  }
+
+  void TestGcmNegotiationUsesCipherSuite(bool local_gcm_enabled,
+                                         bool remote_gcm_enabled,
+                                         bool aes_ctr_enabled,
+                                         int expected_cipher_suite) {
+    PeerConnectionFactory::Options caller_options;
+    caller_options.crypto_options.srtp.enable_gcm_crypto_suites =
+        local_gcm_enabled;
+    caller_options.crypto_options.srtp.enable_aes128_sha1_80_crypto_cipher =
+        aes_ctr_enabled;
+    PeerConnectionFactory::Options callee_options;
+    callee_options.crypto_options.srtp.enable_gcm_crypto_suites =
+        remote_gcm_enabled;
+    callee_options.crypto_options.srtp.enable_aes128_sha1_80_crypto_cipher =
+        aes_ctr_enabled;
+    TestNegotiatedCipherSuite(caller_options, callee_options,
+                              expected_cipher_suite);
+  }
+
+ protected:
+  SdpSemantics sdp_semantics_;
+
+ private:
+  // |ss_| is used by |network_thread_| so it must be destroyed later.
+  std::unique_ptr<rtc::VirtualSocketServer> ss_;
+  std::unique_ptr<rtc::FirewallSocketServer> fss_;
+  // |network_thread_| and |worker_thread_| are used by both
+  // |caller_| and |callee_| so they must be destroyed
+  // later.
+  std::unique_ptr<rtc::Thread> network_thread_;
+  std::unique_ptr<rtc::Thread> worker_thread_;
+  // The turn servers and turn customizers should be accessed & deleted on the
+  // network thread to avoid a race with the socket read/write that occurs
+  // on the network thread.
+  std::vector<std::unique_ptr<cricket::TestTurnServer>> turn_servers_;
+  std::vector<std::unique_ptr<cricket::TestTurnCustomizer>> turn_customizers_;
+  std::unique_ptr<PeerConnectionIntegrationWrapper> caller_;
+  std::unique_ptr<PeerConnectionIntegrationWrapper> callee_;
+};
+
+}  // namespace webrtc
+
+#endif  // PC_TEST_INTEGRATION_TEST_HELPERS_H_
diff --git a/tools_webrtc/iwyu/apply-iwyu b/tools_webrtc/iwyu/apply-iwyu
index 65950d3..691ca8e 100755
--- a/tools_webrtc/iwyu/apply-iwyu
+++ b/tools_webrtc/iwyu/apply-iwyu
@@ -15,28 +15,48 @@
 # the following variable to "yes". This is a style guide violation.
 REMOVE_CC_INCLUDES=no
 
-if [ ! -f $FILE.h ]; then
-   echo "$FILE.h not found"
-   exit 1
+if [ ! -f $FILE ]; then
+  # See if we have the root name of a .cc/.h pair
+  if [ ! -f $FILE.h ]; then
+    echo "$FILE.h not found"
+    exit 1
+  fi
+  FILE_H=$FILE.h
+  if [ ! -f $FILE.cc ]; then
+    echo "$FILE.cc not found"
+    exit 1
+  fi
+  FILE_CC=$FILE.cc
+else
+  # Exact file, no .h file
+  FILE_CC=$FILE
+  FILE_H=""
 fi
 
-if [ ! -f $FILE.cc ]; then
-   echo "$FILE.cc not found"
-   exit 1
-fi 
-
-iwyu -Xiwyu --no_fwd_decls -D__X86_64__  -DWEBRTC_POSIX -I . -I third_party/abseil-cpp $FILE.cc |& fix_include || echo "Some files modified"
+iwyu -Xiwyu --no_fwd_decls -D__X86_64__  -DWEBRTC_POSIX -I . \
+  -I third_party/abseil-cpp \
+  -I third_party/googletest/src/googlemock/include \
+  -I third_party/googletest/src/googletest/include \
+  $FILE_CC |& fix_include || echo "Some files modified"
 
 if [ $REMOVE_CC_INCLUDES == "yes" ]; then
-  grep ^#include $FILE.h | grep -v -f - $FILE.cc > $FILE.ccnew
-  grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE.ccnew > $FILE.cc
+  if [ -n "$FILE_H" ]; then
+    # Don't include in .cc what's already included in .h
+    grep ^#include $FILE_H | grep -v -f - $FILE_CC > $FILE_CC.new
+  else
+    cp $FILE_CC $FILE_CC.new
+  fi
+  # Don't include stuff on the banlist
+  grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE_CC.new > $FILE_CC
   rm $FILE.ccnew
 else
-  grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE.cc > $FILE.ccnew
-  mv $FILE.ccnew $FILE.cc
+  grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE_CC > $FILE_CC.new
+  mv $FILE_CC.new $FILE_CC
 fi
-grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE.h > $FILE.hnew
-mv $FILE.hnew $FILE.h
+if [ -n "$FILE_H" ]; then
+  grep -v -f tools_webrtc/iwyu/iwyu-filter-list $FILE_H > $FILE_H.new
+  mv $FILE_H.new $FILE_H
+fi
 
 echo "Finished. Check diff, compile and git cl format before uploading."