[feat] receive and parse congestion control feedback supported

This commit is contained in:
dijunkun
2025-01-13 17:12:28 +08:00
parent 63ed77e43a
commit ba268016e4
15 changed files with 1112 additions and 7 deletions

View File

@@ -0,0 +1,97 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-13
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _NETWORK_ROUTE_H_
#define _NETWORK_ROUTE_H_
#include <cstdint>
#include <string>
struct NetworkRoute;
class RouteEndpoint {
public:
enum AdapterType {
// This enum resembles the one in Chromium net::ConnectionType.
ADAPTER_TYPE_UNKNOWN = 0,
ADAPTER_TYPE_ETHERNET = 1 << 0,
ADAPTER_TYPE_WIFI = 1 << 1,
ADAPTER_TYPE_CELLULAR = 1 << 2, // This is CELLULAR of unknown type.
ADAPTER_TYPE_VPN = 1 << 3,
ADAPTER_TYPE_LOOPBACK = 1 << 4,
// ADAPTER_TYPE_ANY is used for a network, which only contains a single "any
// address" IP address (INADDR_ANY for IPv4 or in6addr_any for IPv6), and
// can
// use any/all network interfaces. Whereas ADAPTER_TYPE_UNKNOWN is used
// when the network uses a specific interface/IP, but its interface type can
// not be determined or not fit in this enum.
ADAPTER_TYPE_ANY = 1 << 5,
ADAPTER_TYPE_CELLULAR_2G = 1 << 6,
ADAPTER_TYPE_CELLULAR_3G = 1 << 7,
ADAPTER_TYPE_CELLULAR_4G = 1 << 8,
ADAPTER_TYPE_CELLULAR_5G = 1 << 9
};
public:
RouteEndpoint() {} // Used by tests.
RouteEndpoint(AdapterType adapter_type, uint16_t adapter_id,
uint16_t network_id, bool uses_turn)
: adapter_type_(adapter_type),
adapter_id_(adapter_id),
network_id_(network_id),
uses_turn_(uses_turn) {}
RouteEndpoint(const RouteEndpoint&) = default;
RouteEndpoint& operator=(const RouteEndpoint&) = default;
bool operator==(const RouteEndpoint& other) const {
return adapter_type_ == other.adapter_type_ &&
adapter_id_ == other.adapter_id_ &&
network_id_ == other.network_id_ && uses_turn_ == other.uses_turn_;
}
// Used by tests.
static RouteEndpoint CreateWithNetworkId(uint16_t network_id) {
return RouteEndpoint(ADAPTER_TYPE_UNKNOWN,
/* adapter_id = */ 0, network_id,
/* uses_turn = */ false);
}
RouteEndpoint CreateWithTurn(bool uses_turn) const {
return RouteEndpoint(adapter_type_, adapter_id_, network_id_, uses_turn);
}
AdapterType adapter_type() const { return adapter_type_; }
uint16_t adapter_id() const { return adapter_id_; }
uint16_t network_id() const { return network_id_; }
bool uses_turn() const { return uses_turn_; }
private:
AdapterType adapter_type_ = ADAPTER_TYPE_UNKNOWN;
uint16_t adapter_id_ = 0;
uint16_t network_id_ = 0;
bool uses_turn_ = false;
};
struct NetworkRoute {
bool connected = false;
RouteEndpoint local;
RouteEndpoint remote;
// Last packet id sent on the PREVIOUS route.
int last_sent_packet_id = -1;
// The overhead in bytes from IP layer and above.
// This is the maximum of any part of the route.
int packet_overhead = 0;
bool operator==(const NetworkRoute& other) const {
return connected == other.connected && local == other.local &&
remote == other.remote && packet_overhead == other.packet_overhead &&
last_sent_packet_id == other.last_sent_packet_id;
}
bool operator!=(const NetworkRoute& other) { return !operator==(other); }
};
#endif

161
src/common/network_types.h Normal file
View File

