summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/test/scenario/call_client.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/test/scenario/call_client.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/test/scenario/call_client.cc')
-rw-r--r--third_party/libwebrtc/test/scenario/call_client.cc388
1 files changed, 388 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/scenario/call_client.cc b/third_party/libwebrtc/test/scenario/call_client.cc
new file mode 100644
index 0000000000..fdf36dee08
--- /dev/null
+++ b/third_party/libwebrtc/test/scenario/call_client.cc
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2018 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/scenario/call_client.h"
+
+#include <iostream>
+#include <memory>
+#include <utility>
+
+#include "api/media_types.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/rtc_event_log/rtc_event_log_factory.h"
+#include "api/transport/network_types.h"
+#include "call/call.h"
+#include "call/rtp_transport_controller_send_factory.h"
+#include "modules/audio_device/include/test_audio_device.h"
+#include "modules/audio_mixer/audio_mixer_impl.h"
+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
+#include "modules/rtp_rtcp/source/rtp_packet_received.h"
+#include "modules/rtp_rtcp/source/rtp_util.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+static constexpr size_t kNumSsrcs = 6;
+const uint32_t kSendRtxSsrcs[kNumSsrcs] = {0xBADCAFD, 0xBADCAFE, 0xBADCAFF,
+ 0xBADCB00, 0xBADCB01, 0xBADCB02};
+const uint32_t kVideoSendSsrcs[kNumSsrcs] = {0xC0FFED, 0xC0FFEE, 0xC0FFEF,
+ 0xC0FFF0, 0xC0FFF1, 0xC0FFF2};
+const uint32_t kVideoRecvLocalSsrcs[kNumSsrcs] = {0xDAB001, 0xDAB002, 0xDAB003,
+ 0xDAB004, 0xDAB005, 0xDAB006};
+const uint32_t kAudioSendSsrc = 0xDEADBEEF;
+const uint32_t kReceiverLocalAudioSsrc = 0x1234567;
+
+constexpr int kEventLogOutputIntervalMs = 5000;
+
+CallClientFakeAudio InitAudio(TimeController* time_controller) {
+ CallClientFakeAudio setup;
+ auto capturer = TestAudioDeviceModule::CreatePulsedNoiseCapturer(256, 48000);
+ auto renderer = TestAudioDeviceModule::CreateDiscardRenderer(48000);
+ setup.fake_audio_device = TestAudioDeviceModule::Create(
+ time_controller->GetTaskQueueFactory(), std::move(capturer),
+ std::move(renderer), 1.f);
+ setup.apm = AudioProcessingBuilder().Create();
+ setup.fake_audio_device->Init();
+ AudioState::Config audio_state_config;
+ audio_state_config.audio_mixer = AudioMixerImpl::Create();
+ audio_state_config.audio_processing = setup.apm;
+ audio_state_config.audio_device_module = setup.fake_audio_device;
+ setup.audio_state = AudioState::Create(audio_state_config);
+ setup.fake_audio_device->RegisterAudioCallback(
+ setup.audio_state->audio_transport());
+ return setup;
+}
+
+std::unique_ptr<Call> CreateCall(
+ TimeController* time_controller,
+ RtcEventLog* event_log,
+ CallClientConfig config,
+ LoggingNetworkControllerFactory* network_controller_factory,
+ rtc::scoped_refptr<AudioState> audio_state) {
+ CallConfig call_config(event_log);
+ call_config.bitrate_config.max_bitrate_bps =
+ config.transport.rates.max_rate.bps_or(-1);
+ call_config.bitrate_config.min_bitrate_bps =
+ config.transport.rates.min_rate.bps();
+ call_config.bitrate_config.start_bitrate_bps =
+ config.transport.rates.start_rate.bps();
+ call_config.task_queue_factory = time_controller->GetTaskQueueFactory();
+ call_config.network_controller_factory = network_controller_factory;
+ call_config.audio_state = audio_state;
+ call_config.pacer_burst_interval = config.pacer_burst_interval;
+ call_config.trials = config.field_trials;
+ Clock* clock = time_controller->GetClock();
+ return Call::Create(call_config, clock,
+ RtpTransportControllerSendFactory().Create(
+ call_config.ExtractTransportConfig(), clock));
+}
+
+std::unique_ptr<RtcEventLog> CreateEventLog(
+ TaskQueueFactory* task_queue_factory,
+ LogWriterFactoryInterface* log_writer_factory) {
+ if (!log_writer_factory) {
+ return std::make_unique<RtcEventLogNull>();
+ }
+ auto event_log = RtcEventLogFactory(task_queue_factory)
+ .CreateRtcEventLog(RtcEventLog::EncodingType::NewFormat);
+ bool success = event_log->StartLogging(log_writer_factory->Create(".rtc.dat"),
+ kEventLogOutputIntervalMs);
+ RTC_CHECK(success);
+ return event_log;
+}
+} // namespace
+NetworkControleUpdateCache::NetworkControleUpdateCache(
+ std::unique_ptr<NetworkControllerInterface> controller)
+ : controller_(std::move(controller)) {}
+NetworkControlUpdate NetworkControleUpdateCache::OnNetworkAvailability(
+ NetworkAvailability msg) {
+ return Update(controller_->OnNetworkAvailability(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnNetworkRouteChange(
+ NetworkRouteChange msg) {
+ return Update(controller_->OnNetworkRouteChange(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnProcessInterval(
+ ProcessInterval msg) {
+ return Update(controller_->OnProcessInterval(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnRemoteBitrateReport(
+ RemoteBitrateReport msg) {
+ return Update(controller_->OnRemoteBitrateReport(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnRoundTripTimeUpdate(
+ RoundTripTimeUpdate msg) {
+ return Update(controller_->OnRoundTripTimeUpdate(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnSentPacket(SentPacket msg) {
+ return Update(controller_->OnSentPacket(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnReceivedPacket(
+ ReceivedPacket msg) {
+ return Update(controller_->OnReceivedPacket(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnStreamsConfig(
+ StreamsConfig msg) {
+ return Update(controller_->OnStreamsConfig(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnTargetRateConstraints(
+ TargetRateConstraints msg) {
+ return Update(controller_->OnTargetRateConstraints(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnTransportLossReport(
+ TransportLossReport msg) {
+ return Update(controller_->OnTransportLossReport(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnTransportPacketsFeedback(
+ TransportPacketsFeedback msg) {
+ return Update(controller_->OnTransportPacketsFeedback(msg));
+}
+NetworkControlUpdate NetworkControleUpdateCache::OnNetworkStateEstimate(
+ NetworkStateEstimate msg) {
+ return Update(controller_->OnNetworkStateEstimate(msg));
+}
+
+NetworkControlUpdate NetworkControleUpdateCache::update_state() const {
+ return update_state_;
+}
+NetworkControlUpdate NetworkControleUpdateCache::Update(
+ NetworkControlUpdate update) {
+ if (update.target_rate)
+ update_state_.target_rate = update.target_rate;
+ if (update.pacer_config)
+ update_state_.pacer_config = update.pacer_config;
+ if (update.congestion_window)
+ update_state_.congestion_window = update.congestion_window;
+ if (!update.probe_cluster_configs.empty())
+ update_state_.probe_cluster_configs = update.probe_cluster_configs;
+ return update;
+}
+
+LoggingNetworkControllerFactory::LoggingNetworkControllerFactory(
+ LogWriterFactoryInterface* log_writer_factory,
+ TransportControllerConfig config) {
+ if (config.cc_factory) {
+ cc_factory_ = config.cc_factory;
+ if (log_writer_factory)
+ RTC_LOG(LS_WARNING)
+ << "Can't log controller state for injected network controllers";
+ } else {
+ if (log_writer_factory) {
+ goog_cc_factory_.AttachWriter(
+ log_writer_factory->Create(".cc_state.txt"));
+ print_cc_state_ = true;
+ }
+ cc_factory_ = &goog_cc_factory_;
+ }
+}
+
+LoggingNetworkControllerFactory::~LoggingNetworkControllerFactory() {}
+
+void LoggingNetworkControllerFactory::LogCongestionControllerStats(
+ Timestamp at_time) {
+ if (print_cc_state_)
+ goog_cc_factory_.PrintState(at_time);
+}
+
+NetworkControlUpdate LoggingNetworkControllerFactory::GetUpdate() const {
+ if (last_controller_)
+ return last_controller_->update_state();
+ return NetworkControlUpdate();
+}
+
+std::unique_ptr<NetworkControllerInterface>
+LoggingNetworkControllerFactory::Create(NetworkControllerConfig config) {
+ auto controller =
+ std::make_unique<NetworkControleUpdateCache>(cc_factory_->Create(config));
+ last_controller_ = controller.get();
+ return controller;
+}
+
+TimeDelta LoggingNetworkControllerFactory::GetProcessInterval() const {
+ return cc_factory_->GetProcessInterval();
+}
+
+void LoggingNetworkControllerFactory::SetRemoteBitrateEstimate(
+ RemoteBitrateReport msg) {
+ if (last_controller_)
+ last_controller_->OnRemoteBitrateReport(msg);
+}
+
+CallClient::CallClient(
+ TimeController* time_controller,
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
+ CallClientConfig config)
+ : time_controller_(time_controller),
+ clock_(time_controller->GetClock()),
+ log_writer_factory_(std::move(log_writer_factory)),
+ network_controller_factory_(log_writer_factory_.get(), config.transport),
+ task_queue_(time_controller->GetTaskQueueFactory()->CreateTaskQueue(
+ "CallClient",
+ TaskQueueFactory::Priority::NORMAL)) {
+ config.field_trials = &field_trials_;
+ SendTask([this, config] {
+ event_log_ = CreateEventLog(time_controller_->GetTaskQueueFactory(),
+ log_writer_factory_.get());
+ fake_audio_setup_ = InitAudio(time_controller_);
+
+ call_ =
+ CreateCall(time_controller_, event_log_.get(), config,
+ &network_controller_factory_, fake_audio_setup_.audio_state);
+ transport_ = std::make_unique<NetworkNodeTransport>(clock_, call_.get());
+ });
+}
+
+CallClient::~CallClient() {
+ SendTask([&] {
+ call_.reset();
+ fake_audio_setup_ = {};
+ rtc::Event done;
+ event_log_->StopLogging([&done] { done.Set(); });
+ done.Wait(rtc::Event::kForever);
+ event_log_.reset();
+ });
+}
+
+ColumnPrinter CallClient::StatsPrinter() {
+ return ColumnPrinter::Lambda(
+ "pacer_delay call_send_bw",
+ [this](rtc::SimpleStringBuilder& sb) {
+ Call::Stats call_stats = call_->GetStats();
+ sb.AppendFormat("%.3lf %.0lf", call_stats.pacer_delay_ms / 1000.0,
+ call_stats.send_bandwidth_bps / 8.0);
+ },
+ 64);
+}
+
+Call::Stats CallClient::GetStats() {
+ // This call needs to be made on the thread that `call_` was constructed on.
+ Call::Stats stats;
+ SendTask([this, &stats] { stats = call_->GetStats(); });
+ return stats;
+}
+
+DataRate CallClient::target_rate() const {
+ return network_controller_factory_.GetUpdate().target_rate->target_rate;
+}
+
+DataRate CallClient::stable_target_rate() const {
+ return network_controller_factory_.GetUpdate()
+ .target_rate->stable_target_rate;
+}
+
+DataRate CallClient::padding_rate() const {
+ return network_controller_factory_.GetUpdate().pacer_config->pad_rate();
+}
+
+void CallClient::SetRemoteBitrate(DataRate bitrate) {
+ RemoteBitrateReport msg;
+ msg.bandwidth = bitrate;
+ msg.receive_time = clock_->CurrentTime();
+ network_controller_factory_.SetRemoteBitrateEstimate(msg);
+}
+
+void CallClient::UpdateBitrateConstraints(
+ const BitrateConstraints& constraints) {
+ SendTask([this, &constraints]() {
+ call_->GetTransportControllerSend()->SetSdpBitrateParameters(constraints);
+ });
+}
+
+void CallClient::SetAudioReceiveRtpHeaderExtensions(
+ rtc::ArrayView<RtpExtension> extensions) {
+ SendTask([this, &extensions]() {
+ audio_extensions_ = RtpHeaderExtensionMap(extensions);
+ });
+}
+
+void CallClient::SetVideoReceiveRtpHeaderExtensions(
+ rtc::ArrayView<RtpExtension> extensions) {
+ SendTask([this, &extensions]() {
+ video_extensions_ = RtpHeaderExtensionMap(extensions);
+ });
+}
+
+void CallClient::OnPacketReceived(EmulatedIpPacket packet) {
+ MediaType media_type = MediaType::ANY;
+ if (IsRtpPacket(packet.data)) {
+ media_type = ssrc_media_types_[ParseRtpSsrc(packet.data)];
+ task_queue_.PostTask([this, media_type,
+ packet = std::move(packet)]() mutable {
+ RtpHeaderExtensionMap& extension_map = media_type == MediaType::AUDIO
+ ? audio_extensions_
+ : video_extensions_;
+ RtpPacketReceived received_packet(&extension_map, packet.arrival_time);
+ RTC_CHECK(received_packet.Parse(packet.data));
+ call_->Receiver()->DeliverRtpPacket(media_type, received_packet,
+ /*undemuxable_packet_handler=*/
+ [](const RtpPacketReceived& packet) {
+ RTC_CHECK_NOTREACHED();
+ return false;
+ });
+ });
+ } else {
+ task_queue_.PostTask(
+ [call = call_.get(), packet = std::move(packet)]() mutable {
+ call->Receiver()->DeliverRtcpPacket(packet.data);
+ });
+ }
+}
+
+std::unique_ptr<RtcEventLogOutput> CallClient::GetLogWriter(std::string name) {
+ if (!log_writer_factory_ || name.empty())
+ return nullptr;
+ return log_writer_factory_->Create(name);
+}
+
+uint32_t CallClient::GetNextVideoSsrc() {
+ RTC_CHECK_LT(next_video_ssrc_index_, kNumSsrcs);
+ return kVideoSendSsrcs[next_video_ssrc_index_++];
+}
+
+uint32_t CallClient::GetNextVideoLocalSsrc() {
+ RTC_CHECK_LT(next_video_local_ssrc_index_, kNumSsrcs);
+ return kVideoRecvLocalSsrcs[next_video_local_ssrc_index_++];
+}
+
+uint32_t CallClient::GetNextAudioSsrc() {
+ RTC_CHECK_LT(next_audio_ssrc_index_, 1);
+ next_audio_ssrc_index_++;
+ return kAudioSendSsrc;
+}
+
+uint32_t CallClient::GetNextAudioLocalSsrc() {
+ RTC_CHECK_LT(next_audio_local_ssrc_index_, 1);
+ next_audio_local_ssrc_index_++;
+ return kReceiverLocalAudioSsrc;
+}
+
+uint32_t CallClient::GetNextRtxSsrc() {
+ RTC_CHECK_LT(next_rtx_ssrc_index_, kNumSsrcs);
+ return kSendRtxSsrcs[next_rtx_ssrc_index_++];
+}
+
+void CallClient::SendTask(std::function<void()> task) {
+ task_queue_.SendTask(std::move(task));
+}
+
+int16_t CallClient::Bind(EmulatedEndpoint* endpoint) {
+ uint16_t port = endpoint->BindReceiver(0, this).value();
+ endpoints_.push_back({endpoint, port});
+ return port;
+}
+
+void CallClient::UnBind() {
+ for (auto ep_port : endpoints_)
+ ep_port.first->UnbindReceiver(ep_port.second);
+}
+
+CallClientPair::~CallClientPair() = default;
+
+} // namespace test
+} // namespace webrtc