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."