@@ -0,0 +1,161 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-01-13
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _NETWORK_TYPES_H_
#define _NETWORK_TYPES_H_
#include <algorithm>
#include <limits>
#include <vector>
#include "enc_mark.h"
struct NetworkEstimate {
int64_t at_time = std::numeric_limits<int64_t>::max();
// Deprecated, use TargetTransferRate::target_rate instead.
int64_t bandwidth = std::numeric_limits<int64_t>::max();
int64_t round_trip_time = std::numeric_limits<int64_t>::max();
int64_t bwe_period = std::numeric_limits<int64_t>::max();
float loss_rate_ratio = 0;
};
struct TargetTransferRate {
int64_t at_time = std::numeric_limits<int64_t>::max();
// The estimate on which the target rate is based on.
NetworkEstimate network_estimate;
int64_t target_rate = 0;
int64_t stable_target_rate = 0;
double cwnd_reduce_ratio = 0;
};
struct NetworkControlUpdate {
NetworkControlUpdate() = default;
NetworkControlUpdate(const NetworkControlUpdate&) = default;
~NetworkControlUpdate() = default;
bool has_updates() const {
// return congestion_window.has_value() || pacer_config.has_value() ||
// !probe_cluster_configs.empty() ||
return target_rate.has_value();
}
std::optional<int64_t> congestion_window;
// std::optional<PacerConfig> pacer_config;
// std::vector<ProbeClusterConfig> probe_cluster_configs;
std::optional<TargetTransferRate> target_rate;
};
struct PacedPacketInfo {
PacedPacketInfo() = default;
PacedPacketInfo(int probe_cluster_id, int probe_cluster_min_probes,
int probe_cluster_min_bytes)
: probe_cluster_id(probe_cluster_id),
probe_cluster_min_probes(probe_cluster_min_probes),
probe_cluster_min_bytes(probe_cluster_min_bytes) {}
bool operator==(const PacedPacketInfo& rhs) const {
return send_bitrate == rhs.send_bitrate &&
probe_cluster_id == rhs.probe_cluster_id &&
probe_cluster_min_probes == rhs.probe_cluster_min_probes &&
probe_cluster_min_bytes == rhs.probe_cluster_min_bytes;
}
// TODO(srte): Move probing info to a separate, optional struct.
static constexpr int kNotAProbe = -1;
int64_t send_bitrate = 0;
int probe_cluster_id = kNotAProbe;
int probe_cluster_min_probes = -1;
int probe_cluster_min_bytes = -1;
int probe_cluster_bytes_sent = 0;
};
struct SentPacket {
int64_t send_time = std::numeric_limits<int64_t>::max();
// Size of packet with overhead up to IP layer.
int64_t size = 0;
// Size of preceeding packets that are not part of feedback.
int64_t prior_unacked_data = 0;
// Probe cluster id and parameters including bitrate, number of packets and
// number of bytes.
PacedPacketInfo pacing_info;
// True if the packet is an audio packet, false for video, padding, RTX etc.
bool audio = false;
// Transport independent sequence number, any tracked packet should have a
// sequence number that is unique over the whole call and increasing by 1 for
// each packet.
int64_t sequence_number;
// Tracked data in flight when the packet was sent, excluding unacked data.
int64_t data_in_flight = 0;
};
struct PacketResult {
class ReceiveTimeOrder {
public:
bool operator()(const PacketResult& lhs, const PacketResult& rhs);
};
PacketResult() = default;
PacketResult(const PacketResult&) = default;
~PacketResult() = default;
inline bool IsReceived() const {
return receive_time != std::numeric_limits<int64_t>::max();
}
SentPacket sent_packet;
int64_t receive_time = std::numeric_limits<int64_t>::max();
EcnMarking ecn = EcnMarking::kNotEct;
};
struct TransportPacketsFeedback {
TransportPacketsFeedback() = default;
TransportPacketsFeedback(const TransportPacketsFeedback& other) = default;
~TransportPacketsFeedback() = default;
int64_t feedback_time = std::numeric_limits<int64_t>::max();
int64_t data_in_flight = 0;
bool transport_supports_ecn = false;
std::vector<PacketResult> packet_feedbacks;
// Arrival times for messages without send time information.
std::vector<int64_t> sendless_arrival_times;
std::vector<PacketResult> ReceivedWithSendInfo() const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (fb.IsReceived()) {
res.push_back(fb);
}
}
return res;
}
std::vector<PacketResult> LostWithSendInfo() const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (!fb.IsReceived()) {
res.push_back(fb);
}
}
return res;
}
std::vector<PacketResult> PacketsWithFeedback() const {
return packet_feedbacks;
}
std::vector<PacketResult> SortedByReceiveTime() const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (fb.IsReceived()) {
res.push_back(fb);
}
}
std::sort(res.begin(), res.end(), PacketResult::ReceiveTimeOrder());
return res;
}
};
#endif