112 lines
3.8 KiB
Rust
112 lines
3.8 KiB
Rust
use std::time::Duration;
|
|
use tokio::time::Instant;
|
|
|
|
use super::UpstreamMediaKind;
|
|
use crate::calibration::{FACTORY_MJPEG_AUDIO_OFFSET_US, FACTORY_MJPEG_VIDEO_OFFSET_US};
|
|
|
|
pub(super) fn upstream_timing_trace_enabled() -> bool {
|
|
std::env::var("LESAVKA_UPSTREAM_TIMING_TRACE")
|
|
.ok()
|
|
.map(|value| {
|
|
let trimmed = value.trim();
|
|
!(trimmed.eq_ignore_ascii_case("0")
|
|
|| trimmed.eq_ignore_ascii_case("false")
|
|
|| trimmed.eq_ignore_ascii_case("no")
|
|
|| trimmed.eq_ignore_ascii_case("off"))
|
|
})
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
pub(super) fn upstream_playout_delay() -> Duration {
|
|
let delay_ms = std::env::var("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS")
|
|
.ok()
|
|
.and_then(|value| value.trim().parse::<u64>().ok())
|
|
.unwrap_or(350);
|
|
Duration::from_millis(delay_ms)
|
|
}
|
|
|
|
pub(super) fn upstream_max_live_lag() -> Duration {
|
|
let lag_ms = std::env::var("LESAVKA_UPSTREAM_MAX_LIVE_LAG_MS")
|
|
.ok()
|
|
.and_then(|value| value.trim().parse::<u64>().ok())
|
|
.unwrap_or(1_000);
|
|
Duration::from_millis(lag_ms.max(1))
|
|
}
|
|
|
|
pub(super) fn upstream_startup_timeout() -> Duration {
|
|
let timeout_ms = std::env::var("LESAVKA_UPSTREAM_STARTUP_TIMEOUT_MS")
|
|
.ok()
|
|
.and_then(|value| value.trim().parse::<u64>().ok())
|
|
.unwrap_or(60_000);
|
|
Duration::from_millis(timeout_ms.max(1))
|
|
}
|
|
|
|
pub(super) fn upstream_require_paired_startup() -> bool {
|
|
std::env::var("LESAVKA_UPSTREAM_REQUIRE_PAIRED_STARTUP")
|
|
.ok()
|
|
.map(|value| {
|
|
let trimmed = value.trim();
|
|
!(trimmed.eq_ignore_ascii_case("0")
|
|
|| trimmed.eq_ignore_ascii_case("false")
|
|
|| trimmed.eq_ignore_ascii_case("no")
|
|
|| trimmed.eq_ignore_ascii_case("off"))
|
|
})
|
|
.unwrap_or(true)
|
|
}
|
|
|
|
pub(super) fn upstream_playout_offset_us(kind: UpstreamMediaKind) -> i64 {
|
|
let name = match kind {
|
|
UpstreamMediaKind::Camera => "LESAVKA_UPSTREAM_VIDEO_PLAYOUT_OFFSET_US",
|
|
UpstreamMediaKind::Microphone => "LESAVKA_UPSTREAM_AUDIO_PLAYOUT_OFFSET_US",
|
|
};
|
|
let default_offset_us = match kind {
|
|
UpstreamMediaKind::Camera => FACTORY_MJPEG_VIDEO_OFFSET_US,
|
|
// 0.17 keeps shipped offsets small: the planner owns freshness and
|
|
// pairing, while calibration only handles sub-frame trim.
|
|
UpstreamMediaKind::Microphone => FACTORY_MJPEG_AUDIO_OFFSET_US,
|
|
};
|
|
std::env::var(name)
|
|
.ok()
|
|
.and_then(|value| value.trim().parse::<i64>().ok())
|
|
.unwrap_or(default_offset_us)
|
|
}
|
|
|
|
pub(super) fn upstream_pairing_master_slack() -> Duration {
|
|
let slack_us = std::env::var("LESAVKA_UPSTREAM_PAIR_SLACK_US")
|
|
.ok()
|
|
.and_then(|value| value.trim().parse::<u64>().ok())
|
|
.unwrap_or(80_000);
|
|
Duration::from_micros(slack_us)
|
|
}
|
|
|
|
pub(super) fn upstream_reanchor_late_threshold(playout_delay: Duration) -> Duration {
|
|
if let Some(override_ms) = std::env::var("LESAVKA_UPSTREAM_REANCHOR_LATE_MS")
|
|
.ok()
|
|
.and_then(|value| value.trim().parse::<u64>().ok())
|
|
{
|
|
return Duration::from_millis(override_ms);
|
|
}
|
|
|
|
let default_ms = (playout_delay.as_millis().min(u64::MAX as u128) as u64)
|
|
.saturating_div(2)
|
|
.max(100);
|
|
Duration::from_millis(default_ms)
|
|
}
|
|
|
|
pub(super) fn upstream_camera_startup_grace_us() -> u64 {
|
|
std::env::var("LESAVKA_UPSTREAM_CAMERA_STARTUP_GRACE_MS")
|
|
.ok()
|
|
.and_then(|value| value.trim().parse::<u64>().ok())
|
|
.unwrap_or(if cfg!(test) { 0 } else { 250 })
|
|
.saturating_mul(1_000)
|
|
}
|
|
|
|
pub(super) fn apply_playout_offset(base: Instant, offset_us: i64) -> Instant {
|
|
if offset_us >= 0 {
|
|
base + Duration::from_micros(offset_us as u64)
|
|
} else {
|
|
base.checked_sub(Duration::from_micros(offset_us.unsigned_abs()))
|
|
.unwrap_or(base)
|
|
}
|
|
}
|