|  | /* | 
|  | *  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 <optional> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/algorithm/container.h" | 
|  | #include "absl/strings/string_view.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<SdpSemantics> { | 
|  | protected: | 
|  | PeerConnectionIntegrationTest() | 
|  | : 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(TimeDelta::Seconds(1000)); | 
|  | } | 
|  |  | 
|  | // 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"); | 
|  |  | 
|  | 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 = 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 = 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. | 
|  | PeerConnectionDependencies client_1_deps(nullptr); | 
|  | client_1_deps.tls_cert_verifier = | 
|  | std::unique_ptr<rtc::TestCertificateVerifier>(client_1_cert_verifier); | 
|  | 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_ = cricket::TestStunServer::Create(firewall(), server_address, | 
|  | *network_thread()); | 
|  | } | 
|  |  | 
|  | 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_; | 
|  | cricket::TestStunServer::StunServerPtr 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, | 
|  | Values(SdpSemantics::kPlanB_DEPRECATED, | 
|  | SdpSemantics::kUnifiedPlan)); | 
|  |  | 
|  | 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 |