summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/pc/slow_peer_connection_integration_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/pc/slow_peer_connection_integration_test.cc')
-rw-r--r--third_party/libwebrtc/pc/slow_peer_connection_integration_test.cc512
1 files changed, 512 insertions, 0 deletions
diff --git a/third_party/libwebrtc/pc/slow_peer_connection_integration_test.cc b/third_party/libwebrtc/pc/slow_peer_connection_integration_test.cc
new file mode 100644
index 0000000000..b45571ec22
--- /dev/null
+++ b/third_party/libwebrtc/pc/slow_peer_connection_integration_test.cc
@@ -0,0 +1,512 @@
+/*
+ * Copyright 2022 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// This file is intended for PeerConnection integration tests that are
+// slow to execute (currently defined as more than 5 seconds per test).
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/container.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/dtmf_sender_interface.h"
+#include "api/peer_connection_interface.h"
+#include "api/rtp_receiver_interface.h"
+#include "api/scoped_refptr.h"
+#include "api/units/time_delta.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 "pc/test/integration_test_helpers.h"
+#include "pc/test/mock_peer_connection_observers.h"
+#include "rtc_base/fake_clock.h"
+#include "rtc_base/fake_network.h"
+#include "rtc_base/firewall_socket_server.h"
+#include "rtc_base/gunit.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/socket_address.h"
+#include "rtc_base/ssl_certificate.h"
+#include "rtc_base/test_certificate_verifier.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+class PeerConnectionIntegrationTest
+ : public PeerConnectionIntegrationBaseTest,
+ public ::testing::WithParamInterface<
+ std::tuple<SdpSemantics, std::string>> {
+ protected:
+ PeerConnectionIntegrationTest()
+ : PeerConnectionIntegrationBaseTest(std::get<0>(GetParam()),
+ std::get<1>(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 PeerConnectionIntegrationTestWithFakeClock
+ : public FakeClockForTest,
+ public PeerConnectionIntegrationTest {};
+
+class PeerConnectionIntegrationTestPlanB
+ : public PeerConnectionIntegrationBaseTest {
+ protected:
+ PeerConnectionIntegrationTestPlanB()
+ : PeerConnectionIntegrationBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
+};
+
+class PeerConnectionIntegrationTestUnifiedPlan
+ : public PeerConnectionIntegrationBaseTest {
+ protected:
+ PeerConnectionIntegrationTestUnifiedPlan()
+ : PeerConnectionIntegrationBaseTest(SdpSemantics::kUnifiedPlan) {}
+};
+
+// Test the OnFirstPacketReceived callback from audio/video RtpReceivers. This
+// includes testing that the callback is invoked if an observer is connected
+// after the first packet has already been received.
+TEST_P(PeerConnectionIntegrationTest,
+ RtpReceiverObserverOnFirstPacketReceived) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->AddAudioVideoTracks();
+ callee()->AddAudioVideoTracks();
+ // Start offer/answer exchange and wait for it to complete.
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ // Should be one receiver each for audio/video.
+ EXPECT_EQ(2U, caller()->rtp_receiver_observers().size());
+ EXPECT_EQ(2U, callee()->rtp_receiver_observers().size());
+ // Wait for all "first packet received" callbacks to be fired.
+ EXPECT_TRUE_WAIT(
+ absl::c_all_of(caller()->rtp_receiver_observers(),
+ [](const std::unique_ptr<MockRtpReceiverObserver>& o) {
+ return o->first_packet_received();
+ }),
+ kMaxWaitForFramesMs);
+ EXPECT_TRUE_WAIT(
+ absl::c_all_of(callee()->rtp_receiver_observers(),
+ [](const std::unique_ptr<MockRtpReceiverObserver>& o) {
+ return o->first_packet_received();
+ }),
+ kMaxWaitForFramesMs);
+ // If new observers are set after the first packet was already received, the
+ // callback should still be invoked.
+ caller()->ResetRtpReceiverObservers();
+ callee()->ResetRtpReceiverObservers();
+ EXPECT_EQ(2U, caller()->rtp_receiver_observers().size());
+ EXPECT_EQ(2U, callee()->rtp_receiver_observers().size());
+ EXPECT_TRUE(
+ absl::c_all_of(caller()->rtp_receiver_observers(),
+ [](const std::unique_ptr<MockRtpReceiverObserver>& o) {
+ return o->first_packet_received();
+ }));
+ EXPECT_TRUE(
+ absl::c_all_of(callee()->rtp_receiver_observers(),
+ [](const std::unique_ptr<MockRtpReceiverObserver>& o) {
+ return o->first_packet_received();
+ }));
+}
+
+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_;
+};
+
+TEST_P(PeerConnectionIntegrationTest,
+ SSLCertificateVerifierFailureUsedForTurnConnectionsFailsConnection) {
+ static const rtc::SocketAddress turn_server_internal_address{"88.88.88.0",
+ 3478};
+ static const rtc::SocketAddress turn_server_external_address{"88.88.88.1", 0};
+
+ // Enable TCP-TLS for the fake turn server. We need to pass in 88.88.88.0 so
+ // that host name verification passes on the fake certificate.
+ CreateTurnServer(turn_server_internal_address, turn_server_external_address,
+ cricket::PROTO_TLS, "88.88.88.0");
+
+ webrtc::PeerConnectionInterface::IceServer ice_server;
+ ice_server.urls.push_back("turns:88.88.88.0:3478?transport=tcp");
+ ice_server.username = "test";
+ ice_server.password = "test";
+
+ PeerConnectionInterface::RTCConfiguration client_1_config;
+ client_1_config.servers.push_back(ice_server);
+ client_1_config.type = webrtc::PeerConnectionInterface::kRelay;
+
+ PeerConnectionInterface::RTCConfiguration client_2_config;
+ client_2_config.servers.push_back(ice_server);
+ // Setting the type to kRelay forces the connection to go through a TURN
+ // server.
+ client_2_config.type = webrtc::PeerConnectionInterface::kRelay;
+
+ // Get a copy to the pointer so we can verify calls later.
+ rtc::TestCertificateVerifier* client_1_cert_verifier =
+ new rtc::TestCertificateVerifier();
+ client_1_cert_verifier->verify_certificate_ = false;
+ rtc::TestCertificateVerifier* client_2_cert_verifier =
+ new rtc::TestCertificateVerifier();
+ client_2_cert_verifier->verify_certificate_ = false;
+
+ // Create the dependencies with the test certificate verifier.
+ webrtc::PeerConnectionDependencies client_1_deps(nullptr);
+ client_1_deps.tls_cert_verifier =
+ std::unique_ptr<rtc::TestCertificateVerifier>(client_1_cert_verifier);
+ webrtc::PeerConnectionDependencies client_2_deps(nullptr);
+ client_2_deps.tls_cert_verifier =
+ std::unique_ptr<rtc::TestCertificateVerifier>(client_2_cert_verifier);
+
+ ASSERT_TRUE(CreatePeerConnectionWrappersWithConfigAndDeps(
+ client_1_config, std::move(client_1_deps), client_2_config,
+ std::move(client_2_deps)));
+ ConnectFakeSignaling();
+
+ // Set "offer to receive audio/video" without adding any tracks, so we just
+ // set up ICE/DTLS with no media.
+ PeerConnectionInterface::RTCOfferAnswerOptions options;
+ options.offer_to_receive_audio = 1;
+ options.offer_to_receive_video = 1;
+ caller()->SetOfferAnswerOptions(options);
+ caller()->CreateAndSetAndSignalOffer();
+ bool wait_res = true;
+ // TODO(bugs.webrtc.org/9219): When IceConnectionState is implemented
+ // properly, should be able to just wait for a state of "failed" instead of
+ // waiting a fixed 10 seconds.
+ WAIT_(DtlsConnected(), kDefaultTimeout, wait_res);
+ ASSERT_FALSE(wait_res);
+
+ EXPECT_GT(client_1_cert_verifier->call_count_, 0u);
+ EXPECT_GT(client_2_cert_verifier->call_count_, 0u);
+}
+
+// Test that we can get capture start ntp time.
+TEST_P(PeerConnectionIntegrationTest, GetCaptureStartNtpTimeWithOldStatsApi) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->AddAudioTrack();
+
+ callee()->AddAudioTrack();
+
+ // Do offer/answer, wait for the callee to receive some frames.
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+
+ // Get the remote audio track created on the receiver, so they can be used as
+ // GetStats filters.
+ auto receivers = callee()->pc()->GetReceivers();
+ ASSERT_EQ(1u, receivers.size());
+ auto remote_audio_track = receivers[0]->track();
+
+ // Get the audio output level stats. Note that the level is not available
+ // until an RTCP packet has been received.
+ EXPECT_TRUE_WAIT(callee()->OldGetStatsForTrack(remote_audio_track.get())
+ ->CaptureStartNtpTime() > 0,
+ 2 * kMaxWaitForFramesMs);
+}
+
+// Test that firewalling the ICE connection causes the clients to identify the
+// disconnected state and then removing the firewall causes them to reconnect.
+class PeerConnectionIntegrationIceStatesTest
+ : public PeerConnectionIntegrationBaseTest,
+ public ::testing::WithParamInterface<
+ std::tuple<SdpSemantics, std::tuple<std::string, uint32_t>>> {
+ protected:
+ PeerConnectionIntegrationIceStatesTest()
+ : PeerConnectionIntegrationBaseTest(std::get<0>(GetParam())) {
+ port_allocator_flags_ = std::get<1>(std::get<1>(GetParam()));
+ }
+
+ void StartStunServer(const SocketAddress& server_address) {
+ stun_server_.reset(
+ cricket::TestStunServer::Create(firewall(), server_address));
+ }
+
+ bool TestIPv6() {
+ return (port_allocator_flags_ & cricket::PORTALLOCATOR_ENABLE_IPV6);
+ }
+
+ void SetPortAllocatorFlags() {
+ PeerConnectionIntegrationBaseTest::SetPortAllocatorFlags(
+ port_allocator_flags_, port_allocator_flags_);
+ }
+
+ std::vector<SocketAddress> CallerAddresses() {
+ std::vector<SocketAddress> addresses;
+ addresses.push_back(SocketAddress("1.1.1.1", 0));
+ if (TestIPv6()) {
+ addresses.push_back(SocketAddress("1111:0:a:b:c:d:e:f", 0));
+ }
+ return addresses;
+ }
+
+ std::vector<SocketAddress> CalleeAddresses() {
+ std::vector<SocketAddress> addresses;
+ addresses.push_back(SocketAddress("2.2.2.2", 0));
+ if (TestIPv6()) {
+ addresses.push_back(SocketAddress("2222:0:a:b:c:d:e:f", 0));
+ }
+ return addresses;
+ }
+
+ void SetUpNetworkInterfaces() {
+ // Remove the default interfaces added by the test infrastructure.
+ caller()->network_manager()->RemoveInterface(kDefaultLocalAddress);
+ callee()->network_manager()->RemoveInterface(kDefaultLocalAddress);
+
+ // Add network addresses for test.
+ for (const auto& caller_address : CallerAddresses()) {
+ caller()->network_manager()->AddInterface(caller_address);
+ }
+ for (const auto& callee_address : CalleeAddresses()) {
+ callee()->network_manager()->AddInterface(callee_address);
+ }
+ }
+
+ private:
+ uint32_t port_allocator_flags_;
+ std::unique_ptr<cricket::TestStunServer> stun_server_;
+};
+
+// Ensure FakeClockForTest is constructed first (see class for rationale).
+class PeerConnectionIntegrationIceStatesTestWithFakeClock
+ : public FakeClockForTest,
+ public PeerConnectionIntegrationIceStatesTest {};
+
+#if !defined(THREAD_SANITIZER)
+// This test provokes TSAN errors. bugs.webrtc.org/11282
+
+// Tests that the PeerConnection goes through all the ICE gathering/connection
+// states over the duration of the call. This includes Disconnected and Failed
+// states, induced by putting a firewall between the peers and waiting for them
+// to time out.
+TEST_P(PeerConnectionIntegrationIceStatesTestWithFakeClock, VerifyIceStates) {
+ const SocketAddress kStunServerAddress =
+ SocketAddress("99.99.99.1", cricket::STUN_SERVER_PORT);
+ StartStunServer(kStunServerAddress);
+
+ PeerConnectionInterface::RTCConfiguration config;
+ PeerConnectionInterface::IceServer ice_stun_server;
+ ice_stun_server.urls.push_back(
+ "stun:" + kStunServerAddress.HostAsURIString() + ":" +
+ kStunServerAddress.PortAsString());
+ config.servers.push_back(ice_stun_server);
+
+ ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config));
+ ConnectFakeSignaling();
+ SetPortAllocatorFlags();
+ SetUpNetworkInterfaces();
+ caller()->AddAudioVideoTracks();
+ callee()->AddAudioVideoTracks();
+
+ // Initial state before anything happens.
+ ASSERT_EQ(PeerConnectionInterface::kIceGatheringNew,
+ caller()->ice_gathering_state());
+ ASSERT_EQ(PeerConnectionInterface::kIceConnectionNew,
+ caller()->ice_connection_state());
+ ASSERT_EQ(PeerConnectionInterface::kIceConnectionNew,
+ caller()->standardized_ice_connection_state());
+
+ // Start the call by creating the offer, setting it as the local description,
+ // then sending it to the peer who will respond with an answer. This happens
+ // asynchronously so that we can watch the states as it runs in the
+ // background.
+ caller()->CreateAndSetAndSignalOffer();
+
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
+ caller()->ice_connection_state(), kDefaultTimeout,
+ FakeClock());
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
+ caller()->standardized_ice_connection_state(),
+ kDefaultTimeout, FakeClock());
+
+ // Verify that the observer was notified of the intermediate transitions.
+ EXPECT_THAT(caller()->ice_connection_state_history(),
+ ElementsAre(PeerConnectionInterface::kIceConnectionChecking,
+ PeerConnectionInterface::kIceConnectionConnected,
+ PeerConnectionInterface::kIceConnectionCompleted));
+ EXPECT_THAT(caller()->standardized_ice_connection_state_history(),
+ ElementsAre(PeerConnectionInterface::kIceConnectionChecking,
+ PeerConnectionInterface::kIceConnectionConnected,
+ PeerConnectionInterface::kIceConnectionCompleted));
+ EXPECT_THAT(
+ caller()->peer_connection_state_history(),
+ ElementsAre(PeerConnectionInterface::PeerConnectionState::kConnecting,
+ PeerConnectionInterface::PeerConnectionState::kConnected));
+ EXPECT_THAT(caller()->ice_gathering_state_history(),
+ ElementsAre(PeerConnectionInterface::kIceGatheringGathering,
+ PeerConnectionInterface::kIceGatheringComplete));
+
+ // Block connections to/from the caller and wait for ICE to become
+ // disconnected.
+ for (const auto& caller_address : CallerAddresses()) {
+ firewall()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, caller_address);
+ }
+ RTC_LOG(LS_INFO) << "Firewall rules applied";
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
+ caller()->ice_connection_state(), kDefaultTimeout,
+ FakeClock());
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionDisconnected,
+ caller()->standardized_ice_connection_state(),
+ kDefaultTimeout, FakeClock());
+
+ // Let ICE re-establish by removing the firewall rules.
+ firewall()->ClearRules();
+ RTC_LOG(LS_INFO) << "Firewall rules cleared";
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
+ caller()->ice_connection_state(), kDefaultTimeout,
+ FakeClock());
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionCompleted,
+ caller()->standardized_ice_connection_state(),
+ kDefaultTimeout, FakeClock());
+
+ // According to RFC7675, if there is no response within 30 seconds then the
+ // peer should consider the other side to have rejected the connection. This
+ // is signaled by the state transitioning to "failed".
+ constexpr int kConsentTimeout = 30000;
+ for (const auto& caller_address : CallerAddresses()) {
+ firewall()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, caller_address);
+ }
+ RTC_LOG(LS_INFO) << "Firewall rules applied again";
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionFailed,
+ caller()->ice_connection_state(), kConsentTimeout,
+ FakeClock());
+ ASSERT_EQ_SIMULATED_WAIT(PeerConnectionInterface::kIceConnectionFailed,
+ caller()->standardized_ice_connection_state(),
+ kConsentTimeout, FakeClock());
+}
+#endif
+
+// This test sets up a call that's transferred to a new caller with a different
+// DTLS fingerprint.
+TEST_P(PeerConnectionIntegrationTest, CallTransferredForCallee) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->AddAudioVideoTracks();
+ callee()->AddAudioVideoTracks();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+
+ // Keep the original peer around which will still send packets to the
+ // receiving client. These SRTP packets will be dropped.
+ std::unique_ptr<PeerConnectionIntegrationWrapper> original_peer(
+ SetCallerPcWrapperAndReturnCurrent(
+ CreatePeerConnectionWrapperWithAlternateKey().release()));
+ // TODO(deadbeef): Why do we call Close here? That goes against the comment
+ // directly above.
+ original_peer->pc()->Close();
+
+ ConnectFakeSignaling();
+ caller()->AddAudioVideoTracks();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ // Wait for some additional frames to be transmitted end-to-end.
+ MediaExpectations media_expectations;
+ media_expectations.ExpectBidirectionalAudioAndVideo();
+ ASSERT_TRUE(ExpectNewFrames(media_expectations));
+}
+
+// This test sets up a call that's transferred to a new callee with a different
+// DTLS fingerprint.
+TEST_P(PeerConnectionIntegrationTest, CallTransferredForCaller) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->AddAudioVideoTracks();
+ callee()->AddAudioVideoTracks();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+
+ // Keep the original peer around which will still send packets to the
+ // receiving client. These SRTP packets will be dropped.
+ std::unique_ptr<PeerConnectionIntegrationWrapper> original_peer(
+ SetCalleePcWrapperAndReturnCurrent(
+ CreatePeerConnectionWrapperWithAlternateKey().release()));
+ // TODO(deadbeef): Why do we call Close here? That goes against the comment
+ // directly above.
+ original_peer->pc()->Close();
+
+ ConnectFakeSignaling();
+ callee()->AddAudioVideoTracks();
+ caller()->SetOfferAnswerOptions(IceRestartOfferAnswerOptions());
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
+ // Wait for some additional frames to be transmitted end-to-end.
+ MediaExpectations media_expectations;
+ media_expectations.ExpectBidirectionalAudioAndVideo();
+ ASSERT_TRUE(ExpectNewFrames(media_expectations));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PeerConnectionIntegrationTest,
+ PeerConnectionIntegrationTest,
+ Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
+ Values("WebRTC-FrameBuffer3/arm:FrameBuffer2/",
+ "WebRTC-FrameBuffer3/arm:FrameBuffer3/",
+ "WebRTC-FrameBuffer3/arm:SyncDecoding/")));
+
+constexpr uint32_t kFlagsIPv4NoStun = cricket::PORTALLOCATOR_DISABLE_TCP |
+ cricket::PORTALLOCATOR_DISABLE_STUN |
+ cricket::PORTALLOCATOR_DISABLE_RELAY;
+constexpr uint32_t kFlagsIPv6NoStun =
+ cricket::PORTALLOCATOR_DISABLE_TCP | cricket::PORTALLOCATOR_DISABLE_STUN |
+ cricket::PORTALLOCATOR_ENABLE_IPV6 | cricket::PORTALLOCATOR_DISABLE_RELAY;
+constexpr uint32_t kFlagsIPv4Stun =
+ cricket::PORTALLOCATOR_DISABLE_TCP | cricket::PORTALLOCATOR_DISABLE_RELAY;
+
+INSTANTIATE_TEST_SUITE_P(
+ PeerConnectionIntegrationTest,
+ PeerConnectionIntegrationIceStatesTestWithFakeClock,
+ Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
+ Values(std::make_pair("IPv4 no STUN", kFlagsIPv4NoStun),
+ std::make_pair("IPv6 no STUN", kFlagsIPv6NoStun),
+ std::make_pair("IPv4 with STUN", kFlagsIPv4Stun))));
+
+} // namespace
+} // namespace webrtc