blob: 6ef6c374ec530649c7c627a338fbc5e148cbe468 [file] [log] [blame]
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// moqt_simulator simulates the behavior of MoQ Transport under various network
// conditions and application settings.
#include <cstdint>
#include <iostream>
#include <string>
#include "absl/strings/ascii.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "quiche/quic/core/quic_bandwidth.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/moqt/moqt_priority.h"
#include "quiche/quic/moqt/test_tools/moqt_simulator.h"
#include "quiche/common/platform/api/quiche_command_line_flags.h"
namespace {
using ::quic::QuicBandwidth;
using ::quic::QuicByteCount;
using ::quic::QuicTimeDelta;
} // namespace
DEFINE_QUICHE_COMMAND_LINE_FLAG(
uint64_t, bandwidth,
moqt::test::SimulationParameters().bandwidth.ToKBitsPerSecond(),
"Bandwidth of the simulated link, in kilobits per second.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
uint64_t, bitrate,
moqt::test::SimulationParameters().bitrate.ToKBitsPerSecond(),
"Initial bitrate of the simulated media.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
absl::Duration, deadline,
moqt::test::SimulationParameters().deadline.ToAbsl(),
"Frame delivery deadline (used for measurement only).");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
absl::Duration, duration,
moqt::test::SimulationParameters().duration.ToAbsl(),
"Duration of the simulation");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
std::string, delivery_order, "desc",
"Delivery order used for the MoQT track simulated ('asc' or 'desc').");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
bool, bitrate_adaptation, true,
"Whether track payload's bitrate can be adjusted.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(absl::Duration, delivery_timeout,
absl::InfiniteDuration(),
"Delivery timeout for the subscription.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(bool, alternative_timeout, false,
"Use alternative delivery timeout design.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
float, packet_loss_rate,
moqt::test::SimulationParameters().packet_loss_rate,
"Adds additional packet loss at the publisher-to-subscriber direction, "
"specified as a fraction.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
absl::Duration, blackhole_duration,
moqt::test::SimulationParameters().blackhole_duration.ToAbsl(),
"If non-zero, makes the traffic disappear in the middle of the connection "
"for the specified duration.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
quic::QuicByteCount, aggregation_threshold,
moqt::test::SimulationParameters().aggregation_threshold,
"If non-zero, enables packet aggregation with the specified threshold (the "
"packets sent by publisher will be delayed until the specified number is "
"present).");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
absl::Duration, aggregation_timeout,
moqt::test::SimulationParameters().aggregation_timeout.ToAbsl(),
"Sets the timeout for packet aggregation; if zero, this will be set to the "
"quarter of min RTT.");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
absl::Duration, group_duration, absl::ZeroDuration(),
"If non-zero, sets the group size to match the requested duration");
DEFINE_QUICHE_COMMAND_LINE_FLAG(
std::string, output_format, "",
R"(If non-empty, instead of the usual human-readable format,
the tool will output the raw numbers from the simulation, formatted as
descrbied by the parameter.
Supported format keys:
* {on_time_fraction} -- fraction of objects that arrived on time
* {late_fraction} -- fraction of objects that arrived late
* {missing_fraction} -- fraction of objects that never arrived)");
int main(int argc, char** argv) {
moqt::test::SimulationParameters parameters;
quiche::QuicheParseCommandLineFlags("moqt_simulator", argc, argv);
parameters.bandwidth = quic::QuicBandwidth::FromKBitsPerSecond(
quiche::GetQuicheCommandLineFlag(FLAGS_bandwidth));
parameters.bitrate = quic::QuicBandwidth::FromKBitsPerSecond(
quiche::GetQuicheCommandLineFlag(FLAGS_bitrate));
parameters.deadline =
quic::QuicTimeDelta(quiche::GetQuicheCommandLineFlag(FLAGS_deadline));
parameters.duration =
quic::QuicTimeDelta(quiche::GetQuicheCommandLineFlag(FLAGS_duration));
parameters.bitrate_adaptation =
quiche::GetQuicheCommandLineFlag(FLAGS_bitrate_adaptation);
parameters.delivery_timeout = quic::QuicTimeDelta(
quiche::GetQuicheCommandLineFlag(FLAGS_delivery_timeout));
parameters.packet_loss_rate =
quiche::GetQuicheCommandLineFlag(FLAGS_packet_loss_rate);
parameters.alternative_timeout =
quiche::GetQuicheCommandLineFlag(FLAGS_alternative_timeout);
parameters.blackhole_duration = quic::QuicTimeDelta(
quiche::GetQuicheCommandLineFlag(FLAGS_blackhole_duration));
parameters.aggregation_threshold =
quiche::GetQuicheCommandLineFlag(FLAGS_aggregation_threshold);
parameters.aggregation_timeout = quic::QuicTimeDelta(
quiche::GetQuicheCommandLineFlag(FLAGS_aggregation_timeout));
absl::Duration group_duration =
quiche::GetQuicheCommandLineFlag(FLAGS_group_duration);
if (group_duration > absl::ZeroDuration()) {
parameters.keyframe_interval =
absl::ToDoubleSeconds(group_duration) * parameters.fps;
}
std::string raw_delivery_order = absl::AsciiStrToLower(
quiche::GetQuicheCommandLineFlag(FLAGS_delivery_order));
if (raw_delivery_order == "asc") {
parameters.delivery_order = moqt::MoqtDeliveryOrder::kAscending;
} else if (raw_delivery_order == "desc") {
parameters.delivery_order = moqt::MoqtDeliveryOrder::kDescending;
} else {
std::cerr << "--delivery_order must be 'asc' or 'desc'." << std::endl;
return 1;
}
moqt::test::MoqtSimulator simulator(parameters);
simulator.Run();
std::string output_format =
quiche::GetQuicheCommandLineFlag(FLAGS_output_format);
if (output_format.empty()) {
simulator.HumanReadableOutput();
} else {
simulator.CustomOutput(output_format);
}
return 0;
}