use broadcast_common::impl_spec_display;
use broadcast_common::units::{MICROS_PER_MILLI, MICROS_PER_SEC};
use thiserror::Error;
pub const DEFAULT_UTC_TIMEOUT_US: u64 = 2 * MICROS_PER_SEC;
pub const DEFAULT_UTC_WAIT_US: u64 = 5 * MICROS_PER_SEC;
pub const DEFAULT_UTC_MAX_RTT_US: u64 = 2 * MICROS_PER_SEC;
pub const DEFAULT_UTC_RESYNC_US: u64 = 600 * MICROS_PER_SEC;
pub const DEFAULT_HOST_CLOCK_UNCERTAINTY_US: u64 = 500 * MICROS_PER_MILLI;
pub const DEFAULT_AVAILABILITY_MARGIN_US: u64 = 0;
pub const DEFAULT_EARLY_RETRY_US: u64 = 250 * MICROS_PER_MILLI;
pub const DEFAULT_EARLY_GRACE_US: u64 = MICROS_PER_SEC;
pub const DEFAULT_MIN_MPD_REFRESH_US: u64 = MICROS_PER_SEC;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum DashClockPolicy {
#[default]
Auto,
PreferHost,
}
impl DashClockPolicy {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::Auto => "auto",
Self::PreferHost => "prefer_host",
}
}
}
impl_spec_display!(DashClockPolicy);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("invalid dash config: {field}")]
pub struct DashConfigError {
pub field: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct DashConfig {
pub clock_policy: DashClockPolicy,
pub utc_timeout_us: u64,
pub utc_wait_us: u64,
pub utc_max_rtt_us: u64,
pub utc_resync_us: u64,
pub host_clock_uncertainty_us: u64,
pub live_delay_us: Option<u64>,
pub availability_margin_us: u64,
pub early_retry_us: u64,
pub early_grace_us: u64,
pub min_mpd_refresh_us: u64,
pub use_availability_time_offset: bool,
pub cross_origin_urls: bool,
}
impl Default for DashConfig {
fn default() -> Self {
Self {
clock_policy: DashClockPolicy::Auto,
utc_timeout_us: DEFAULT_UTC_TIMEOUT_US,
utc_wait_us: DEFAULT_UTC_WAIT_US,
utc_max_rtt_us: DEFAULT_UTC_MAX_RTT_US,
utc_resync_us: DEFAULT_UTC_RESYNC_US,
host_clock_uncertainty_us: DEFAULT_HOST_CLOCK_UNCERTAINTY_US,
live_delay_us: None,
availability_margin_us: DEFAULT_AVAILABILITY_MARGIN_US,
early_retry_us: DEFAULT_EARLY_RETRY_US,
early_grace_us: DEFAULT_EARLY_GRACE_US,
min_mpd_refresh_us: DEFAULT_MIN_MPD_REFRESH_US,
use_availability_time_offset: false,
cross_origin_urls: true,
}
}
}
impl DashConfig {
pub fn validate(&self) -> Result<(), DashConfigError> {
let invalid = |field| Err(DashConfigError { field });
if self.utc_timeout_us == 0 {
return invalid("utc_timeout_us");
}
if self.utc_wait_us < self.utc_timeout_us {
return invalid("utc_wait_us");
}
if self.utc_max_rtt_us == 0 {
return invalid("utc_max_rtt_us");
}
if self.utc_resync_us == 0 {
return invalid("utc_resync_us");
}
if self.early_retry_us == 0 {
return invalid("early_retry_us");
}
if self.min_mpd_refresh_us == 0 {
return invalid("min_mpd_refresh_us");
}
Ok(())
}
}
pub const DEFAULT_MAX_SEGMENT_BYTES: usize = 64 * 1024 * 1024;
pub const DEFAULT_MAX_INFLIGHT_SEGMENTS: usize = 4;
pub const DEFAULT_MAX_SEGMENT_FAILURES: u32 = 8;
pub const DEFAULT_MAX_INIT_FAILURES: u32 = 8;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("invalid PullLimits: {field} must be non-zero")]
pub struct PullLimitsError {
pub field: &'static str,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct PullLimits {
pub policy: crate::selection::Policy,
pub limits: broadcast_dash::limits::Limits,
pub max_segment_bytes: usize,
pub max_inflight_segments: usize,
pub max_segment_failures: u32,
pub max_init_failures: u32,
}
impl Default for PullLimits {
fn default() -> Self {
Self {
policy: crate::selection::Policy::default(),
limits: broadcast_dash::limits::Limits::default(),
max_segment_bytes: DEFAULT_MAX_SEGMENT_BYTES,
max_inflight_segments: DEFAULT_MAX_INFLIGHT_SEGMENTS,
max_segment_failures: DEFAULT_MAX_SEGMENT_FAILURES,
max_init_failures: DEFAULT_MAX_INIT_FAILURES,
}
}
}
impl PullLimits {
pub fn validate(&self) -> Result<(), PullLimitsError> {
if self.limits.max_bytes == 0 {
return Err(PullLimitsError {
field: "limits.max_bytes",
});
}
if self.max_segment_bytes == 0 {
return Err(PullLimitsError {
field: "max_segment_bytes",
});
}
Ok(())
}
pub(crate) fn window(&self) -> usize {
self.max_inflight_segments.max(1)
}
}