Move integration test helper functions from .h to .cc This makes for a cleaner .h file. Pure setters and getters are left in the .h file. Bug: None Change-Id: I4ca3911f5493884d49cbbe134fcaea88f13f441c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/470841 Commit-Queue: Harald Alvestrand <hta@webrtc.org> Auto-Submit: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47679}
diff --git a/pc/test/integration_test_helpers.cc b/pc/test/integration_test_helpers.cc index 2728edb..dad66e8 100644 --- a/pc/test/integration_test_helpers.cc +++ b/pc/test/integration_test_helpers.cc
@@ -10,10 +10,13 @@ #include "pc/test/integration_test_helpers.h" +#include <algorithm> +#include <climits> #include <cstddef> #include <cstdint> #include <memory> #include <optional> +#include <set> #include <string> #include <utility> #include <vector> @@ -22,15 +25,28 @@ #include "absl/memory/memory.h" #include "absl/strings/string_view.h" #include "api/audio/builtin_audio_processing_builder.h" +#include "api/audio_options.h" +#include "api/candidate.h" #include "api/create_modular_peer_connection_factory.h" +#include "api/crypto/crypto_options.h" +#include "api/data_channel_interface.h" +#include "api/dtls_transport_interface.h" #include "api/enable_media_with_defaults.h" #include "api/environment/environment.h" +#include "api/environment/environment_factory.h" +#include "api/field_trials.h" #include "api/jsep.h" #include "api/make_ref_counted.h" #include "api/media_stream_interface.h" +#include "api/media_types.h" #include "api/peer_connection_interface.h" #include "api/rtc_error.h" #include "api/rtc_event_log/rtc_event_log_factory.h" +#include "api/rtp_parameters.h" +#include "api/rtp_receiver_interface.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/sequence_checker.h" #include "api/stats/rtc_stats_report.h" @@ -41,23 +57,43 @@ #include "api/test/time_controller.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "api/video/video_rotation.h" #include "logging/rtc_event_log/fake_rtc_event_log_factory.h" #include "media/base/stream_params.h" +#include "p2p/base/port.h" +#include "p2p/test/test_turn_customizer.h" +#include "p2p/test/test_turn_server.h" +#include "pc/peer_connection.h" #include "pc/peer_connection_factory.h" +#include "pc/peer_connection_proxy.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/test/rtc_stats_obtainer.h" #include "rtc_base/checks.h" +#include "rtc_base/crypto_random.h" +#include "rtc_base/fake_mdns_responder.h" #include "rtc_base/fake_network.h" #include "rtc_base/firewall_socket_server.h" #include "rtc_base/logging.h" +#include "rtc_base/net_helper.h" +#include "rtc_base/socket_address.h" +#include "rtc_base/socket_factory.h" #include "rtc_base/socket_server.h" +#include "rtc_base/ssl_stream_adapter.h" +#include "rtc_base/task_queue_for_test.h" #include "rtc_base/thread.h" #include "rtc_base/virtual_socket_server.h" #include "system_wrappers/include/metrics.h" #include "test/create_test_environment.h" +#include "test/create_test_field_trials.h" #include "test/gmock.h" #include "test/gtest.h" +#include "test/run_loop.h" #include "test/time_controller/simulated_time_controller.h" #include "test/wait_until.h" @@ -104,118 +140,11 @@ sdp = CreateSessionDescription(sdpType, str); } -scoped_refptr<MockStatsObserver> -PeerConnectionIntegrationWrapper::OldGetStatsForTrack( - MediaStreamTrackInterface* track) { - auto observer = make_ref_counted<MockStatsObserver>(); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - EXPECT_TRUE(peer_connection_->GetStats( - observer.get(), nullptr, - PeerConnectionInterface::kStatsOutputLevelStandard)); -#pragma clang diagnostic pop - EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, - ::testing::IsTrue()), - IsRtcOk()); - return observer; -} - -scoped_refptr<const RTCStatsReport> -PeerConnectionIntegrationWrapper::NewGetStats(WaitUntilSettings settings) { - auto callback = make_ref_counted<MockRTCStatsCollectorCallback>(); - peer_connection_->GetStats(callback.get()); - EXPECT_THAT(test_->GetWaiter(settings).Until( - [&] { return callback->called(); }, ::testing::IsTrue()), - IsRtcOk()); - return callback->report(); -} - -std::unique_ptr<SessionDescriptionInterface> -PeerConnectionIntegrationWrapper::CreateOfferAndWait() { - auto observer = make_ref_counted<MockCreateSessionDescriptionObserver>(); - pc()->CreateOffer(observer.get(), offer_answer_options_); - EXPECT_TRUE(test_->GetWaiter().Until([&] { return observer->called(); })); - if (!observer->result()) { - return nullptr; +void ReplaceFirstSsrc(StreamParams& stream, uint32_t ssrc) { + stream.ssrcs[0] = ssrc; + for (auto& group : stream.ssrc_groups) { + group.ssrcs[0] = ssrc; } - auto description = observer->MoveDescription(); - if (generated_sdp_munger_) { - generated_sdp_munger_(description); - } - return description; -} - -bool PeerConnectionIntegrationWrapper::SetRemoteDescription( - std::unique_ptr<SessionDescriptionInterface> desc) { - auto observer = make_ref_counted<FakeSetRemoteDescriptionObserver>(); - std::string sdp; - EXPECT_TRUE(desc->ToString(&sdp)); - RTC_LOG(LS_INFO) << debug_name_ - << ": SetRemoteDescription SDP: type=" << desc->GetType() - << " contents=\n" - << sdp; - pc()->SetRemoteDescription(std::move(desc), observer); - RemoveUnusedVideoRenderers(); - EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, - ::testing::IsTrue()), - IsRtcOk()); - auto err = observer->error(); - if (!err.ok()) { - RTC_LOG(LS_WARNING) << debug_name_ - << ": SetRemoteDescription error: " << err.message(); - } - return observer->error().ok(); -} - -bool PeerConnectionIntegrationWrapper::SetLocalDescriptionAndSendSdpMessage( - std::unique_ptr<SessionDescriptionInterface> desc) { - auto observer = make_ref_counted<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 type=" << desc->GetType() - << " contents=\n" - << sdp; - pc()->SetLocalDescription(observer.get(), desc.release()); - RemoveUnusedVideoRenderers(); - SendSdpMessage(type, sdp); - EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, - ::testing::IsTrue()), - IsRtcOk()); - return true; -} - -std::unique_ptr<SessionDescriptionInterface> -PeerConnectionIntegrationWrapper::CreateAnswer() { - auto observer = make_ref_counted<MockCreateSessionDescriptionObserver>(); - pc()->CreateAnswer(observer.get(), offer_answer_options_); - EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, - ::testing::IsTrue()), - IsRtcOk()); - if (!observer->result()) { - return nullptr; - } - auto description = observer->MoveDescription(); - if (generated_sdp_munger_) { - generated_sdp_munger_(description); - } - return description; -} - -void PeerConnectionIntegrationWrapper::ReceiveIceMessage( - const std::string& sdp_mid, - int sdp_mline_index, - const std::string& msg) { - RTC_LOG(LS_INFO) << debug_name_ << ": ReceiveIceMessage"; - std::optional<RTCError> result; - pc()->AddIceCandidate(absl::WrapUnique(CreateIceCandidate( - sdp_mid, sdp_mline_index, msg, nullptr)), - [&result](RTCError r) { result = r; }); - EXPECT_THAT(test_->GetWaiter().Until([&] { return result.has_value(); }, - ::testing::IsTrue()), - IsRtcOk()); - EXPECT_TRUE(result.value().ok()); } int FindFirstMediaStatsIndexByKind( @@ -229,13 +158,6 @@ return -1; } -void ReplaceFirstSsrc(StreamParams& stream, uint32_t ssrc) { - stream.ssrcs[0] = ssrc; - for (auto& group : stream.ssrc_groups) { - group.ssrcs[0] = ssrc; - } -} - TaskQueueMetronome::TaskQueueMetronome(TimeDelta tick_period) : tick_period_(tick_period) {} @@ -255,7 +177,7 @@ [this] { RTC_DCHECK_RUN_ON(&sequence_checker_); std::vector<absl::AnyInvocable<void() &&>> callbacks; - callbacks_.swap(callbacks); + callbacks.swap(callbacks_); for (auto& callback : callbacks) std::move(callback)(); }), @@ -268,7 +190,373 @@ return tick_period_; } -// Implementation of PeerConnectionIntegrationWrapper functions +PeerConnectionIntegrationWrapper::PeerConnectionIntegrationWrapper( + const std::string& debug_name, + Environment env, + internal::PeerConnectionIntegrationTestBase* test) + : debug_name_(debug_name), env_(env), test_(test) {} + +PeerConnection* PeerConnectionIntegrationWrapper::pc_internal() const { + auto* pci = + static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>( + pc()); + return static_cast<PeerConnection*>(pci->internal()); +} + +void PeerConnectionIntegrationWrapper::CreateAndSetAndSignalOffer() { + std::unique_ptr<SessionDescriptionInterface> offer = CreateOfferAndWait(); + ASSERT_NE(nullptr, offer); + EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(offer))); +} + +void PeerConnectionIntegrationWrapper::AddAudioVideoTracks() { + AddAudioTrack(); + AddVideoTrack(); + ResetRtpSenderObservers(); +} + +scoped_refptr<AudioTrackInterface> +PeerConnectionIntegrationWrapper::CreateLocalAudioTrack() { + AudioOptions options; + // Disable highpass filter so that we can get all the test audio frames. + options.highpass_filter = false; + scoped_refptr<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(CreateRandomUuid(), + source.get()); +} + +scoped_refptr<VideoTrackInterface> +PeerConnectionIntegrationWrapper::CreateLocalVideoTrack() { + FakePeriodicVideoSource::Config config; + config.timestamp_offset = env_.clock().CurrentTime(); + return CreateLocalVideoTrackInternal(config); +} + +scoped_refptr<VideoTrackInterface> +PeerConnectionIntegrationWrapper::CreateLocalVideoTrackWithConfig( + FakePeriodicVideoSource::Config config) { + return CreateLocalVideoTrackInternal(config); +} + +scoped_refptr<VideoTrackInterface> +PeerConnectionIntegrationWrapper::CreateLocalVideoTrackWithRotation( + VideoRotation rotation) { + FakePeriodicVideoSource::Config config; + config.rotation = rotation; + config.timestamp_offset = env_.clock().CurrentTime(); + return CreateLocalVideoTrackInternal(config); +} + +scoped_refptr<RtpSenderInterface> PeerConnectionIntegrationWrapper::AddTrack( + scoped_refptr<MediaStreamTrackInterface> track, + const std::vector<std::string>& stream_ids) { + EXPECT_TRUE(track); + if (!track) { + return nullptr; + } + auto result = pc()->AddTrack(track, stream_ids); + EXPECT_EQ(RTCErrorType::NONE, result.error().type()); + if (result.ok()) { + return result.MoveValue(); + } else { + return nullptr; + } +} + +std::vector<scoped_refptr<RtpReceiverInterface>> +PeerConnectionIntegrationWrapper::GetReceiversOfType( + webrtc::MediaType media_type) { + std::vector<scoped_refptr<RtpReceiverInterface>> receivers; + for (const auto& receiver : pc()->GetReceivers()) { + if (receiver->media_type() == media_type) { + receivers.push_back(receiver); + } + } + return receivers; +} + +scoped_refptr<RtpTransceiverInterface> +PeerConnectionIntegrationWrapper::GetFirstTransceiverOfType( + webrtc::MediaType media_type) { + for (auto transceiver : pc()->GetTransceivers()) { + if (transceiver->receiver()->media_type() == media_type) { + return transceiver; + } + } + return nullptr; +} + +bool PeerConnectionIntegrationWrapper::SignalingStateStable() { + return pc()->signaling_state() == PeerConnectionInterface::kStable; +} + +bool PeerConnectionIntegrationWrapper::IceGatheringStateComplete() { + return pc()->ice_gathering_state() == + PeerConnectionInterface::kIceGatheringComplete; +} + +void PeerConnectionIntegrationWrapper::CreateDataChannel() { + CreateDataChannel(nullptr); +} + +void PeerConnectionIntegrationWrapper::CreateDataChannel( + const DataChannelInit* init) { + CreateDataChannel(kDataChannelLabel, init); +} + +void PeerConnectionIntegrationWrapper::CreateDataChannel( + const std::string& label, + const DataChannelInit* init) { + auto data_channel_or_error = pc()->CreateDataChannelOrError(label, init); + ASSERT_TRUE(data_channel_or_error.ok()); + data_channels_.push_back(data_channel_or_error.MoveValue()); + ASSERT_TRUE(data_channels_.back().get() != nullptr); + data_observers_.push_back( + std::make_unique<MockDataChannelObserver>(data_channels_.back().get())); +} + +DataChannelInterface* PeerConnectionIntegrationWrapper::data_channel() { + if (data_channels_.empty()) { + return nullptr; + } + return data_channels_.back().get(); +} + +MockDataChannelObserver* PeerConnectionIntegrationWrapper::data_observer() + const { + if (data_observers_.empty()) { + return nullptr; + } + return data_observers_.back().get(); +} + +std::unique_ptr<SessionDescriptionInterface> +PeerConnectionIntegrationWrapper::CreateAnswerForTest() { + return CreateAnswer(); +} + +int PeerConnectionIntegrationWrapper::audio_frames_received() const { + return fake_audio_capture_module_->frames_received(); +} + +int PeerConnectionIntegrationWrapper::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; +} + +scoped_refptr<MockStatsObserver> +PeerConnectionIntegrationWrapper::OldGetStatsForTrack( + MediaStreamTrackInterface* track) { + auto observer = make_ref_counted<MockStatsObserver>(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + EXPECT_TRUE(peer_connection_->GetStats( + observer.get(), nullptr, + PeerConnectionInterface::kStatsOutputLevelStandard)); +#pragma clang diagnostic pop + EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, + ::testing::IsTrue()), + IsRtcOk()); + return observer; +} + +scoped_refptr<MockStatsObserver> +PeerConnectionIntegrationWrapper::OldGetStats() { + return OldGetStatsForTrack(nullptr); +} + +scoped_refptr<const RTCStatsReport> +PeerConnectionIntegrationWrapper::NewGetStats(WaitUntilSettings settings) { + auto callback = make_ref_counted<MockRTCStatsCollectorCallback>(); + peer_connection_->GetStats(callback.get()); + EXPECT_THAT(test_->GetWaiter(settings).Until( + [&] { return callback->called(); }, ::testing::IsTrue()), + IsRtcOk()); + return callback->report(); +} + +scoped_refptr<const RTCStatsReport> +PeerConnectionIntegrationWrapper::NewGetStats(test::RunLoop& run_loop) { + scoped_refptr<const RTCStatsReport> report; + auto callback = RTCStatsObtainer::Create(&report, run_loop.QuitClosure()); + peer_connection_->GetStats(callback.get()); + run_loop.Run(); + EXPECT_TRUE(report); + return report; +} + +std::string PeerConnectionIntegrationWrapper::DtlsCipher() { + auto report = NewGetStats(); + if (!report) + return ""; + auto stats = report->GetStatsOfType<RTCTransportStats>(); + if (stats.empty() || !stats[0]->dtls_cipher.has_value()) + return ""; + return *stats[0]->dtls_cipher; +} + +std::string PeerConnectionIntegrationWrapper::SrtpCipher() { + auto report = NewGetStats(); + if (!report) + return ""; + auto stats = report->GetStatsOfType<RTCTransportStats>(); + if (stats.empty() || !stats[0]->srtp_cipher.has_value()) + return ""; + return *stats[0]->srtp_cipher; +} + +int PeerConnectionIntegrationWrapper::rendered_width() { + EXPECT_FALSE(fake_video_renderers_.empty()); + return fake_video_renderers_.empty() + ? 0 + : fake_video_renderers_.begin()->second->width(); +} + +int PeerConnectionIntegrationWrapper::rendered_height() { + EXPECT_FALSE(fake_video_renderers_.empty()); + return fake_video_renderers_.empty() + ? 0 + : fake_video_renderers_.begin()->second->height(); +} + +double PeerConnectionIntegrationWrapper::rendered_aspect_ratio() { + if (rendered_height() == 0) { + return 0.0; + } + return static_cast<double>(rendered_width()) / rendered_height(); +} + +VideoRotation PeerConnectionIntegrationWrapper::rendered_rotation() { + EXPECT_FALSE(fake_video_renderers_.empty()); + return fake_video_renderers_.empty() + ? kVideoRotation_0 + : fake_video_renderers_.begin()->second->rotation(); +} + +int PeerConnectionIntegrationWrapper::local_rendered_width() { + return local_video_renderer_ ? local_video_renderer_->width() : 0; +} + +int PeerConnectionIntegrationWrapper::local_rendered_height() { + return local_video_renderer_ ? local_video_renderer_->height() : 0; +} + +double PeerConnectionIntegrationWrapper::local_rendered_aspect_ratio() { + if (local_rendered_height() == 0) { + return 0.0; + } + return static_cast<double>(local_rendered_width()) / local_rendered_height(); +} + +size_t PeerConnectionIntegrationWrapper::number_of_remote_streams() { + if (!pc()) { + return 0; + } + return pc()->remote_streams()->count(); +} + +StreamCollectionInterface* PeerConnectionIntegrationWrapper::remote_streams() + const { + if (!pc()) { + ADD_FAILURE(); + return nullptr; + } + return pc()->remote_streams().get(); +} + +StreamCollectionInterface* PeerConnectionIntegrationWrapper::local_streams() { + if (!pc()) { + ADD_FAILURE(); + return nullptr; + } + return pc()->local_streams().get(); +} + +PeerConnectionInterface::SignalingState +PeerConnectionIntegrationWrapper::signaling_state() { + return pc()->signaling_state(); +} + +PeerConnectionInterface::IceConnectionState +PeerConnectionIntegrationWrapper::ice_connection_state() { + return pc()->ice_connection_state(); +} + +PeerConnectionInterface::IceConnectionState +PeerConnectionIntegrationWrapper::standardized_ice_connection_state() { + return pc()->standardized_ice_connection_state(); +} + +PeerConnectionInterface::IceGatheringState +PeerConnectionIntegrationWrapper::ice_gathering_state() { + return pc()->ice_gathering_state(); +} + +void PeerConnectionIntegrationWrapper::ResetRtpReceiverObservers() { + rtp_receiver_observers_.clear(); + for (const 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)); + } +} + +void PeerConnectionIntegrationWrapper::ResetRtpSenderObservers() { + rtp_sender_observers_.clear(); + for (const scoped_refptr<RtpSenderInterface>& sender : pc()->GetSenders()) { + std::unique_ptr<MockRtpSenderObserver> observer( + new MockRtpSenderObserver(sender->media_type())); + sender->SetObserver(observer.get()); + rtp_sender_observers_.push_back(std::move(observer)); + } +} + +Candidate PeerConnectionIntegrationWrapper::last_candidate_gathered() const { + if (last_gathered_ice_candidate_) { + return last_gathered_ice_candidate_->candidate(); + } + return Candidate(); +} + +void PeerConnectionIntegrationWrapper::SetMdnsResponder( + std::unique_ptr<FakeMdnsResponder> mdns_responder) { + RTC_DCHECK(mdns_responder != nullptr); + mdns_responder_ = mdns_responder.get(); + network_manager()->set_mdns_responder(std::move(mdns_responder)); +} + +std::unique_ptr<SessionDescriptionInterface> +PeerConnectionIntegrationWrapper::CreateOfferAndWait() { + auto observer = make_ref_counted<MockCreateSessionDescriptionObserver>(); + pc()->CreateOffer(observer.get(), offer_answer_options_); + EXPECT_TRUE(test_->GetWaiter().Until([&] { return observer->called(); })); + if (!observer->result()) { + return nullptr; + } + auto description = observer->MoveDescription(); + if (generated_sdp_munger_) { + generated_sdp_munger_(description); + } + return description; +} + +bool PeerConnectionIntegrationWrapper::Rollback() { + return SetRemoteDescription(CreateRollbackSessionDescription()); +} + void PeerConnectionIntegrationWrapper::StartWatchingDelayStats() { // Get the baseline numbers for audio_packets and audio_delay. auto received_stats = NewGetStats(); @@ -356,6 +644,102 @@ audio_concealed_stat_ = *rtp_stats->concealed_samples; } +bool PeerConnectionIntegrationWrapper::SetRemoteDescription( + std::unique_ptr<SessionDescriptionInterface> desc) { + auto observer = make_ref_counted<FakeSetRemoteDescriptionObserver>(); + std::string sdp; + EXPECT_TRUE(desc->ToString(&sdp)); + RTC_LOG(LS_INFO) << debug_name_ + << ": SetRemoteDescription SDP: type=" << desc->GetType() + << " contents=\n" + << sdp; + pc()->SetRemoteDescription(std::move(desc), observer); + RemoveUnusedVideoRenderers(); + EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, + ::testing::IsTrue()), + IsRtcOk()); + auto err = observer->error(); + if (!err.ok()) { + RTC_LOG(LS_WARNING) << debug_name_ + << ": SetRemoteDescription error: " << err.message(); + } + return observer->error().ok(); +} + +void PeerConnectionIntegrationWrapper::NegotiateCorruptionDetectionHeader() { + for (const auto& transceiver : pc()->GetTransceivers()) { + if (transceiver->media_type() != webrtc::MediaType::VIDEO) { + continue; + } + auto extensions = transceiver->GetHeaderExtensionsToNegotiate(); + for (auto& extension : extensions) { + if (extension.uri == RtpExtension::kCorruptionDetectionUri) { + extension.direction = RtpTransceiverDirection::kSendRecv; + } + } + transceiver->SetHeaderExtensionsToNegotiate(extensions); + } +} + +uint32_t PeerConnectionIntegrationWrapper::GetCorruptionScoreCount() { + scoped_refptr<const RTCStatsReport> report = NewGetStats(); + auto inbound_stream_stats = + report->GetStatsOfType<RTCInboundRtpStreamStats>(); + for (const auto& stat : inbound_stream_stats) { + if (*stat->kind == "video") { + return stat->corruption_measurements.value_or(0); + } + } + return 0; +} + +uint32_t PeerConnectionIntegrationWrapper::GetReceivedFrameCount() { + scoped_refptr<const RTCStatsReport> report = NewGetStats(); + auto inbound_stream_stats = + report->GetStatsOfType<RTCInboundRtpStreamStats>(); + for (const auto& stat : inbound_stream_stats) { + if (*stat->kind == "video") { + return stat->frames_received.value_or(0); + } + } + return 0; +} + +std::optional<int> PeerConnectionIntegrationWrapper::tls_version() { + return dtls_transport_information().tls_version(); +} + +std::optional<DtlsTransportTlsRole> +PeerConnectionIntegrationWrapper::dtls_transport_role() { + return dtls_transport_information().role(); +} + +DtlsTransportInformation +PeerConnectionIntegrationWrapper::dtls_transport_information() { + return network_thread_->BlockingCall([&] { + return pc()->GetSctpTransport()->dtls_transport()->Information(); + }); +} + +bool PeerConnectionIntegrationWrapper::SetLocalDescriptionAndSendSdpMessage( + std::unique_ptr<SessionDescriptionInterface> desc) { + auto observer = make_ref_counted<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 type=" << desc->GetType() + << " contents=\n" + << sdp; + pc()->SetLocalDescription(observer.get(), desc.release()); + RemoveUnusedVideoRenderers(); + SendSdpMessage(type, sdp); + EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, + ::testing::IsTrue()), + IsRtcOk()); + return true; +} + bool PeerConnectionIntegrationWrapper::Init( const PeerConnectionFactory::Options* options, const PeerConnectionInterface::RTCConfiguration* config, @@ -437,6 +821,330 @@ return peer_connection_.get() != nullptr; } +scoped_refptr<PeerConnectionInterface> +PeerConnectionIntegrationWrapper::CreatePeerConnection( + const PeerConnectionInterface::RTCConfiguration* config, + PeerConnectionDependencies dependencies) { + PeerConnectionInterface::RTCConfiguration modified_config; + modified_config.sdp_semantics = sdp_semantics_; + // 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; + auto peer_connection_or_error = + peer_connection_factory_->CreatePeerConnectionOrError( + modified_config, std::move(dependencies)); + return peer_connection_or_error.ok() ? peer_connection_or_error.MoveValue() + : nullptr; +} + +scoped_refptr<VideoTrackInterface> +PeerConnectionIntegrationWrapper::CreateLocalVideoTrackInternal( + 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 = TimeDelta::Millis(100); + + video_track_sources_.emplace_back( + make_ref_counted<FakePeriodicVideoTrackSource>(config, + false /* remote */)); + scoped_refptr<VideoTrackInterface> track = + peer_connection_factory_->CreateVideoTrack(video_track_sources_.back(), + CreateRandomUuid()); + if (!local_video_renderer_) { + local_video_renderer_.reset(new FakeVideoTrackRenderer(track.get())); + } + return track; +} + +void PeerConnectionIntegrationWrapper::HandleIncomingOffer( + const std::string& msg) { + RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingOffer"; + std::unique_ptr<SessionDescriptionInterface> desc = + CreateSessionDescription(SdpType::kOffer, msg); + if (received_sdp_munger_) { + received_sdp_munger_(desc); + } + + 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_(); + } + std::unique_ptr<SessionDescriptionInterface> answer = CreateAnswer(); + ASSERT_NE(nullptr, answer); + EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(answer))); +} + +void PeerConnectionIntegrationWrapper::HandleIncomingAnswer( + SdpType type, + const std::string& msg) { + RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingAnswer of type " << type; + std::unique_ptr<SessionDescriptionInterface> desc = + CreateSessionDescription(type, msg); + if (received_sdp_munger_) { + received_sdp_munger_(desc); + if (!desc) { + // Answer was "taken" by munger...so that it can be applied later ? + RTC_LOG(LS_INFO) << debug_name_ << ": answer NOT applied"; + return; + } + } + EXPECT_TRUE(SetRemoteDescription(std::move(desc))); + // Set the RtpReceiverObserver after receivers are created. + ResetRtpReceiverObservers(); +} + +std::unique_ptr<SessionDescriptionInterface> +PeerConnectionIntegrationWrapper::CreateAnswer() { + auto observer = make_ref_counted<MockCreateSessionDescriptionObserver>(); + pc()->CreateAnswer(observer.get(), offer_answer_options_); + EXPECT_THAT(test_->GetWaiter().Until([&] { return observer->called(); }, + ::testing::IsTrue()), + IsRtcOk()); + if (!observer->result()) { + return nullptr; + } + auto description = observer->MoveDescription(); + if (generated_sdp_munger_) { + generated_sdp_munger_(description); + } + return description; +} + +void PeerConnectionIntegrationWrapper::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() == webrtc::MediaType::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++; + } + } +} + +void PeerConnectionIntegrationWrapper::SendSdpMessage(SdpType type, + const std::string& msg) { + if (signaling_delay_ms_ == 0) { + RelaySdpMessageIfReceiverExists(type, msg); + } else { + Thread::Current()->PostDelayedTask( + SafeTask( + task_safety_.flag(), + [this, type, msg] { RelaySdpMessageIfReceiverExists(type, msg); }), + TimeDelta::Millis(signaling_delay_ms_)); + } +} + +void PeerConnectionIntegrationWrapper::RelaySdpMessageIfReceiverExists( + SdpType type, + const std::string& msg) { + if (signaling_message_receiver_) { + signaling_message_receiver_->ReceiveSdpMessage(type, msg); + } +} + +void PeerConnectionIntegrationWrapper::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 { + Thread::Current()->PostDelayedTask( + SafeTask(task_safety_.flag(), + [this, sdp_mid, sdp_mline_index, msg] { + RelayIceMessageIfReceiverExists(sdp_mid, sdp_mline_index, + msg); + }), + TimeDelta::Millis(signaling_delay_ms_)); + } +} + +void PeerConnectionIntegrationWrapper::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); + } +} + +void PeerConnectionIntegrationWrapper::ReceiveSdpMessage( + SdpType type, + const std::string& msg) { + if (type == SdpType::kOffer) { + HandleIncomingOffer(msg); + } else { + HandleIncomingAnswer(type, msg); + } +} + +void PeerConnectionIntegrationWrapper::ReceiveIceMessage( + const std::string& sdp_mid, + int sdp_mline_index, + const std::string& msg) { + RTC_LOG(LS_INFO) << debug_name_ << ": ReceiveIceMessage"; + std::optional<RTCError> result; + pc()->AddIceCandidate(absl::WrapUnique(CreateIceCandidate( + sdp_mid, sdp_mline_index, msg, nullptr)), + [&result](RTCError r) { result = r; }); + EXPECT_THAT(test_->GetWaiter().Until([&] { return result.has_value(); }, + ::testing::IsTrue()), + IsRtcOk()); + EXPECT_TRUE(result.value().ok()); +} + +void PeerConnectionIntegrationWrapper::OnSignalingChange( + PeerConnectionInterface::SignalingState new_state) { + EXPECT_EQ(pc()->signaling_state(), new_state); + peer_connection_signaling_state_history_.push_back(new_state); +} + +void PeerConnectionIntegrationWrapper::OnAddTrack( + scoped_refptr<RtpReceiverInterface> receiver, + const std::vector<scoped_refptr<MediaStreamInterface>>& streams) { + if (receiver->media_type() == webrtc::MediaType::VIDEO) { + 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.get()); + } +} + +void PeerConnectionIntegrationWrapper::OnRemoveTrack( + scoped_refptr<RtpReceiverInterface> receiver) { + if (receiver->media_type() == webrtc::MediaType::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 PeerConnectionIntegrationWrapper::OnRenegotiationNeeded() {} + +void PeerConnectionIntegrationWrapper::OnIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) { + EXPECT_EQ(pc()->ice_connection_state(), new_state); + ice_connection_state_history_.push_back(new_state); +} + +void PeerConnectionIntegrationWrapper::OnStandardizedIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) { + standardized_ice_connection_state_history_.push_back(new_state); +} + +void PeerConnectionIntegrationWrapper::OnConnectionChange( + PeerConnectionInterface::PeerConnectionState new_state) { + peer_connection_state_history_.push_back(new_state); + if (connection_change_callback_) { + connection_change_callback_(new_state); + } +} + +void PeerConnectionIntegrationWrapper::OnIceGatheringChange( + PeerConnectionInterface::IceGatheringState new_state) { + EXPECT_EQ(pc()->ice_gathering_state(), new_state); + ice_gathering_state_history_.push_back(new_state); +} + +void PeerConnectionIntegrationWrapper::OnIceCandidate( + const IceCandidate* candidate) { + RTC_LOG(LS_INFO) << debug_name_ << ": OnIceCandidate"; + + if (remote_async_dns_resolver_) { + const auto& local_candidate = candidate->candidate(); + if (local_candidate.address().IsUnresolvedIP()) { + RTC_DCHECK(local_candidate.is_local()); + const auto resolved_ip = mdns_responder_->GetMappedAddressForName( + local_candidate.address().hostname()); + RTC_DCHECK(!resolved_ip.IsNil()); + remote_async_dns_resolved_addr_ = local_candidate.address(); + remote_async_dns_resolved_addr_.SetResolvedIP(resolved_ip); + EXPECT_CALL(*remote_async_dns_resolver_, Start(_, _)) + .WillOnce([](const SocketAddress& addr, + absl::AnyInvocable<void()> callback) { callback(); }); + EXPECT_CALL(*remote_async_dns_resolver_, result()) + .WillOnce(ReturnRef(remote_async_dns_resolver_result_)); + EXPECT_CALL(remote_async_dns_resolver_result_, GetResolvedAddress(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(remote_async_dns_resolved_addr_), + Return(true))); + } + } + + // Check if we expected to have a candidate. + EXPECT_GT(candidates_expected_, 1); + candidates_expected_--; + std::string ice_sdp = candidate->ToString(); + 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_gathered_ice_candidate_ = + CreateIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(), + candidate->candidate()); +} + +void PeerConnectionIntegrationWrapper::OnIceCandidateError( + const std::string& address, + int port, + const std::string& url, + int error_code, + const std::string& error_text) { + error_event_ = + IceCandidateErrorEvent(address, port, url, error_code, error_text); +} + +void PeerConnectionIntegrationWrapper::OnDataChannel( + scoped_refptr<DataChannelInterface> data_channel) { + RTC_LOG(LS_INFO) << debug_name_ << ": OnDataChannel"; + data_channels_.push_back(data_channel); + data_observers_.push_back( + std::make_unique<MockDataChannelObserver>(data_channel.get())); +} + +bool PeerConnectionIntegrationWrapper::IdExists( + const RtpHeaderExtensions& extensions, + int id) { + for (const auto& extension : extensions) { + if (extension.id == id) { + return true; + } + } + return false; +} + namespace internal { // Utility class for tests that run multiple operations that cause excessive @@ -494,6 +1202,291 @@ DestroyPeerConnections(); } +bool PeerConnectionIntegrationTestBase::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() == + PeerConnectionInterface::kIceConnectionConnected || + callee()->ice_connection_state() == + PeerConnectionInterface::kIceConnectionCompleted) && + (caller()->ice_connection_state() == + PeerConnectionInterface::kIceConnectionConnected || + caller()->ice_connection_state() == + PeerConnectionInterface::kIceConnectionCompleted); +} + +void PeerConnectionIntegrationTestBase::SetFieldTrials( + absl::string_view field_trials) { + RTC_CHECK(caller_ == nullptr); + RTC_CHECK(callee_ == nullptr); + field_trials_ = std::string(field_trials); +} + +void PeerConnectionIntegrationTestBase::SetFieldTrials( + absl::string_view debug_name, + absl::string_view field_trials) { + RTC_CHECK(caller_ == nullptr); + RTC_CHECK(callee_ == nullptr); + field_trials_overrides_[std::string(debug_name)] = field_trials; +} + +std::unique_ptr<PeerConnectionIntegrationWrapper> +PeerConnectionIntegrationTestBase::CreatePeerConnectionWrapper( + const std::string& debug_name, + const PeerConnectionFactory::Options* options, + const RTCConfiguration* config, + PeerConnectionDependencies dependencies, + std::unique_ptr<FakeRtcEventLogFactory> event_log_factory, + bool reset_encoder_factory, + bool reset_decoder_factory, + bool create_media_engine) { + 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::string field_trials = field_trials_; + EnvironmentFactory env = EnvironmentFactory(env_); + + auto it = field_trials_overrides_.find(debug_name); + if (it != field_trials_overrides_.end()) { + field_trials = it->second; + dependencies.trials = std::make_unique<FieldTrials>(it->second); + } + env.Set(CreateTestFieldTrialsPtr(field_trials)); + + std::unique_ptr<PeerConnectionIntegrationWrapper> client = + CreatePeerConnectionWrapperInternal(debug_name, env.Create()); + + if (!client->Init(options, &modified_config, std::move(dependencies), + fss_.get(), network_thread_.get(), worker_thread_.get(), + std::move(event_log_factory), reset_encoder_factory, + reset_decoder_factory, create_media_engine)) { + return nullptr; + } + return client; +} + +std::unique_ptr<PeerConnectionIntegrationWrapper> +PeerConnectionIntegrationTestBase:: + CreatePeerConnectionWrapperWithFakeRtcEventLog( + const std::string& debug_name, + const PeerConnectionFactory::Options* options, + const RTCConfiguration* config, + PeerConnectionDependencies dependencies) { + return CreatePeerConnectionWrapper(debug_name, options, config, + std::move(dependencies), + std::make_unique<FakeRtcEventLogFactory>(), + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false); +} + +bool PeerConnectionIntegrationTestBase:: + 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(kCallerName, nullptr, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false); + sdp_semantics_ = callee_semantics; + callee_ = + CreatePeerConnectionWrapper(kCalleeName, nullptr, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false); + sdp_semantics_ = original_semantics; + return caller_ && callee_; +} + +bool PeerConnectionIntegrationTestBase::CreatePeerConnectionWrappersWithConfig( + const PeerConnectionInterface::RTCConfiguration& caller_config, + const PeerConnectionInterface::RTCConfiguration& callee_config, + bool create_media_engine) { + caller_ = CreatePeerConnectionWrapper( + kCallerName, nullptr, &caller_config, PeerConnectionDependencies(nullptr), + nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false, create_media_engine); + callee_ = CreatePeerConnectionWrapper( + kCalleeName, nullptr, &callee_config, PeerConnectionDependencies(nullptr), + nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false, create_media_engine); + return caller_ && callee_; +} + +bool PeerConnectionIntegrationTestBase:: + CreatePeerConnectionWrappersWithConfigAndDeps( + const PeerConnectionInterface::RTCConfiguration& caller_config, + PeerConnectionDependencies caller_dependencies, + const PeerConnectionInterface::RTCConfiguration& callee_config, + PeerConnectionDependencies callee_dependencies) { + caller_ = CreatePeerConnectionWrapper(kCallerName, nullptr, &caller_config, + std::move(caller_dependencies), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false); + callee_ = CreatePeerConnectionWrapper(kCalleeName, nullptr, &callee_config, + std::move(callee_dependencies), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false); + return caller_ && callee_; +} + +bool PeerConnectionIntegrationTestBase::CreatePeerConnectionWrappersWithOptions( + const PeerConnectionFactory::Options& caller_options, + const PeerConnectionFactory::Options& callee_options) { + caller_ = + CreatePeerConnectionWrapper(kCallerName, &caller_options, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false); + callee_ = + CreatePeerConnectionWrapper(kCalleeName, &callee_options, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false); + return caller_ && callee_; +} + +bool PeerConnectionIntegrationTestBase:: + CreatePeerConnectionWrappersWithFakeRtcEventLog() { + PeerConnectionInterface::RTCConfiguration default_config; + caller_ = CreatePeerConnectionWrapperWithFakeRtcEventLog( + kCallerName, nullptr, &default_config, + PeerConnectionDependencies(nullptr)); + callee_ = CreatePeerConnectionWrapperWithFakeRtcEventLog( + kCalleeName, nullptr, &default_config, + PeerConnectionDependencies(nullptr)); + return caller_ && callee_; +} + +std::unique_ptr<PeerConnectionIntegrationWrapper> +PeerConnectionIntegrationTestBase:: + CreatePeerConnectionWrapperWithAlternateKey() { + std::unique_ptr<FakeRTCCertificateGenerator> cert_generator( + new FakeRTCCertificateGenerator()); + cert_generator->use_alternate_key(); + + 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 PeerConnectionIntegrationTestBase:: + CreateOneDirectionalPeerConnectionWrappers(bool caller_to_callee) { + caller_ = + CreatePeerConnectionWrapper(kCallerName, nullptr, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/!caller_to_callee, + /*reset_decoder_factory=*/caller_to_callee); + callee_ = + CreatePeerConnectionWrapper(kCalleeName, nullptr, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/caller_to_callee, + /*reset_decoder_factory=*/!caller_to_callee); + return caller_ && callee_; +} + +bool PeerConnectionIntegrationTestBase:: + CreatePeerConnectionWrappersWithoutMediaEngine() { + caller_ = + CreatePeerConnectionWrapper(kCallerName, nullptr, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false, + /*create_media_engine=*/false); + callee_ = + CreatePeerConnectionWrapper(kCalleeName, nullptr, nullptr, + PeerConnectionDependencies(nullptr), nullptr, + /*reset_encoder_factory=*/false, + /*reset_decoder_factory=*/false, + /*create_media_engine=*/false); + return caller_ && callee_; +} + +TestTurnServer* PeerConnectionIntegrationTestBase::CreateTurnServer( + SocketAddress internal_address, + SocketAddress external_address, + ProtocolType type, + const std::string& common_name) { + Thread* thread = network_thread(); + SocketFactory* socket_factory = fss_.get(); + std::unique_ptr<TestTurnServer> turn_server; + SendTask(network_thread(), [&] { + turn_server = std::make_unique<TestTurnServer>( + CreateTestEnvironment(), thread, socket_factory, 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(); +} + +TestTurnCustomizer* PeerConnectionIntegrationTestBase::CreateTurnCustomizer() { + std::unique_ptr<TestTurnCustomizer> turn_customizer; + SendTask(network_thread(), + [&] { turn_customizer = std::make_unique<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(); +} + +void PeerConnectionIntegrationTestBase::ExpectTurnCustomizerCountersIncremented( + TestTurnCustomizer* turn_customizer) { + SendTask(network_thread(), [turn_customizer] { + EXPECT_GT(turn_customizer->allow_channel_data_cnt_, 0u); + EXPECT_GT(turn_customizer->modify_cnt_, 0u); + }); +} + +void PeerConnectionIntegrationTestBase::ConnectFakeSignaling() { + caller_->set_signaling_message_receiver(callee_.get()); + callee_->set_signaling_message_receiver(caller_.get()); +} + +void PeerConnectionIntegrationTestBase::ConnectFakeSignalingForSdpOnly() { + ConnectFakeSignaling(); + SetSignalIceCandidates(false); +} + +void PeerConnectionIntegrationTestBase::SetSignalingDelayMs(int delay_ms) { + caller_->set_signaling_delay_ms(delay_ms); + callee_->set_signaling_delay_ms(delay_ms); +} + +void PeerConnectionIntegrationTestBase::SetSignalIceCandidates(bool signal) { + caller_->set_signal_ice_candidates(signal); + callee_->set_signal_ice_candidates(signal); +} + +void PeerConnectionIntegrationTestBase::SendRtpDataWithRetries( + DataChannelInterface* dc, + const std::string& data, + int retries) { + for (int i = 0; i < retries; ++i) { + dc->Send(DataBuffer(data)); + } +} + void PeerConnectionIntegrationTestBase::DestroyTurnServers() { ExecuteTask(*network_thread(), [this] { turn_servers_.clear(); @@ -513,6 +1506,206 @@ std::make_unique<ScopedSetLoggingLevel>(new_severity); } +void PeerConnectionIntegrationTestBase::DestroyPeerConnections() { + if (caller_) { + caller_->set_signaling_message_receiver(nullptr); + caller_->pc()->Close(); + } + if (callee_) { + callee_->set_signaling_message_receiver(nullptr); + callee_->pc()->Close(); + } + caller_.reset(); + callee_.reset(); +} + +PeerConnectionIntegrationWrapper* +PeerConnectionIntegrationTestBase::SetCallerPcWrapperAndReturnCurrent( + std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper) { + PeerConnectionIntegrationWrapper* old = caller_.release(); + caller_ = std::move(wrapper); + return old; +} + +PeerConnectionIntegrationWrapper* +PeerConnectionIntegrationTestBase::SetCalleePcWrapperAndReturnCurrent( + std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper) { + PeerConnectionIntegrationWrapper* old = callee_.release(); + callee_ = std::move(wrapper); + return old; +} + +bool PeerConnectionIntegrationTestBase::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_THAT( + GetWaiter({.timeout = kMaxWaitForFrames}) + .Until( + [&] { + return 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; + }, + ::testing::IsTrue()), + IsRtcOk()); + 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 PeerConnectionIntegrationTestBase::ClosePeerConnections() { + if (caller()) + caller()->pc()->Close(); + if (callee()) + callee()->pc()->Close(); +} + +void PeerConnectionIntegrationTestBase::TestNegotiatedCipherSuite( + const RTCConfiguration& caller_config, + const RTCConfiguration& callee_config, + int expected_cipher_suite) { + ASSERT_TRUE( + CreatePeerConnectionWrappersWithConfig(caller_config, callee_config)); + ConnectFakeSignaling(); + caller()->AddAudioVideoTracks(); + callee()->AddAudioVideoTracks(); + caller()->CreateAndSetAndSignalOffer(); + WaitUntilSettings settings; + settings.polling_interval = TimeDelta::Millis(100); + if (auto* tc = time_controller()) { + settings.clock = tc; + } + ASSERT_THAT(GetWaiter(settings).Until([&] { return DtlsConnected(); }, + ::testing::IsTrue()), + IsRtcOk()); + EXPECT_THAT(GetWaiter(settings).Until( + [&] { + auto report = caller()->NewGetStats(settings); + if (!report) { + return false; + } + auto transport_stats = + report->GetStatsOfType<RTCTransportStats>(); + if (transport_stats.empty()) { + return false; + } + return *transport_stats[0]->srtp_cipher == + SrtpCryptoSuiteToName(expected_cipher_suite); + }, + ::testing::IsTrue()), + IsRtcOk()); +} + +void PeerConnectionIntegrationTestBase::TestGcmNegotiationUsesCipherSuite( + bool local_gcm_enabled, + bool remote_gcm_enabled, + bool aes_ctr_enabled, + int expected_cipher_suite) { + RTCConfiguration caller_config; + CryptoOptions caller_crypto; + caller_crypto.srtp.enable_gcm_crypto_suites = local_gcm_enabled; + caller_crypto.srtp.enable_aes128_sha1_80_crypto_cipher = aes_ctr_enabled; + caller_config.crypto_options = caller_crypto; + RTCConfiguration callee_config; + CryptoOptions callee_crypto; + callee_crypto.srtp.enable_gcm_crypto_suites = remote_gcm_enabled; + callee_crypto.srtp.enable_aes128_sha1_80_crypto_cipher = aes_ctr_enabled; + callee_config.crypto_options = callee_crypto; + TestNegotiatedCipherSuite(caller_config, callee_config, + expected_cipher_suite); +} + std::unique_ptr<PeerConnectionIntegrationWrapper> PeerConnectionIntegrationTestBase::CreatePeerConnectionWrapperInternal( const std::string& debug_name, @@ -528,8 +1721,34 @@ : internal::PeerConnectionIntegrationTestBase(CreateTestEnvironment(), sdp_semantics) {} -PeerConnectionIntegrationTestWithSimulatedTime:: +PeerConnectionIntegrationBaseTest::~PeerConnectionIntegrationBaseTest() { + DestroyPeerConnections(); + DestroyTurnServers(); +} +void PeerConnectionIntegrationBaseTest::ExecuteTask( + TaskQueueBase& task_queue, + absl::AnyInvocable<void()> task) { + task_queue.PostTask([this, task = std::move(task)]() mutable { + task(); + run_loop_.task_queue()->PostTask(run_loop_.QuitClosure()); + }); + run_loop_.Run(); +} + +Waiter PeerConnectionIntegrationBaseTest::GetWaiter( + WaitUntilSettings overrides) { + return Waiter(overrides); +} + +std::unique_ptr<Thread> PeerConnectionIntegrationBaseTest::CreateThread( + absl::string_view name) { + auto thread = Thread::Create(); + thread->Start(); + return thread; +} + +PeerConnectionIntegrationTestWithSimulatedTime:: PeerConnectionIntegrationTestWithSimulatedTime(SdpSemantics sdp_semantics) : PeerConnectionIntegrationTestWithSimulatedTime( sdp_semantics, @@ -549,6 +1768,25 @@ DestroyThreads(); } +void PeerConnectionIntegrationTestWithSimulatedTime::ExecuteTask( + TaskQueueBase& task_queue, + absl::AnyInvocable<void()> task) { + task_queue.PostTask(std::move(task)); + time_controller_->AdvanceTime(TimeDelta::Zero()); +} + +Waiter PeerConnectionIntegrationTestWithSimulatedTime::GetWaiter( + WaitUntilSettings overrides) { + overrides.clock = time_controller_.get(); + return Waiter(overrides); +} + +std::unique_ptr<Thread> +PeerConnectionIntegrationTestWithSimulatedTime::CreateThread( + absl::string_view name) { + return time_controller_->CreateThread(std::string(name), nullptr); +} + PeerConnectionIntegrationTestWithSimulatedTime:: PeerConnectionIntegrationTestWithSimulatedTime( SdpSemantics sdp_semantics,
diff --git a/pc/test/integration_test_helpers.h b/pc/test/integration_test_helpers.h index 28d393f..fe59699 100644 --- a/pc/test/integration_test_helpers.h +++ b/pc/test/integration_test_helpers.h
@@ -15,13 +15,11 @@ #include <stdint.h> #include <stdio.h> -#include <algorithm> #include <functional> #include <limits> #include <map> #include <memory> #include <optional> -#include <set> #include <string> #include <tuple> #include <utility> @@ -29,14 +27,10 @@ #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" -#include "api/audio_options.h" #include "api/candidate.h" -#include "api/crypto/crypto_options.h" #include "api/data_channel_interface.h" #include "api/dtls_transport_interface.h" #include "api/environment/environment.h" -#include "api/environment/environment_factory.h" -#include "api/field_trials.h" #include "api/ice_transport_interface.h" #include "api/jsep.h" #include "api/make_ref_counted.h" @@ -44,12 +38,9 @@ #include "api/media_types.h" #include "api/metronome/metronome.h" #include "api/peer_connection_interface.h" -#include "api/rtc_error.h" #include "api/rtc_event_log_output.h" -#include "api/rtp_parameters.h" #include "api/rtp_receiver_interface.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/sequence_checker.h" @@ -58,10 +49,8 @@ #include "api/task_queue/pending_task_safety_flag.h" #include "api/task_queue/task_queue_base.h" #include "api/test/mock_async_dns_resolver.h" -#include "api/test/rtc_error_matchers.h" #include "api/test/time_controller.h" #include "api/units/time_delta.h" -#include "api/units/timestamp.h" #include "api/video/video_rotation.h" #include "logging/rtc_event_log/fake_rtc_event_log_factory.h" #include "media/base/stream_params.h" @@ -74,35 +63,23 @@ #include "p2p/test/test_turn_server.h" #include "pc/peer_connection.h" #include "pc/peer_connection_factory.h" -#include "pc/peer_connection_proxy.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/test/rtc_stats_obtainer.h" #include "pc/video_track_source.h" -#include "rtc_base/checks.h" -#include "rtc_base/crypto_random.h" #include "rtc_base/fake_mdns_responder.h" #include "rtc_base/fake_network.h" #include "rtc_base/firewall_socket_server.h" -#include "rtc_base/ip_address.h" #include "rtc_base/logging.h" #include "rtc_base/net_helper.h" #include "rtc_base/socket_address.h" -#include "rtc_base/socket_factory.h" #include "rtc_base/socket_server.h" #include "rtc_base/ssl_stream_adapter.h" #include "rtc_base/system/plan_b_only.h" -#include "rtc_base/task_queue_for_test.h" #include "rtc_base/thread.h" #include "rtc_base/virtual_socket_server.h" -#include "system_wrappers/include/clock.h" -#include "test/create_test_environment.h" -#include "test/create_test_field_trials.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/run_loop.h" @@ -261,8 +238,7 @@ explicit PeerConnectionIntegrationWrapper( const std::string& debug_name, Environment env, - internal::PeerConnectionIntegrationTestBase* test) - : debug_name_(debug_name), env_(env), test_(test) {} + internal::PeerConnectionIntegrationTestBase* test); PeerConnectionFactoryInterface* pc_factory() const { return peer_connection_factory_.get(); @@ -272,21 +248,12 @@ // Return the PC implementation, so that non-public interfaces // can be used in tests. - PeerConnection* pc_internal() const { - auto* pci = - static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>( - pc()); - return static_cast<PeerConnection*>(pci->internal()); - } + PeerConnection* pc_internal() const; // 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() { - std::unique_ptr<SessionDescriptionInterface> offer = CreateOfferAndWait(); - ASSERT_NE(nullptr, offer); - EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(offer))); - } + void CreateAndSetAndSignalOffer(); // Sets the options to be used when CreateAndSetAndSignalOffer is called, or // when a remote offer is received (via fake signaling) and an answer is @@ -364,11 +331,7 @@ return peer_connection_signaling_state_history_; } - void AddAudioVideoTracks() { - AddAudioTrack(); - AddVideoTrack(); - ResetRtpSenderObservers(); - } + void AddAudioVideoTracks(); scoped_refptr<RtpSenderInterface> AddAudioTrack() { return AddTrack(CreateLocalAudioTrack()); @@ -378,129 +341,52 @@ return AddTrack(CreateLocalVideoTrack()); } - scoped_refptr<AudioTrackInterface> CreateLocalAudioTrack() { - AudioOptions options; - // Disable highpass filter so that we can get all the test audio frames. - options.highpass_filter = false; - scoped_refptr<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(CreateRandomUuid(), - source.get()); - } + scoped_refptr<AudioTrackInterface> CreateLocalAudioTrack(); - scoped_refptr<VideoTrackInterface> CreateLocalVideoTrack() { - FakePeriodicVideoSource::Config config; - config.timestamp_offset = env_.clock().CurrentTime(); - return CreateLocalVideoTrackInternal(config); - } + scoped_refptr<VideoTrackInterface> CreateLocalVideoTrack(); scoped_refptr<VideoTrackInterface> CreateLocalVideoTrackWithConfig( - FakePeriodicVideoSource::Config config) { - return CreateLocalVideoTrackInternal(config); - } + FakePeriodicVideoSource::Config config); scoped_refptr<VideoTrackInterface> CreateLocalVideoTrackWithRotation( - VideoRotation rotation) { - FakePeriodicVideoSource::Config config; - config.rotation = rotation; - config.timestamp_offset = env_.clock().CurrentTime(); - return CreateLocalVideoTrackInternal(config); - } + VideoRotation rotation); scoped_refptr<RtpSenderInterface> AddTrack( scoped_refptr<MediaStreamTrackInterface> track, - const std::vector<std::string>& stream_ids = {}) { - EXPECT_TRUE(track); - if (!track) { - return nullptr; - } - auto result = pc()->AddTrack(track, stream_ids); - EXPECT_EQ(RTCErrorType::NONE, result.error().type()); - if (result.ok()) { - return result.MoveValue(); - } else { - return nullptr; - } - } + const std::vector<std::string>& stream_ids = {}); std::vector<scoped_refptr<RtpReceiverInterface>> GetReceiversOfType( - webrtc::MediaType media_type) { - std::vector<scoped_refptr<RtpReceiverInterface>> receivers; - for (const auto& receiver : pc()->GetReceivers()) { - if (receiver->media_type() == media_type) { - receivers.push_back(receiver); - } - } - return receivers; - } + webrtc::MediaType media_type); scoped_refptr<RtpTransceiverInterface> GetFirstTransceiverOfType( - webrtc::MediaType media_type) { - for (auto transceiver : pc()->GetTransceivers()) { - if (transceiver->receiver()->media_type() == media_type) { - return transceiver; - } - } - return nullptr; - } + webrtc::MediaType media_type); - bool SignalingStateStable() { - return pc()->signaling_state() == PeerConnectionInterface::kStable; - } + bool SignalingStateStable(); - bool IceGatheringStateComplete() { - return pc()->ice_gathering_state() == - PeerConnectionInterface::kIceGatheringComplete; - } + bool IceGatheringStateComplete(); - void CreateDataChannel() { CreateDataChannel(nullptr); } + void CreateDataChannel(); - void CreateDataChannel(const DataChannelInit* init) { - CreateDataChannel(kDataChannelLabel, init); - } + void CreateDataChannel(const DataChannelInit* init); - void CreateDataChannel(const std::string& label, - const DataChannelInit* init) { - auto data_channel_or_error = pc()->CreateDataChannelOrError(label, init); - ASSERT_TRUE(data_channel_or_error.ok()); - data_channels_.push_back(data_channel_or_error.MoveValue()); - ASSERT_TRUE(data_channels_.back().get() != nullptr); - data_observers_.push_back( - std::make_unique<MockDataChannelObserver>(data_channels_.back().get())); - } + void CreateDataChannel(const std::string& label, const DataChannelInit* init); // Return the last observed data channel. - DataChannelInterface* data_channel() { - if (data_channels_.empty()) { - return nullptr; - } - return data_channels_.back().get(); - } + DataChannelInterface* data_channel(); // Return all data channels. std::vector<scoped_refptr<DataChannelInterface>>& data_channels() { return data_channels_; } - MockDataChannelObserver* data_observer() const { - if (data_observers_.empty()) { - return nullptr; - } - return data_observers_.back().get(); - } + MockDataChannelObserver* data_observer() const; std::vector<std::unique_ptr<MockDataChannelObserver>>& data_observers() { return data_observers_; } - std::unique_ptr<SessionDescriptionInterface> CreateAnswerForTest() { - return CreateAnswer(); - } + std::unique_ptr<SessionDescriptionInterface> CreateAnswerForTest(); - int audio_frames_received() const { - return fake_audio_capture_module_->frames_received(); - } + int audio_frames_received() const; // Takes minimum of video frames received for each track. // @@ -509,17 +395,7 @@ // // 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; - } + int min_video_frames_received_per_track() const; // Returns a MockStatsObserver in a state after stats gathering finished, // which can be used to access the gathered stats. @@ -527,9 +403,7 @@ MediaStreamTrackInterface* track); // Version that doesn't take a track "filter", and gathers all stats. - scoped_refptr<MockStatsObserver> OldGetStats() { - return OldGetStatsForTrack(nullptr); - } + scoped_refptr<MockStatsObserver> OldGetStats(); // Synchronously gets stats and returns them. If it times out, fails the test // and returns null. @@ -539,118 +413,40 @@ scoped_refptr<const RTCStatsReport> NewGetStats( WaitUntilSettings settings = {}); - scoped_refptr<const RTCStatsReport> NewGetStats(test::RunLoop& run_loop) { - scoped_refptr<const RTCStatsReport> report; - auto callback = RTCStatsObtainer::Create(&report, run_loop.QuitClosure()); - peer_connection_->GetStats(callback.get()); - run_loop.Run(); - EXPECT_TRUE(report); - return report; - } + scoped_refptr<const RTCStatsReport> NewGetStats(test::RunLoop& run_loop); - std::string DtlsCipher() { - auto report = NewGetStats(); - if (!report) - return ""; - auto stats = report->GetStatsOfType<RTCTransportStats>(); - if (stats.empty() || !stats[0]->dtls_cipher.has_value()) - return ""; - return *stats[0]->dtls_cipher; - } + std::string DtlsCipher(); - std::string SrtpCipher() { - auto report = NewGetStats(); - if (!report) - return ""; - auto stats = report->GetStatsOfType<RTCTransportStats>(); - if (stats.empty() || !stats[0]->srtp_cipher.has_value()) - return ""; - return *stats[0]->srtp_cipher; - } + std::string SrtpCipher(); - int rendered_width() { - EXPECT_FALSE(fake_video_renderers_.empty()); - return fake_video_renderers_.empty() - ? 0 - : fake_video_renderers_.begin()->second->width(); - } + int rendered_width(); - int rendered_height() { - EXPECT_FALSE(fake_video_renderers_.empty()); - return fake_video_renderers_.empty() - ? 0 - : fake_video_renderers_.begin()->second->height(); - } + int rendered_height(); - double rendered_aspect_ratio() { - if (rendered_height() == 0) { - return 0.0; - } - return static_cast<double>(rendered_width()) / rendered_height(); - } + double rendered_aspect_ratio(); - VideoRotation rendered_rotation() { - EXPECT_FALSE(fake_video_renderers_.empty()); - return fake_video_renderers_.empty() - ? kVideoRotation_0 - : fake_video_renderers_.begin()->second->rotation(); - } + VideoRotation rendered_rotation(); - int local_rendered_width() { - return local_video_renderer_ ? local_video_renderer_->width() : 0; - } + int local_rendered_width(); - int local_rendered_height() { - return local_video_renderer_ ? local_video_renderer_->height() : 0; - } + int local_rendered_height(); - double local_rendered_aspect_ratio() { - if (local_rendered_height() == 0) { - return 0.0; - } - return static_cast<double>(local_rendered_width()) / - local_rendered_height(); - } + double local_rendered_aspect_ratio(); - PLAN_B_ONLY size_t number_of_remote_streams() { - if (!pc()) { - return 0; - } - return pc()->remote_streams()->count(); - } + PLAN_B_ONLY size_t number_of_remote_streams(); - PLAN_B_ONLY StreamCollectionInterface* remote_streams() const { - if (!pc()) { - ADD_FAILURE(); - return nullptr; - } - return pc()->remote_streams().get(); - } + PLAN_B_ONLY StreamCollectionInterface* remote_streams() const; - PLAN_B_ONLY StreamCollectionInterface* local_streams() { - if (!pc()) { - ADD_FAILURE(); - return nullptr; - } - return pc()->local_streams().get(); - } + PLAN_B_ONLY StreamCollectionInterface* local_streams(); - PeerConnectionInterface::SignalingState signaling_state() { - return pc()->signaling_state(); - } + PeerConnectionInterface::SignalingState signaling_state(); - PeerConnectionInterface::IceConnectionState ice_connection_state() { - return pc()->ice_connection_state(); - } + PeerConnectionInterface::IceConnectionState ice_connection_state(); PeerConnectionInterface::IceConnectionState - standardized_ice_connection_state() { - return pc()->standardized_ice_connection_state(); - } + standardized_ice_connection_state(); - PeerConnectionInterface::IceGatheringState ice_gathering_state() { - return pc()->ice_gathering_state(); - } + PeerConnectionInterface::IceGatheringState ice_gathering_state(); // Returns a MockRtpReceiverObserver for each RtpReceiver returned by // GetReceivers. They're updated automatically when a remote offer/answer @@ -661,31 +457,14 @@ return rtp_receiver_observers_; } - void ResetRtpReceiverObservers() { - rtp_receiver_observers_.clear(); - for (const 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)); - } - } + void ResetRtpReceiverObservers(); const std::vector<std::unique_ptr<MockRtpSenderObserver>>& rtp_sender_observers() { return rtp_sender_observers_; } - void ResetRtpSenderObservers() { - rtp_sender_observers_.clear(); - for (const scoped_refptr<RtpSenderInterface>& sender : pc()->GetSenders()) { - std::unique_ptr<MockRtpSenderObserver> observer( - new MockRtpSenderObserver(sender->media_type())); - sender->SetObserver(observer.get()); - rtp_sender_observers_.push_back(std::move(observer)); - } - } + void ResetRtpSenderObservers(); FakeNetworkManager* network_manager() const { return fake_network_manager_; } @@ -693,12 +472,7 @@ return event_log_factory_; } - Candidate last_candidate_gathered() const { - if (last_gathered_ice_candidate_) { - return last_gathered_ice_candidate_->candidate(); - } - return Candidate(); - } + Candidate last_candidate_gathered() const; const IceCandidate* last_gathered_ice_candidate() const { return last_gathered_ice_candidate_.get(); } @@ -706,17 +480,11 @@ // Sets the mDNS responder for the owned fake network manager and keeps a // reference to the responder. - void SetMdnsResponder(std::unique_ptr<FakeMdnsResponder> mdns_responder) { - RTC_DCHECK(mdns_responder != nullptr); - mdns_responder_ = mdns_responder.get(); - network_manager()->set_mdns_responder(std::move(mdns_responder)); - } + void SetMdnsResponder(std::unique_ptr<FakeMdnsResponder> mdns_responder); // Returns null on failure. std::unique_ptr<SessionDescriptionInterface> CreateOfferAndWait(); - bool Rollback() { - return SetRemoteDescription(CreateRollbackSessionDescription()); - } + bool Rollback(); // Functions for querying stats. void StartWatchingDelayStats(); @@ -734,63 +502,22 @@ bool SetRemoteDescription(std::unique_ptr<SessionDescriptionInterface> desc); - void NegotiateCorruptionDetectionHeader() { - for (const auto& transceiver : pc()->GetTransceivers()) { - if (transceiver->media_type() != webrtc::MediaType::VIDEO) { - continue; - } - auto extensions = transceiver->GetHeaderExtensionsToNegotiate(); - for (auto& extension : extensions) { - if (extension.uri == RtpExtension::kCorruptionDetectionUri) { - extension.direction = RtpTransceiverDirection::kSendRecv; - } - } - transceiver->SetHeaderExtensionsToNegotiate(extensions); - } - } + void NegotiateCorruptionDetectionHeader(); - uint32_t GetCorruptionScoreCount() { - scoped_refptr<const RTCStatsReport> report = NewGetStats(); - auto inbound_stream_stats = - report->GetStatsOfType<RTCInboundRtpStreamStats>(); - for (const auto& stat : inbound_stream_stats) { - if (*stat->kind == "video") { - return stat->corruption_measurements.value_or(0); - } - } - return 0; - } + uint32_t GetCorruptionScoreCount(); - uint32_t GetReceivedFrameCount() { - scoped_refptr<const RTCStatsReport> report = NewGetStats(); - auto inbound_stream_stats = - report->GetStatsOfType<RTCInboundRtpStreamStats>(); - for (const auto& stat : inbound_stream_stats) { - if (*stat->kind == "video") { - return stat->frames_received.value_or(0); - } - } - return 0; - } + uint32_t GetReceivedFrameCount(); void set_connection_change_callback( std::function<void(PeerConnectionInterface::PeerConnectionState)> func) { connection_change_callback_ = std::move(func); } - std::optional<int> tls_version() { - return dtls_transport_information().tls_version(); - } + std::optional<int> tls_version(); - std::optional<DtlsTransportTlsRole> dtls_transport_role() { - return dtls_transport_information().role(); - } + std::optional<DtlsTransportTlsRole> dtls_transport_role(); - DtlsTransportInformation dtls_transport_information() { - return network_thread_->BlockingCall([&] { - return pc()->GetSctpTransport()->dtls_transport()->Information(); - }); - } + DtlsTransportInformation dtls_transport_information(); // Setting the local description and sending the SDP message over the fake // signaling channel are combined into the same method because the SDP @@ -814,27 +541,7 @@ scoped_refptr<PeerConnectionInterface> CreatePeerConnection( const PeerConnectionInterface::RTCConfiguration* config, - PeerConnectionDependencies dependencies) { - PeerConnectionInterface::RTCConfiguration modified_config; - modified_config.sdp_semantics = sdp_semantics_; - // 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; - auto peer_connection_or_error = - peer_connection_factory_->CreatePeerConnectionOrError( - modified_config, std::move(dependencies)); - return peer_connection_or_error.ok() ? peer_connection_or_error.MoveValue() - : nullptr; - } + PeerConnectionDependencies dependencies); void set_signaling_delay_ms(int delay_ms) { signaling_delay_ms_ = delay_ms; } @@ -843,138 +550,34 @@ } scoped_refptr<VideoTrackInterface> CreateLocalVideoTrackInternal( - 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 = TimeDelta::Millis(100); + FakePeriodicVideoSource::Config config); - video_track_sources_.emplace_back( - make_ref_counted<FakePeriodicVideoTrackSource>(config, - false /* remote */)); - scoped_refptr<VideoTrackInterface> track = - peer_connection_factory_->CreateVideoTrack(video_track_sources_.back(), - CreateRandomUuid()); - if (!local_video_renderer_) { - local_video_renderer_.reset(new FakeVideoTrackRenderer(track.get())); - } - return track; - } + void HandleIncomingOffer(const std::string& msg); - void HandleIncomingOffer(const std::string& msg) { - RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingOffer"; - std::unique_ptr<SessionDescriptionInterface> desc = - CreateSessionDescription(SdpType::kOffer, msg); - if (received_sdp_munger_) { - received_sdp_munger_(desc); - } - - 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_(); - } - std::unique_ptr<SessionDescriptionInterface> answer = CreateAnswer(); - ASSERT_NE(nullptr, answer); - EXPECT_TRUE(SetLocalDescriptionAndSendSdpMessage(std::move(answer))); - } - - void HandleIncomingAnswer(SdpType type, const std::string& msg) { - RTC_LOG(LS_INFO) << debug_name_ << ": HandleIncomingAnswer of type " - << type; - std::unique_ptr<SessionDescriptionInterface> desc = - CreateSessionDescription(type, msg); - if (received_sdp_munger_) { - received_sdp_munger_(desc); - if (!desc) { - // Answer was "taken" by munger...so that it can be applied later ? - RTC_LOG(LS_INFO) << debug_name_ << ": answer NOT applied"; - return; - } - } - EXPECT_TRUE(SetRemoteDescription(std::move(desc))); - // Set the RtpReceiverObserver after receivers are created. - ResetRtpReceiverObservers(); - } + void HandleIncomingAnswer(SdpType type, const std::string& msg); // Returns null on failure. std::unique_ptr<SessionDescriptionInterface> CreateAnswer(); // 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() == webrtc::MediaType::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++; - } - } - } + void RemoveUnusedVideoRenderers(); // 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 { - Thread::Current()->PostDelayedTask( - SafeTask(task_safety_.flag(), - [this, type, msg] { - RelaySdpMessageIfReceiverExists(type, msg); - }), - TimeDelta::Millis(signaling_delay_ms_)); - } - } + void SendSdpMessage(SdpType type, const std::string& msg); - void RelaySdpMessageIfReceiverExists(SdpType type, const std::string& msg) { - if (signaling_message_receiver_) { - signaling_message_receiver_->ReceiveSdpMessage(type, msg); - } - } + void RelaySdpMessageIfReceiverExists(SdpType type, const std::string& 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 { - Thread::Current()->PostDelayedTask( - SafeTask(task_safety_.flag(), - [this, sdp_mid, sdp_mline_index, msg] { - RelayIceMessageIfReceiverExists(sdp_mid, sdp_mline_index, - msg); - }), - TimeDelta::Millis(signaling_delay_ms_)); - } - } + const std::string& msg); 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); - } - } + const std::string& msg); // SignalingMessageReceiver callbacks. public: @@ -983,13 +586,7 @@ signaling_message_receiver_ = signaling_message_receiver; } - void ReceiveSdpMessage(SdpType type, const std::string& msg) override { - if (type == SdpType::kOffer) { - HandleIncomingOffer(msg); - } else { - HandleIncomingAnswer(type, msg); - } - } + void ReceiveSdpMessage(SdpType type, const std::string& msg) override; void ReceiveIceMessage(const std::string& sdp_mid, int sdp_mline_index, @@ -998,125 +595,40 @@ private: // PeerConnectionObserver callbacks. void OnSignalingChange( - PeerConnectionInterface::SignalingState new_state) override { - EXPECT_EQ(pc()->signaling_state(), new_state); - peer_connection_signaling_state_history_.push_back(new_state); - } - void OnAddTrack(scoped_refptr<RtpReceiverInterface> receiver, - const std::vector<scoped_refptr<MediaStreamInterface>>& - streams) override { - if (receiver->media_type() == webrtc::MediaType::VIDEO) { - 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.get()); - } - } - void OnRemoveTrack(scoped_refptr<RtpReceiverInterface> receiver) override { - if (receiver->media_type() == webrtc::MediaType::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 {} + PeerConnectionInterface::SignalingState new_state) override; + void OnAddTrack( + scoped_refptr<RtpReceiverInterface> receiver, + const std::vector<scoped_refptr<MediaStreamInterface>>& streams) override; + void OnRemoveTrack(scoped_refptr<RtpReceiverInterface> receiver) override; + void OnRenegotiationNeeded() override; void OnIceConnectionChange( - PeerConnectionInterface::IceConnectionState new_state) override { - EXPECT_EQ(pc()->ice_connection_state(), new_state); - ice_connection_state_history_.push_back(new_state); - } + PeerConnectionInterface::IceConnectionState new_state) override; void OnStandardizedIceConnectionChange( - PeerConnectionInterface::IceConnectionState new_state) override { - standardized_ice_connection_state_history_.push_back(new_state); - } + PeerConnectionInterface::IceConnectionState new_state) override; void OnConnectionChange( - PeerConnectionInterface::PeerConnectionState new_state) override { - peer_connection_state_history_.push_back(new_state); - if (connection_change_callback_) { - connection_change_callback_(new_state); - } - } + PeerConnectionInterface::PeerConnectionState new_state) override; void OnIceGatheringChange( - PeerConnectionInterface::IceGatheringState new_state) override { - EXPECT_EQ(pc()->ice_gathering_state(), new_state); - ice_gathering_state_history_.push_back(new_state); - } + PeerConnectionInterface::IceGatheringState new_state) override; void OnIceSelectedCandidatePairChanged( const CandidatePairChangeEvent& event) override { ice_candidate_pair_change_history_.push_back(event); } - void OnIceCandidate(const IceCandidate* candidate) override { - RTC_LOG(LS_INFO) << debug_name_ << ": OnIceCandidate"; - - if (remote_async_dns_resolver_) { - const auto& local_candidate = candidate->candidate(); - if (local_candidate.address().IsUnresolvedIP()) { - RTC_DCHECK(local_candidate.is_local()); - const auto resolved_ip = mdns_responder_->GetMappedAddressForName( - local_candidate.address().hostname()); - RTC_DCHECK(!resolved_ip.IsNil()); - remote_async_dns_resolved_addr_ = local_candidate.address(); - remote_async_dns_resolved_addr_.SetResolvedIP(resolved_ip); - EXPECT_CALL(*remote_async_dns_resolver_, Start(_, _)) - .WillOnce([](const SocketAddress& addr, - absl::AnyInvocable<void()> callback) { callback(); }); - EXPECT_CALL(*remote_async_dns_resolver_, result()) - .WillOnce(ReturnRef(remote_async_dns_resolver_result_)); - EXPECT_CALL(remote_async_dns_resolver_result_, GetResolvedAddress(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(remote_async_dns_resolved_addr_), - Return(true))); - } - } - - // Check if we expected to have a candidate. - EXPECT_GT(candidates_expected_, 1); - candidates_expected_--; - std::string ice_sdp = candidate->ToString(); - 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_gathered_ice_candidate_ = - CreateIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(), - candidate->candidate()); - } + void OnIceCandidate(const IceCandidate* candidate) override; void OnIceCandidateError(const std::string& address, int port, const std::string& url, int error_code, - const std::string& error_text) override { - error_event_ = - IceCandidateErrorEvent(address, port, url, error_code, error_text); - } + const std::string& error_text) override; void OnIceCandidateRemoved(const IceCandidate* candidate) override {} - void OnDataChannel( - scoped_refptr<DataChannelInterface> data_channel) override { - RTC_LOG(LS_INFO) << debug_name_ << ": OnDataChannel"; - data_channels_.push_back(data_channel); - data_observers_.push_back( - std::make_unique<MockDataChannelObserver>(data_channel.get())); - } - bool IdExists(const RtpHeaderExtensions& extensions, int id) { - for (const auto& extension : extensions) { - if (extension.id == id) { - return true; - } - } - return false; - } + void OnDataChannel(scoped_refptr<DataChannelInterface> data_channel) override; + bool IdExists(const RtpHeaderExtensions& extensions, int id); private: std::string debug_name_; @@ -1377,36 +889,16 @@ callee_->pc()->peer_connection_state() == state; } - 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() == - PeerConnectionInterface::kIceConnectionConnected || - callee()->ice_connection_state() == - PeerConnectionInterface::kIceConnectionCompleted) && - (caller()->ice_connection_state() == - PeerConnectionInterface::kIceConnectionConnected || - caller()->ice_connection_state() == - PeerConnectionInterface::kIceConnectionCompleted); - } + bool DtlsConnected(); // Sets field trials to pass to created PeerConnectionWrapper. // Must be called before PeerConnectionWrappers are created. - void SetFieldTrials(absl::string_view field_trials) { - RTC_CHECK(caller_ == nullptr); - RTC_CHECK(callee_ == nullptr); - field_trials_ = std::string(field_trials); - } + void SetFieldTrials(absl::string_view field_trials); // Sets field trials to pass to created PeerConnectionWrapper key:ed on // debug_name. Must be called before PeerConnectionWrappers are created. void SetFieldTrials(absl::string_view debug_name, - absl::string_view field_trials) { - RTC_CHECK(caller_ == nullptr); - RTC_CHECK(callee_ == nullptr); - field_trials_overrides_[std::string(debug_name)] = field_trials; - } + absl::string_view field_trials); // When `event_log_factory` is null, the default implementation of the event // log factory will be used. @@ -1418,50 +910,14 @@ std::unique_ptr<FakeRtcEventLogFactory> event_log_factory, bool reset_encoder_factory, bool reset_decoder_factory, - bool create_media_engine = true) { - 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::string field_trials = field_trials_; - EnvironmentFactory env = EnvironmentFactory(env_); - - auto it = field_trials_overrides_.find(debug_name); - if (it != field_trials_overrides_.end()) { - field_trials = it->second; - dependencies.trials = std::make_unique<FieldTrials>(it->second); - } - env.Set(CreateTestFieldTrialsPtr(field_trials)); - - std::unique_ptr<PeerConnectionIntegrationWrapper> client = - CreatePeerConnectionWrapperInternal(debug_name, env.Create()); - - if (!client->Init(options, &modified_config, std::move(dependencies), - fss_.get(), network_thread_.get(), worker_thread_.get(), - std::move(event_log_factory), reset_encoder_factory, - reset_decoder_factory, create_media_engine)) { - return nullptr; - } - return client; - } + bool create_media_engine = true); std::unique_ptr<PeerConnectionIntegrationWrapper> CreatePeerConnectionWrapperWithFakeRtcEventLog( const std::string& debug_name, const PeerConnectionFactory::Options* options, const RTCConfiguration* config, - PeerConnectionDependencies dependencies) { - return CreatePeerConnectionWrapper( - debug_name, options, config, std::move(dependencies), - std::make_unique<FakeRtcEventLogFactory>(), - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false); - } + PeerConnectionDependencies dependencies); bool CreatePeerConnectionWrappers() { return CreatePeerConnectionWrappersWithConfig( @@ -1471,208 +927,63 @@ 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(kCallerName, nullptr, nullptr, - PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false); - sdp_semantics_ = callee_semantics; - callee_ = CreatePeerConnectionWrapper(kCalleeName, nullptr, nullptr, - PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false); - sdp_semantics_ = original_semantics; - return caller_ && callee_; - } + SdpSemantics callee_semantics); bool CreatePeerConnectionWrappersWithConfig( const PeerConnectionInterface::RTCConfiguration& caller_config, const PeerConnectionInterface::RTCConfiguration& callee_config, - bool create_media_engine = true) { - caller_ = CreatePeerConnectionWrapper( - kCallerName, nullptr, &caller_config, - PeerConnectionDependencies(nullptr), nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false, create_media_engine); - callee_ = CreatePeerConnectionWrapper( - kCalleeName, nullptr, &callee_config, - PeerConnectionDependencies(nullptr), nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false, create_media_engine); - return caller_ && callee_; - } + bool create_media_engine = true); bool CreatePeerConnectionWrappersWithConfigAndDeps( const PeerConnectionInterface::RTCConfiguration& caller_config, PeerConnectionDependencies caller_dependencies, const PeerConnectionInterface::RTCConfiguration& callee_config, - PeerConnectionDependencies callee_dependencies) { - caller_ = - CreatePeerConnectionWrapper(kCallerName, nullptr, &caller_config, - std::move(caller_dependencies), nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false); - callee_ = - CreatePeerConnectionWrapper(kCalleeName, nullptr, &callee_config, - std::move(callee_dependencies), nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false); - return caller_ && callee_; - } + PeerConnectionDependencies callee_dependencies); bool CreatePeerConnectionWrappersWithOptions( const PeerConnectionFactory::Options& caller_options, - const PeerConnectionFactory::Options& callee_options) { - caller_ = CreatePeerConnectionWrapper(kCallerName, &caller_options, nullptr, - PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false); - callee_ = CreatePeerConnectionWrapper(kCalleeName, &callee_options, nullptr, - PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false); - return caller_ && callee_; - } + const PeerConnectionFactory::Options& callee_options); - bool CreatePeerConnectionWrappersWithFakeRtcEventLog() { - PeerConnectionInterface::RTCConfiguration default_config; - caller_ = CreatePeerConnectionWrapperWithFakeRtcEventLog( - kCallerName, nullptr, &default_config, - PeerConnectionDependencies(nullptr)); - callee_ = CreatePeerConnectionWrapperWithFakeRtcEventLog( - kCalleeName, nullptr, &default_config, - PeerConnectionDependencies(nullptr)); - return caller_ && callee_; - } + bool CreatePeerConnectionWrappersWithFakeRtcEventLog(); std::unique_ptr<PeerConnectionIntegrationWrapper> - CreatePeerConnectionWrapperWithAlternateKey() { - std::unique_ptr<FakeRTCCertificateGenerator> cert_generator( - new FakeRTCCertificateGenerator()); - cert_generator->use_alternate_key(); + CreatePeerConnectionWrapperWithAlternateKey(); - 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); - bool CreateOneDirectionalPeerConnectionWrappers(bool caller_to_callee) { - caller_ = CreatePeerConnectionWrapper( - kCallerName, nullptr, nullptr, PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/!caller_to_callee, - /*reset_decoder_factory=*/caller_to_callee); - callee_ = CreatePeerConnectionWrapper( - kCalleeName, nullptr, nullptr, PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/caller_to_callee, - /*reset_decoder_factory=*/!caller_to_callee); - return caller_ && callee_; - } - - bool CreatePeerConnectionWrappersWithoutMediaEngine() { - caller_ = CreatePeerConnectionWrapper(kCallerName, nullptr, nullptr, - PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false, - /*create_media_engine=*/false); - callee_ = CreatePeerConnectionWrapper(kCalleeName, nullptr, nullptr, - PeerConnectionDependencies(nullptr), - nullptr, - /*reset_encoder_factory=*/false, - /*reset_decoder_factory=*/false, - /*create_media_engine=*/false); - return caller_ && callee_; - } + bool CreatePeerConnectionWrappersWithoutMediaEngine(); TestTurnServer* CreateTurnServer( SocketAddress internal_address, SocketAddress external_address, ProtocolType type = ProtocolType::PROTO_UDP, - const std::string& common_name = "test turn server") { - Thread* thread = network_thread(); - SocketFactory* socket_factory = fss_.get(); - std::unique_ptr<TestTurnServer> turn_server; - SendTask(network_thread(), [&] { - turn_server = std::make_unique<TestTurnServer>( - CreateTestEnvironment(), thread, socket_factory, 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(); - } + const std::string& common_name = "test turn server"); - TestTurnCustomizer* CreateTurnCustomizer() { - std::unique_ptr<TestTurnCustomizer> turn_customizer; - SendTask(network_thread(), - [&] { turn_customizer = std::make_unique<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(); - } + TestTurnCustomizer* CreateTurnCustomizer(); // Checks that the function counters for a TestTurnCustomizer are greater than // 0. void ExpectTurnCustomizerCountersIncremented( - TestTurnCustomizer* turn_customizer) { - SendTask(network_thread(), [turn_customizer] { - EXPECT_GT(turn_customizer->allow_channel_data_cnt_, 0u); - EXPECT_GT(turn_customizer->modify_cnt_, 0u); - }); - } + TestTurnCustomizer* turn_customizer); // 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()); - } + void ConnectFakeSignaling(); // 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 ConnectFakeSignalingForSdpOnly(); - void SetSignalingDelayMs(int delay_ms) { - caller_->set_signaling_delay_ms(delay_ms); - callee_->set_signaling_delay_ms(delay_ms); - } + void SetSignalingDelayMs(int delay_ms); - void SetSignalIceCandidates(bool signal) { - caller_->set_signal_ice_candidates(signal); - callee_->set_signal_ice_candidates(signal); - } + void SetSignalIceCandidates(bool signal); // Messages may get lost on the unreliable DataChannel, so we send multiple // times to avoid test flakiness. void SendRtpDataWithRetries(DataChannelInterface* dc, const std::string& data, - int retries) { - for (int i = 0; i < retries; ++i) { - dc->Send(DataBuffer(data)); - } - } + int retries); Thread* network_thread() { return network_thread_.get(); } @@ -1683,18 +994,7 @@ // Destroy peer connections. // This can be used to ensure that all pointers to on-stack mocks // get dropped before exit. - void DestroyPeerConnections() { - if (caller_) { - caller_->set_signaling_message_receiver(nullptr); - caller_->pc()->Close(); - } - if (callee_) { - callee_->set_signaling_message_receiver(nullptr); - callee_->pc()->Close(); - } - caller_.reset(); - callee_.reset(); - } + void DestroyPeerConnections(); void DestroyTurnServers(); void DestroyThreads(); @@ -1702,22 +1002,14 @@ // Set the `caller_` to the `wrapper` passed in and return the // original `caller_`. PeerConnectionIntegrationWrapper* SetCallerPcWrapperAndReturnCurrent( - std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper) { - PeerConnectionIntegrationWrapper* old = caller_.release(); - caller_ = std::move(wrapper); - return old; - } + std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper); PeerConnectionIntegrationWrapper* callee() { return callee_.get(); } // Set the `callee_` to the `wrapper` passed in and return the // original `callee_`. PeerConnectionIntegrationWrapper* SetCalleePcWrapperAndReturnCurrent( - std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper) { - PeerConnectionIntegrationWrapper* old = callee_.release(); - callee_ = std::move(wrapper); - return old; - } + std::unique_ptr<PeerConnectionIntegrationWrapper> wrapper); FirewallSocketServer* firewall() const { return fss_.get(); } @@ -1725,175 +1017,18 @@ // 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_; - } + bool ExpectNewFrames(const MediaExpectations& media_expectations); - // Wait for the expected frames. - EXPECT_THAT( - GetWaiter({.timeout = kMaxWaitForFrames}) - .Until( - [&] { - return 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; - }, - ::testing::IsTrue()), - IsRtcOk()); - 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() { - if (caller()) - caller()->pc()->Close(); - if (callee()) - callee()->pc()->Close(); - } + void ClosePeerConnections(); void TestNegotiatedCipherSuite(const RTCConfiguration& caller_config, const RTCConfiguration& callee_config, - int expected_cipher_suite) { - ASSERT_TRUE( - CreatePeerConnectionWrappersWithConfig(caller_config, callee_config)); - ConnectFakeSignaling(); - caller()->AddAudioVideoTracks(); - callee()->AddAudioVideoTracks(); - caller()->CreateAndSetAndSignalOffer(); - WaitUntilSettings settings; - settings.polling_interval = TimeDelta::Millis(100); - if (auto* tc = time_controller()) { - settings.clock = tc; - } - ASSERT_THAT(GetWaiter(settings).Until([&] { return DtlsConnected(); }, - ::testing::IsTrue()), - IsRtcOk()); - EXPECT_THAT(GetWaiter(settings).Until( - [&] { - auto report = caller()->NewGetStats(settings); - if (!report) { - return false; - } - auto transport_stats = - report->GetStatsOfType<RTCTransportStats>(); - if (transport_stats.empty()) { - return false; - } - return *transport_stats[0]->srtp_cipher == - SrtpCryptoSuiteToName(expected_cipher_suite); - }, - ::testing::IsTrue()), - IsRtcOk()); - } + int expected_cipher_suite); void TestGcmNegotiationUsesCipherSuite(bool local_gcm_enabled, bool remote_gcm_enabled, bool aes_ctr_enabled, - int expected_cipher_suite) { - RTCConfiguration caller_config; - CryptoOptions caller_crypto; - caller_crypto.srtp.enable_gcm_crypto_suites = local_gcm_enabled; - caller_crypto.srtp.enable_aes128_sha1_80_crypto_cipher = aes_ctr_enabled; - caller_config.crypto_options = caller_crypto; - RTCConfiguration callee_config; - CryptoOptions callee_crypto; - callee_crypto.srtp.enable_gcm_crypto_suites = remote_gcm_enabled; - callee_crypto.srtp.enable_aes128_sha1_80_crypto_cipher = aes_ctr_enabled; - callee_config.crypto_options = callee_crypto; - TestNegotiatedCipherSuite(caller_config, callee_config, - expected_cipher_suite); - } + int expected_cipher_suite); protected: void OverrideLoggingLevelForTest(LoggingSeverity new_severity); @@ -1936,31 +1071,16 @@ : public internal::PeerConnectionIntegrationTestBase { public: explicit PeerConnectionIntegrationBaseTest(SdpSemantics sdp_semantics); - ~PeerConnectionIntegrationBaseTest() override { - DestroyPeerConnections(); - DestroyTurnServers(); - } + ~PeerConnectionIntegrationBaseTest() override; test::RunLoop& run_loop() { return run_loop_; } void ExecuteTask(TaskQueueBase& task_queue, - absl::AnyInvocable<void()> task) override { - task_queue.PostTask([this, task = std::move(task)]() mutable { - task(); - run_loop_.task_queue()->PostTask(run_loop_.QuitClosure()); - }); - run_loop_.Run(); - } + absl::AnyInvocable<void()> task) override; - Waiter GetWaiter(WaitUntilSettings overrides = {}) override { - return Waiter(overrides); - } + Waiter GetWaiter(WaitUntilSettings overrides = {}) override; - std::unique_ptr<Thread> CreateThread(absl::string_view name) override { - auto thread = Thread::Create(); - thread->Start(); - return thread; - } + std::unique_ptr<Thread> CreateThread(absl::string_view name) override; protected: test::RunLoop run_loop_; @@ -1973,19 +1093,11 @@ SdpSemantics sdp_semantics); void ExecuteTask(TaskQueueBase& task_queue, - absl::AnyInvocable<void()> task) override { - task_queue.PostTask(std::move(task)); - time_controller_->AdvanceTime(TimeDelta::Zero()); - } + absl::AnyInvocable<void()> task) override; - Waiter GetWaiter(WaitUntilSettings overrides = {}) override { - overrides.clock = time_controller_.get(); - return Waiter(overrides); - } - TimeController* time_controller() override { return time_controller_.get(); } - std::unique_ptr<Thread> CreateThread(absl::string_view name) override { - return time_controller_->CreateThread(std::string(name), nullptr); - } + Waiter GetWaiter(WaitUntilSettings overrides = {}) override; + TimeController* time_controller() { return time_controller_.get(); } + std::unique_ptr<Thread> CreateThread(absl::string_view name) override; ~PeerConnectionIntegrationTestWithSimulatedTime() override;