blob: 866df06b0b7ad82e1e826a96ae56b87c6145bb7e [file] [log] [blame]
/*
* 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 <utility>
#include "absl/memory/memory.h"
#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
#include "modules/audio_mixer/audio_mixer_impl.h"
#include "modules/congestion_controller/goog_cc/test/goog_cc_printer.h"
#include "test/call_test.h"
namespace webrtc {
namespace test {
namespace {
const char* kPriorityStreamId = "priority-track";
CallClientFakeAudio InitAudio() {
CallClientFakeAudio setup;
auto capturer = TestAudioDeviceModule::CreatePulsedNoiseCapturer(256, 48000);
auto renderer = TestAudioDeviceModule::CreateDiscardRenderer(48000);
setup.fake_audio_device = TestAudioDeviceModule::CreateTestAudioDeviceModule(
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;
}
Call* CreateCall(CallClientConfig config,
LoggingNetworkControllerFactory* network_controller_factory_,
rtc::scoped_refptr<AudioState> audio_state) {
CallConfig call_config(network_controller_factory_->GetEventLog());
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.network_controller_factory = network_controller_factory_;
call_config.audio_state = audio_state;
return Call::Create(call_config);
}
}
LoggingNetworkControllerFactory::LoggingNetworkControllerFactory(
std::string filename,
TransportControllerConfig config) {
if (filename.empty()) {
event_log_ = RtcEventLog::CreateNull();
} else {
event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
bool success = event_log_->StartLogging(
absl::make_unique<RtcEventLogOutputFile>(filename + ".rtc.dat",
RtcEventLog::kUnlimitedOutput),
RtcEventLog::kImmediateOutput);
RTC_CHECK(success);
cc_out_ = fopen((filename + ".cc_state.txt").c_str(), "w");
}
switch (config.cc) {
case TransportControllerConfig::CongestionController::kGoogCc:
if (cc_out_) {
auto goog_printer = absl::make_unique<GoogCcStatePrinter>();
owned_cc_factory_.reset(
new GoogCcDebugFactory(event_log_.get(), goog_printer.get()));
cc_printer_.reset(
new ControlStatePrinter(cc_out_, std::move(goog_printer)));
} else {
owned_cc_factory_.reset(
new GoogCcNetworkControllerFactory(event_log_.get()));
}
break;
case TransportControllerConfig::CongestionController::kGoogCcFeedback:
if (cc_out_) {
auto goog_printer = absl::make_unique<GoogCcStatePrinter>();
owned_cc_factory_.reset(new GoogCcFeedbackDebugFactory(
event_log_.get(), goog_printer.get()));
cc_printer_.reset(
new ControlStatePrinter(cc_out_, std::move(goog_printer)));
} else {
owned_cc_factory_.reset(
new GoogCcFeedbackNetworkControllerFactory(event_log_.get()));
}
break;
case TransportControllerConfig::CongestionController::kInjected:
cc_factory_ = config.cc_factory;
if (cc_out_)
RTC_LOG(LS_WARNING)
<< "Can't log controller state for injected network controllers";
break;
}
if (cc_printer_)
cc_printer_->PrintHeaders();
if (owned_cc_factory_) {
RTC_DCHECK(!cc_factory_);
cc_factory_ = owned_cc_factory_.get();
}
}
LoggingNetworkControllerFactory::~LoggingNetworkControllerFactory() {
if (cc_out_)
fclose(cc_out_);
}
void LoggingNetworkControllerFactory::LogCongestionControllerStats(
Timestamp at_time) {
if (cc_printer_)
cc_printer_->PrintState(at_time);
}
RtcEventLog* LoggingNetworkControllerFactory::GetEventLog() const {
return event_log_.get();
}
std::unique_ptr<NetworkControllerInterface>
LoggingNetworkControllerFactory::Create(NetworkControllerConfig config) {
return cc_factory_->Create(config);
}
TimeDelta LoggingNetworkControllerFactory::GetProcessInterval() const {
return cc_factory_->GetProcessInterval();
}
CallClient::CallClient(Clock* clock,
std::string name,
std::string log_filename,
CallClientConfig config)
: clock_(clock),
name_(name),
network_controller_factory_(log_filename, config.transport),
fake_audio_setup_(InitAudio()),
call_(CreateCall(config,
&network_controller_factory_,
fake_audio_setup_.audio_state)),
transport_(clock_, call_.get()),
header_parser_(RtpHeaderParser::Create()) {}
CallClient::~CallClient() {
delete header_parser_;
}
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() {
return call_->GetStats();
}
void CallClient::OnPacketReceived(EmulatedIpPacket packet) {
// Removes added overhead before delivering packet to sender.
RTC_DCHECK_GE(packet.data.size(),
route_overhead_.at(packet.dest_endpoint_id).bytes());
packet.data.SetSize(packet.data.size() -
route_overhead_.at(packet.dest_endpoint_id).bytes());
MediaType media_type = MediaType::ANY;
if (!RtpHeaderParser::IsRtcp(packet.cdata(), packet.data.size())) {
RTPHeader header;
bool success =
header_parser_->Parse(packet.cdata(), packet.data.size(), &header);
if (!success) {
RTC_DLOG(LS_ERROR) << "Failed to parse RTP header of packet";
return;
}
media_type = ssrc_media_types_[header.ssrc];
}
call_->Receiver()->DeliverPacket(media_type, packet.data,
packet.arrival_time.us());
}
uint32_t CallClient::GetNextVideoSsrc() {
RTC_CHECK_LT(next_video_ssrc_index_, CallTest::kNumSsrcs);
return CallTest::kVideoSendSsrcs[next_video_ssrc_index_++];
}
uint32_t CallClient::GetNextAudioSsrc() {
RTC_CHECK_LT(next_audio_ssrc_index_, 1);
next_audio_ssrc_index_++;
return CallTest::kAudioSendSsrc;
}
uint32_t CallClient::GetNextRtxSsrc() {
RTC_CHECK_LT(next_rtx_ssrc_index_, CallTest::kNumSsrcs);
return CallTest::kSendRtxSsrcs[next_rtx_ssrc_index_++];
}
std::string CallClient::GetNextPriorityId() {
RTC_CHECK_LT(next_priority_index_++, 1);
return kPriorityStreamId;
}
void CallClient::AddExtensions(std::vector<RtpExtension> extensions) {
for (const auto& extension : extensions)
header_parser_->RegisterRtpHeaderExtension(extension);
}
CallClientPair::~CallClientPair() = default;
} // namespace test
} // namespace webrtc