diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc')
-rw-r--r-- | third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc b/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc new file mode 100644 index 0000000000..5d77f17561 --- /dev/null +++ b/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "test/peer_scenario/peer_scenario_client.h" + +#include <limits> +#include <memory> +#include <utility> + +#include "absl/memory/memory.h" +#include "api/audio_codecs/builtin_audio_decoder_factory.h" +#include "api/audio_codecs/builtin_audio_encoder_factory.h" +#include "api/rtc_event_log/rtc_event_log_factory.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "api/test/create_time_controller.h" +#include "api/transport/field_trial_based_config.h" +#include "api/video_codecs/builtin_video_decoder_factory.h" +#include "api/video_codecs/builtin_video_encoder_factory.h" +#include "media/engine/webrtc_media_engine.h" +#include "modules/audio_device/include/test_audio_device.h" +#include "p2p/client/basic_port_allocator.h" +#include "test/fake_decoder.h" +#include "test/fake_vp8_encoder.h" +#include "test/frame_generator_capturer.h" + +namespace webrtc { +namespace test { + +namespace { + +constexpr char kCommonStreamId[] = "stream_id"; + +std::map<int, EmulatedEndpoint*> CreateEndpoints( + NetworkEmulationManager* net, + std::map<int, EmulatedEndpointConfig> endpoint_configs) { + std::map<int, EmulatedEndpoint*> endpoints; + for (const auto& kv : endpoint_configs) + endpoints[kv.first] = net->CreateEndpoint(kv.second); + return endpoints; +} + +class LambdaPeerConnectionObserver final : public PeerConnectionObserver { + public: + explicit LambdaPeerConnectionObserver( + PeerScenarioClient::CallbackHandlers* handlers) + : handlers_(handlers) {} + void OnSignalingChange( + PeerConnectionInterface::SignalingState new_state) override { + for (const auto& handler : handlers_->on_signaling_change) + handler(new_state); + } + void OnDataChannel( + rtc::scoped_refptr<DataChannelInterface> data_channel) override { + for (const auto& handler : handlers_->on_data_channel) + handler(data_channel); + } + void OnRenegotiationNeeded() override { + for (const auto& handler : handlers_->on_renegotiation_needed) + handler(); + } + void OnStandardizedIceConnectionChange( + PeerConnectionInterface::IceConnectionState new_state) override { + for (const auto& handler : handlers_->on_standardized_ice_connection_change) + handler(new_state); + } + void OnConnectionChange( + PeerConnectionInterface::PeerConnectionState new_state) override { + for (const auto& handler : handlers_->on_connection_change) + handler(new_state); + } + void OnIceGatheringChange( + PeerConnectionInterface::IceGatheringState new_state) override { + for (const auto& handler : handlers_->on_ice_gathering_change) + handler(new_state); + } + void OnIceCandidate(const IceCandidateInterface* candidate) override { + for (const auto& handler : handlers_->on_ice_candidate) + handler(candidate); + } + void OnIceCandidateError(const std::string& address, + int port, + const std::string& url, + int error_code, + const std::string& error_text) override { + for (const auto& handler : handlers_->on_ice_candidate_error) + handler(address, port, url, error_code, error_text); + } + void OnIceCandidatesRemoved( + const std::vector<cricket::Candidate>& candidates) override { + for (const auto& handler : handlers_->on_ice_candidates_removed) + handler(candidates); + } + void OnAddTrack(rtc::scoped_refptr<RtpReceiverInterface> receiver, + const std::vector<rtc::scoped_refptr<MediaStreamInterface> >& + streams) override { + for (const auto& handler : handlers_->on_add_track) + handler(receiver, streams); + } + void OnTrack( + rtc::scoped_refptr<RtpTransceiverInterface> transceiver) override { + for (const auto& handler : handlers_->on_track) + handler(transceiver); + } + void OnRemoveTrack( + rtc::scoped_refptr<RtpReceiverInterface> receiver) override { + for (const auto& handler : handlers_->on_remove_track) + handler(receiver); + } + + private: + PeerScenarioClient::CallbackHandlers* handlers_; +}; + +class LambdaCreateSessionDescriptionObserver + : public CreateSessionDescriptionObserver { + public: + explicit LambdaCreateSessionDescriptionObserver( + std::function<void(std::unique_ptr<SessionDescriptionInterface> desc)> + on_success) + : on_success_(on_success) {} + void OnSuccess(SessionDescriptionInterface* desc) override { + // Takes ownership of answer, according to CreateSessionDescriptionObserver + // convention. + on_success_(absl::WrapUnique(desc)); + } + void OnFailure(RTCError error) override { + RTC_DCHECK_NOTREACHED() << error.message(); + } + + private: + std::function<void(std::unique_ptr<SessionDescriptionInterface> desc)> + on_success_; +}; + +class LambdaSetLocalDescriptionObserver + : public SetLocalDescriptionObserverInterface { + public: + explicit LambdaSetLocalDescriptionObserver( + std::function<void(RTCError)> on_complete) + : on_complete_(on_complete) {} + void OnSetLocalDescriptionComplete(RTCError error) override { + on_complete_(error); + } + + private: + std::function<void(RTCError)> on_complete_; +}; + +class LambdaSetRemoteDescriptionObserver + : public SetRemoteDescriptionObserverInterface { + public: + explicit LambdaSetRemoteDescriptionObserver( + std::function<void(RTCError)> on_complete) + : on_complete_(on_complete) {} + void OnSetRemoteDescriptionComplete(RTCError error) override { + on_complete_(error); + } + + private: + std::function<void(RTCError)> on_complete_; +}; + +class FakeVideoEncoderFactory : public VideoEncoderFactory { + public: + FakeVideoEncoderFactory(Clock* clock) : clock_(clock) {} + std::vector<SdpVideoFormat> GetSupportedFormats() const override { + return {SdpVideoFormat("VP8")}; + } + std::unique_ptr<VideoEncoder> CreateVideoEncoder( + const SdpVideoFormat& format) override { + RTC_CHECK_EQ(format.name, "VP8"); + return std::make_unique<FakeVp8Encoder>(clock_); + } + + private: + Clock* const clock_; +}; +class FakeVideoDecoderFactory : public VideoDecoderFactory { + public: + std::vector<SdpVideoFormat> GetSupportedFormats() const override { + return {SdpVideoFormat("VP8")}; + } + std::unique_ptr<VideoDecoder> CreateVideoDecoder( + const SdpVideoFormat& format) override { + return std::make_unique<FakeDecoder>(); + } +}; +} // namespace + +PeerScenarioClient::PeerScenarioClient( + NetworkEmulationManager* net, + rtc::Thread* signaling_thread, + std::unique_ptr<LogWriterFactoryInterface> log_writer_factory, + PeerScenarioClient::Config config) + : endpoints_(CreateEndpoints(net, config.endpoints)), + task_queue_factory_(net->time_controller()->GetTaskQueueFactory()), + signaling_thread_(signaling_thread), + log_writer_factory_(std::move(log_writer_factory)), + worker_thread_(net->time_controller()->CreateThread("worker")), + handlers_(config.handlers), + observer_(new LambdaPeerConnectionObserver(&handlers_)) { + handlers_.on_track.push_back( + [this](rtc::scoped_refptr<RtpTransceiverInterface> transceiver) { + auto track = transceiver->receiver()->track().get(); + if (track->kind() == MediaStreamTrackInterface::kVideoKind) { + auto* video = static_cast<VideoTrackInterface*>(track); + RTC_DCHECK_RUN_ON(signaling_thread_); + for (auto* sink : track_id_to_video_sinks_[track->id()]) { + video->AddOrUpdateSink(sink, rtc::VideoSinkWants()); + } + } + }); + handlers_.on_signaling_change.push_back( + [this](PeerConnectionInterface::SignalingState state) { + RTC_DCHECK_RUN_ON(signaling_thread_); + if (state == PeerConnectionInterface::SignalingState::kStable && + peer_connection_->current_remote_description()) { + for (const auto& candidate : pending_ice_candidates_) { + RTC_CHECK(peer_connection_->AddIceCandidate(candidate.get())); + } + pending_ice_candidates_.clear(); + } + }); + + std::vector<EmulatedEndpoint*> endpoints_vector; + for (const auto& kv : endpoints_) + endpoints_vector.push_back(kv.second); + auto* manager = net->CreateEmulatedNetworkManagerInterface(endpoints_vector); + + PeerConnectionFactoryDependencies pcf_deps; + pcf_deps.network_thread = manager->network_thread(); + pcf_deps.signaling_thread = signaling_thread_; + pcf_deps.worker_thread = worker_thread_.get(); + pcf_deps.call_factory = + CreateTimeControllerBasedCallFactory(net->time_controller()); + pcf_deps.task_queue_factory = + net->time_controller()->CreateTaskQueueFactory(); + pcf_deps.event_log_factory = + std::make_unique<RtcEventLogFactory>(task_queue_factory_); + pcf_deps.trials = std::make_unique<FieldTrialBasedConfig>(); + + cricket::MediaEngineDependencies media_deps; + media_deps.task_queue_factory = task_queue_factory_; + media_deps.adm = TestAudioDeviceModule::Create( + task_queue_factory_, + TestAudioDeviceModule::CreatePulsedNoiseCapturer( + config.audio.pulsed_noise->amplitude * + std::numeric_limits<int16_t>::max(), + config.audio.sample_rate, config.audio.channels), + TestAudioDeviceModule::CreateDiscardRenderer(config.audio.sample_rate)); + + media_deps.audio_processing = AudioProcessingBuilder().Create(); + if (config.video.use_fake_codecs) { + media_deps.video_encoder_factory = + std::make_unique<FakeVideoEncoderFactory>( + net->time_controller()->GetClock()); + media_deps.video_decoder_factory = + std::make_unique<FakeVideoDecoderFactory>(); + } else { + media_deps.video_encoder_factory = CreateBuiltinVideoEncoderFactory(); + media_deps.video_decoder_factory = CreateBuiltinVideoDecoderFactory(); + } + media_deps.audio_encoder_factory = CreateBuiltinAudioEncoderFactory(); + media_deps.audio_decoder_factory = CreateBuiltinAudioDecoderFactory(); + media_deps.trials = pcf_deps.trials.get(); + + pcf_deps.media_engine = cricket::CreateMediaEngine(std::move(media_deps)); + pcf_deps.fec_controller_factory = nullptr; + pcf_deps.network_controller_factory = nullptr; + pcf_deps.network_state_predictor_factory = nullptr; + + pc_factory_ = CreateModularPeerConnectionFactory(std::move(pcf_deps)); + PeerConnectionFactoryInterface::Options pc_options; + pc_options.disable_encryption = config.disable_encryption; + pc_factory_->SetOptions(pc_options); + + PeerConnectionDependencies pc_deps(observer_.get()); + pc_deps.allocator = std::make_unique<cricket::BasicPortAllocator>( + manager->network_manager(), manager->packet_socket_factory()); + pc_deps.allocator->set_flags(pc_deps.allocator->flags() | + cricket::PORTALLOCATOR_DISABLE_TCP); + peer_connection_ = + pc_factory_ + ->CreatePeerConnectionOrError(config.rtc_config, std::move(pc_deps)) + .MoveValue(); + if (log_writer_factory_) { + peer_connection_->StartRtcEventLog(log_writer_factory_->Create(".rtc.dat"), + /*output_period_ms=*/1000); + } +} + +EmulatedEndpoint* PeerScenarioClient::endpoint(int index) { + RTC_CHECK_GT(endpoints_.size(), index); + return endpoints_.at(index); +} + +PeerScenarioClient::AudioSendTrack PeerScenarioClient::CreateAudio( + std::string track_id, + cricket::AudioOptions options) { + RTC_DCHECK_RUN_ON(signaling_thread_); + AudioSendTrack res; + auto source = pc_factory_->CreateAudioSource(options); + auto track = pc_factory_->CreateAudioTrack(track_id, source.get()); + res.track = track; + res.sender = peer_connection_->AddTrack(track, {kCommonStreamId}).value(); + return res; +} + +PeerScenarioClient::VideoSendTrack PeerScenarioClient::CreateVideo( + std::string track_id, + VideoSendTrackConfig config) { + RTC_DCHECK_RUN_ON(signaling_thread_); + VideoSendTrack res; + auto capturer = FrameGeneratorCapturer::Create(clock(), *task_queue_factory_, + config.generator); + res.capturer = capturer.get(); + capturer->Init(); + res.source = rtc::make_ref_counted<FrameGeneratorCapturerVideoTrackSource>( + std::move(capturer), config.screencast); + auto track = pc_factory_->CreateVideoTrack(track_id, res.source.get()); + res.track = track.get(); + res.sender = + peer_connection_->AddTrack(track, {kCommonStreamId}).MoveValue().get(); + return res; +} + +void PeerScenarioClient::AddVideoReceiveSink( + std::string track_id, + rtc::VideoSinkInterface<VideoFrame>* video_sink) { + RTC_DCHECK_RUN_ON(signaling_thread_); + track_id_to_video_sinks_[track_id].push_back(video_sink); +} + +void PeerScenarioClient::CreateAndSetSdp( + std::function<void(SessionDescriptionInterface*)> munge_offer, + std::function<void(std::string)> offer_handler) { + RTC_DCHECK_RUN_ON(signaling_thread_); + peer_connection_->CreateOffer( + rtc::make_ref_counted<LambdaCreateSessionDescriptionObserver>( + [=](std::unique_ptr<SessionDescriptionInterface> offer) { + RTC_DCHECK_RUN_ON(signaling_thread_); + if (munge_offer) { + munge_offer(offer.get()); + } + std::string sdp_offer; + RTC_CHECK(offer->ToString(&sdp_offer)); + peer_connection_->SetLocalDescription( + std::move(offer), + rtc::make_ref_counted<LambdaSetLocalDescriptionObserver>( + [sdp_offer, offer_handler](RTCError) { + offer_handler(sdp_offer); + })); + }) + .get(), + PeerConnectionInterface::RTCOfferAnswerOptions()); +} + +void PeerScenarioClient::SetSdpOfferAndGetAnswer( + std::string remote_offer, + std::function<void(std::string)> answer_handler) { + if (!signaling_thread_->IsCurrent()) { + signaling_thread_->PostTask( + [=] { SetSdpOfferAndGetAnswer(remote_offer, answer_handler); }); + return; + } + RTC_DCHECK_RUN_ON(signaling_thread_); + peer_connection_->SetRemoteDescription( + CreateSessionDescription(SdpType::kOffer, remote_offer), + rtc::make_ref_counted<LambdaSetRemoteDescriptionObserver>([=](RTCError) { + RTC_DCHECK_RUN_ON(signaling_thread_); + peer_connection_->CreateAnswer( + rtc::make_ref_counted<LambdaCreateSessionDescriptionObserver>( + [=](std::unique_ptr<SessionDescriptionInterface> answer) { + RTC_DCHECK_RUN_ON(signaling_thread_); + std::string sdp_answer; + answer->ToString(&sdp_answer); + RTC_LOG(LS_INFO) << sdp_answer; + peer_connection_->SetLocalDescription( + std::move(answer), + rtc::make_ref_counted<LambdaSetLocalDescriptionObserver>( + [answer_handler, sdp_answer](RTCError) { + answer_handler(sdp_answer); + })); + }) + .get(), + PeerConnectionInterface::RTCOfferAnswerOptions()); + })); +} + +void PeerScenarioClient::SetSdpAnswer( + std::string remote_answer, + std::function<void(const SessionDescriptionInterface&)> done_handler) { + if (!signaling_thread_->IsCurrent()) { + signaling_thread_->PostTask( + [=] { SetSdpAnswer(remote_answer, done_handler); }); + return; + } + RTC_DCHECK_RUN_ON(signaling_thread_); + peer_connection_->SetRemoteDescription( + CreateSessionDescription(SdpType::kAnswer, remote_answer), + rtc::make_ref_counted<LambdaSetRemoteDescriptionObserver>( + [remote_answer, done_handler](RTCError) { + auto answer = + CreateSessionDescription(SdpType::kAnswer, remote_answer); + done_handler(*answer); + })); +} + +void PeerScenarioClient::AddIceCandidate( + std::unique_ptr<IceCandidateInterface> candidate) { + RTC_DCHECK_RUN_ON(signaling_thread_); + if (peer_connection_->signaling_state() == + PeerConnectionInterface::SignalingState::kStable && + peer_connection_->current_remote_description()) { + RTC_CHECK(peer_connection_->AddIceCandidate(candidate.get())); + } else { + pending_ice_candidates_.push_back(std::move(candidate)); + } +} + +} // namespace test +} // namespace webrtc |