102 lines
3.6 KiB
Rust
102 lines
3.6 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(1_000);
|
|
Duration::from_millis(delay_ms)
|
|
}
|
|
|
|
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,
|
|
// Hardware sync probes on the MJPEG UVC path show the UAC leg arriving
|
|
// about 80ms after video when using the older +35ms default. Bias the
|
|
// server playout earlier so the shipped default lands in the preferred
|
|
// lip-sync band instead of hovering at the guardrail.
|
|
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(20_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(250);
|
|
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 upstream_reanchor_window_us(playout_delay: Duration) -> u64 {
|
|
playout_delay.as_micros().min(u64::MAX as u128) as u64
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|