use serde::{Deserialize, Serialize};
use std::fmt;
use std::time::Duration;
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CandidatePairState {
#[default]
#[serde(rename = "unspecified")]
Unspecified = 0,
#[serde(rename = "waiting")]
Waiting = 1,
#[serde(rename = "in-progress")]
InProgress = 2,
#[serde(rename = "failed")]
Failed = 3,
#[serde(rename = "succeeded")]
Succeeded = 4,
}
impl From<u8> for CandidatePairState {
fn from(v: u8) -> Self {
match v {
1 => Self::Waiting,
2 => Self::InProgress,
3 => Self::Failed,
4 => Self::Succeeded,
_ => Self::Unspecified,
}
}
}
impl fmt::Display for CandidatePairState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
Self::Waiting => "waiting",
Self::InProgress => "in-progress",
Self::Failed => "failed",
Self::Succeeded => "succeeded",
Self::Unspecified => "unspecified",
};
write!(f, "{s}")
}
}
#[derive(Clone, Copy)]
pub struct CandidatePair {
pub local_index: usize,
pub remote_index: usize,
pub local_priority: u32,
pub remote_priority: u32,
pub(crate) ice_role_controlling: bool,
pub(crate) binding_request_count: u16,
pub(crate) state: CandidatePairState,
pub(crate) nominated: bool,
pub(crate) requests_sent: u64,
pub(crate) requests_received: u64,
pub(crate) responses_sent: u64,
pub(crate) responses_received: u64,
pub(crate) consent_requests_sent: u64,
pub(crate) total_round_trip_time: Duration,
pub(crate) current_round_trip_time: Duration,
}
impl fmt::Debug for CandidatePair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"prio {} (local, prio {}) {} <-> {} (remote, prio {})",
self.priority(),
self.local_priority,
self.local_index,
self.remote_index,
self.remote_priority,
)
}
}
impl fmt::Display for CandidatePair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"prio {} (local, prio {}) {} <-> {} (remote, prio {})",
self.priority(),
self.local_priority,
self.local_index,
self.remote_index,
self.remote_priority,
)
}
}
impl PartialEq for CandidatePair {
fn eq(&self, other: &Self) -> bool {
self.local_index == other.local_index && self.remote_index == other.remote_index
}
}
impl CandidatePair {
#[must_use]
pub fn new(
local_index: usize,
remote_index: usize,
local_priority: u32,
remote_priority: u32,
ice_role_controlling: bool,
) -> Self {
Self {
local_index,
remote_index,
local_priority,
remote_priority,
ice_role_controlling,
state: CandidatePairState::Waiting,
binding_request_count: 0,
nominated: false,
requests_sent: 0,
requests_received: 0,
responses_sent: 0,
responses_received: 0,
consent_requests_sent: 0,
total_round_trip_time: Duration::ZERO,
current_round_trip_time: Duration::ZERO,
}
}
pub fn priority(&self) -> u64 {
let (g, d) = if self.ice_role_controlling {
(self.local_priority, self.remote_priority)
} else {
(self.remote_priority, self.local_priority)
};
((1 << 32_u64) - 1) * u64::from(std::cmp::min(g, d))
+ 2 * u64::from(std::cmp::max(g, d))
+ u64::from(g > d)
}
pub fn on_request_sent(&mut self) {
self.requests_sent += 1;
}
pub fn on_request_received(&mut self) {
self.requests_received += 1;
}
pub fn on_response_sent(&mut self) {
self.responses_sent += 1;
}
pub fn on_response_received(&mut self, rtt: Duration) {
self.responses_received += 1;
self.current_round_trip_time = rtt;
self.total_round_trip_time += rtt;
}
pub fn on_consent_request_sent(&mut self) {
self.consent_requests_sent += 1;
}
}