feat: support compensated output delay probe
This commit is contained in:
parent
b6faedf802
commit
6236292f56
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.19.3"
|
version = "0.19.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1686,7 +1686,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.19.3"
|
version = "0.19.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@ -1698,7 +1698,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.19.3"
|
version = "0.19.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.19.3"
|
version = "0.19.4"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -72,6 +72,8 @@ struct Config {
|
|||||||
probe_pulse_period_ms: u32,
|
probe_pulse_period_ms: u32,
|
||||||
probe_pulse_width_ms: u32,
|
probe_pulse_width_ms: u32,
|
||||||
probe_event_width_codes: String,
|
probe_event_width_codes: String,
|
||||||
|
probe_audio_delay_us: i64,
|
||||||
|
probe_video_delay_us: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Eq, PartialEq)]
|
#[derive(Debug, Default, Eq, PartialEq)]
|
||||||
@ -84,6 +86,8 @@ struct ParsedCommandArgs {
|
|||||||
probe_pulse_period_ms: u32,
|
probe_pulse_period_ms: u32,
|
||||||
probe_pulse_width_ms: u32,
|
probe_pulse_width_ms: u32,
|
||||||
probe_event_width_codes: String,
|
probe_event_width_codes: String,
|
||||||
|
probe_audio_delay_us: i64,
|
||||||
|
probe_video_delay_us: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
@ -93,7 +97,7 @@ enum ParseOutcome {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> &'static str {
|
fn usage() -> &'static str {
|
||||||
"Usage: lesavka-relayctl [--server http://HOST:50051] <status|version|upstream-sync|output-delay-probe [duration_s warmup_s period_ms width_ms codes]|calibration|calibrate <audio_delta_us> <video_delta_us> [note]|calibration-save-default|calibration-restore-default|calibration-restore-factory|auto|on|off|recover-usb|recover-uac|recover-uvc|reset-usb>"
|
"Usage: lesavka-relayctl [--server http://HOST:50051] <status|version|upstream-sync|output-delay-probe [duration_s warmup_s period_ms width_ms codes audio_delay_us video_delay_us]|calibration|calibrate <audio_delta_us> <video_delta_us> [note]|calibration-save-default|calibration-restore-default|calibration-restore-factory|auto|on|off|recover-usb|recover-uac|recover-uvc|reset-usb>"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_args_outcome_from<I, S>(args: I) -> Result<ParseOutcome>
|
fn parse_args_outcome_from<I, S>(args: I) -> Result<ParseOutcome>
|
||||||
@ -141,6 +145,8 @@ where
|
|||||||
probe_pulse_period_ms: parsed.probe_pulse_period_ms,
|
probe_pulse_period_ms: parsed.probe_pulse_period_ms,
|
||||||
probe_pulse_width_ms: parsed.probe_pulse_width_ms,
|
probe_pulse_width_ms: parsed.probe_pulse_width_ms,
|
||||||
probe_event_width_codes: parsed.probe_event_width_codes,
|
probe_event_width_codes: parsed.probe_event_width_codes,
|
||||||
|
probe_audio_delay_us: parsed.probe_audio_delay_us,
|
||||||
|
probe_video_delay_us: parsed.probe_video_delay_us,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,9 +185,9 @@ fn parse_command_args(command: CommandKind, args: Vec<String>) -> Result<ParsedC
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_output_delay_probe_args(args: Vec<String>) -> Result<ParsedCommandArgs> {
|
fn parse_output_delay_probe_args(args: Vec<String>) -> Result<ParsedCommandArgs> {
|
||||||
if args.len() > 5 {
|
if args.len() > 7 {
|
||||||
bail!(
|
bail!(
|
||||||
"output-delay-probe accepts at most five arguments\n{}",
|
"output-delay-probe accepts at most seven arguments\n{}",
|
||||||
usage()
|
usage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -195,12 +201,24 @@ fn parse_output_delay_probe_args(args: Vec<String>) -> Result<ParsedCommandArgs>
|
|||||||
.transpose()
|
.transpose()
|
||||||
.map(|value| value.unwrap_or(0))
|
.map(|value| value.unwrap_or(0))
|
||||||
};
|
};
|
||||||
|
let parse_i64 = |index: usize, name: &str| -> Result<i64> {
|
||||||
|
args.get(index)
|
||||||
|
.map(|value| {
|
||||||
|
value
|
||||||
|
.parse::<i64>()
|
||||||
|
.with_context(|| format!("parsing {name} `{value}`"))
|
||||||
|
})
|
||||||
|
.transpose()
|
||||||
|
.map(|value| value.unwrap_or(0))
|
||||||
|
};
|
||||||
Ok(ParsedCommandArgs {
|
Ok(ParsedCommandArgs {
|
||||||
probe_duration_seconds: parse_u32(0, "duration_s")?,
|
probe_duration_seconds: parse_u32(0, "duration_s")?,
|
||||||
probe_warmup_seconds: parse_u32(1, "warmup_s")?,
|
probe_warmup_seconds: parse_u32(1, "warmup_s")?,
|
||||||
probe_pulse_period_ms: parse_u32(2, "period_ms")?,
|
probe_pulse_period_ms: parse_u32(2, "period_ms")?,
|
||||||
probe_pulse_width_ms: parse_u32(3, "width_ms")?,
|
probe_pulse_width_ms: parse_u32(3, "width_ms")?,
|
||||||
probe_event_width_codes: args.get(4).cloned().unwrap_or_default(),
|
probe_event_width_codes: args.get(4).cloned().unwrap_or_default(),
|
||||||
|
probe_audio_delay_us: parse_i64(5, "audio_delay_us")?,
|
||||||
|
probe_video_delay_us: parse_i64(6, "video_delay_us")?,
|
||||||
..ParsedCommandArgs::default()
|
..ParsedCommandArgs::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -599,6 +617,8 @@ async fn main() -> Result<()> {
|
|||||||
pulse_period_ms: config.probe_pulse_period_ms,
|
pulse_period_ms: config.probe_pulse_period_ms,
|
||||||
pulse_width_ms: config.probe_pulse_width_ms,
|
pulse_width_ms: config.probe_pulse_width_ms,
|
||||||
event_width_codes: config.probe_event_width_codes.clone(),
|
event_width_codes: config.probe_event_width_codes.clone(),
|
||||||
|
audio_delay_us: config.probe_audio_delay_us,
|
||||||
|
video_delay_us: config.probe_video_delay_us,
|
||||||
};
|
};
|
||||||
let mut stream = client
|
let mut stream = client
|
||||||
.run_output_delay_probe(Request::new(request))
|
.run_output_delay_probe(Request::new(request))
|
||||||
@ -796,6 +816,8 @@ mod tests {
|
|||||||
"1000",
|
"1000",
|
||||||
"120",
|
"120",
|
||||||
"1,2,3,4",
|
"1,2,3,4",
|
||||||
|
"0",
|
||||||
|
"157712",
|
||||||
])
|
])
|
||||||
.expect("probe config");
|
.expect("probe config");
|
||||||
|
|
||||||
@ -805,6 +827,8 @@ mod tests {
|
|||||||
assert_eq!(config.probe_pulse_period_ms, 1000);
|
assert_eq!(config.probe_pulse_period_ms, 1000);
|
||||||
assert_eq!(config.probe_pulse_width_ms, 120);
|
assert_eq!(config.probe_pulse_width_ms, 120);
|
||||||
assert_eq!(config.probe_event_width_codes, "1,2,3,4");
|
assert_eq!(config.probe_event_width_codes, "1,2,3,4");
|
||||||
|
assert_eq!(config.probe_audio_delay_us, 0);
|
||||||
|
assert_eq!(config.probe_video_delay_us, 157_712);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -832,7 +856,20 @@ mod tests {
|
|||||||
assert!(parse_args_from(["status", "extra"]).is_err());
|
assert!(parse_args_from(["status", "extra"]).is_err());
|
||||||
assert!(parse_args_from(["calibrate"]).is_err());
|
assert!(parse_args_from(["calibrate"]).is_err());
|
||||||
assert!(parse_args_from(["calibrate", "0", "not-int"]).is_err());
|
assert!(parse_args_from(["calibrate", "0", "not-int"]).is_err());
|
||||||
assert!(parse_args_from(["output-delay-probe", "1", "2", "3", "4", "1", "extra"]).is_err());
|
assert!(
|
||||||
|
parse_args_from([
|
||||||
|
"output-delay-probe",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"1",
|
||||||
|
"0",
|
||||||
|
"0",
|
||||||
|
"extra"
|
||||||
|
])
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -938,6 +975,8 @@ mod tests {
|
|||||||
probe_pulse_period_ms: 0,
|
probe_pulse_period_ms: 0,
|
||||||
probe_pulse_width_ms: 0,
|
probe_pulse_width_ms: 0,
|
||||||
probe_event_width_codes: String::new(),
|
probe_event_width_codes: String::new(),
|
||||||
|
probe_audio_delay_us: 0,
|
||||||
|
probe_video_delay_us: 0,
|
||||||
};
|
};
|
||||||
let request = calibration_request_for(&config).expect("request");
|
let request = calibration_request_for(&config).expect("request");
|
||||||
assert_eq!(request.action, CalibrationAction::AdjustActive as i32);
|
assert_eq!(request.action, CalibrationAction::AdjustActive as i32);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.19.3"
|
version = "0.19.4"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
@ -71,6 +71,10 @@ message OutputDelayProbeRequest {
|
|||||||
uint32 pulse_period_ms = 3;
|
uint32 pulse_period_ms = 3;
|
||||||
uint32 pulse_width_ms = 4;
|
uint32 pulse_width_ms = 4;
|
||||||
string event_width_codes = 5;
|
string event_width_codes = 5;
|
||||||
|
// Probe-local output delays used to test whether server-side scheduling can
|
||||||
|
// compensate the raw UVC/UAC path. Positive values delay that stream.
|
||||||
|
int64 audio_delay_us = 6;
|
||||||
|
int64 video_delay_us = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OutputDelayProbeReply {
|
message OutputDelayProbeReply {
|
||||||
|
|||||||
@ -23,6 +23,8 @@ PROBE_TIMEOUT_SECONDS=${PROBE_TIMEOUT_SECONDS:-$((PROBE_DURATION_SECONDS + PROBE
|
|||||||
PROBE_PULSE_PERIOD_MS=${PROBE_PULSE_PERIOD_MS:-1000}
|
PROBE_PULSE_PERIOD_MS=${PROBE_PULSE_PERIOD_MS:-1000}
|
||||||
PROBE_PULSE_WIDTH_MS=${PROBE_PULSE_WIDTH_MS:-120}
|
PROBE_PULSE_WIDTH_MS=${PROBE_PULSE_WIDTH_MS:-120}
|
||||||
PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES:-1,2,1,3,2,4,1,1,3,1,4,2,1,2,3,4,1,3,2,2,4,1,2,4,3,1,1,4,2,3,1,2}
|
PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES:-1,2,1,3,2,4,1,1,3,1,4,2,1,2,3,4,1,3,2,2,4,1,2,4,3,1,1,4,2,3,1,2}
|
||||||
|
LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US=${LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US:-0}
|
||||||
|
LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US=${LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US:-0}
|
||||||
# Do not open the UVC host capture far ahead of the probe. The gadget side only
|
# Do not open the UVC host capture far ahead of the probe. The gadget side only
|
||||||
# has frames once the sync probe is feeding the server, and some hosts time out
|
# has frames once the sync probe is feeding the server, and some hosts time out
|
||||||
# VIDIOC_STREAMON if the camera is starved during pre-roll.
|
# VIDIOC_STREAMON if the camera is starved during pre-roll.
|
||||||
@ -1279,7 +1281,9 @@ set +e
|
|||||||
"${PROBE_WARMUP_SECONDS}" \
|
"${PROBE_WARMUP_SECONDS}" \
|
||||||
"${PROBE_PULSE_PERIOD_MS}" \
|
"${PROBE_PULSE_PERIOD_MS}" \
|
||||||
"${PROBE_PULSE_WIDTH_MS}" \
|
"${PROBE_PULSE_WIDTH_MS}" \
|
||||||
"${PROBE_EVENT_WIDTH_CODES}"
|
"${PROBE_EVENT_WIDTH_CODES}" \
|
||||||
|
"${LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US}" \
|
||||||
|
"${LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US}"
|
||||||
) 2>&1 | tee "${LOCAL_SERVER_PROBE_REPLY}"
|
) 2>&1 | tee "${LOCAL_SERVER_PROBE_REPLY}"
|
||||||
probe_status=${PIPESTATUS[0]}
|
probe_status=${PIPESTATUS[0]}
|
||||||
set -e
|
set -e
|
||||||
|
|||||||
@ -10,7 +10,7 @@ bench = false
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.19.3"
|
version = "0.19.4"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
||||||
|
|||||||
@ -62,6 +62,8 @@ struct ProbeConfig {
|
|||||||
pulse_period: Duration,
|
pulse_period: Duration,
|
||||||
pulse_width: Duration,
|
pulse_width: Duration,
|
||||||
event_width_codes: Vec<u32>,
|
event_width_codes: Vec<u32>,
|
||||||
|
audio_delay: Duration,
|
||||||
|
video_delay: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
@ -91,6 +93,8 @@ struct OutputDelayProbeTimeline {
|
|||||||
audio_sample_rate: u32,
|
audio_sample_rate: u32,
|
||||||
audio_channels: usize,
|
audio_channels: usize,
|
||||||
audio_chunk_ms: u64,
|
audio_chunk_ms: u64,
|
||||||
|
audio_delay_us: u64,
|
||||||
|
video_delay_us: u64,
|
||||||
pulse_period_ms: u64,
|
pulse_period_ms: u64,
|
||||||
pulse_width_ms: u64,
|
pulse_width_ms: u64,
|
||||||
warmup_us: u64,
|
warmup_us: u64,
|
||||||
@ -140,6 +144,8 @@ impl OutputDelayProbeTimeline {
|
|||||||
audio_sample_rate: AUDIO_SAMPLE_RATE,
|
audio_sample_rate: AUDIO_SAMPLE_RATE,
|
||||||
audio_channels: AUDIO_CHANNELS,
|
audio_channels: AUDIO_CHANNELS,
|
||||||
audio_chunk_ms: AUDIO_CHUNK_MS,
|
audio_chunk_ms: AUDIO_CHUNK_MS,
|
||||||
|
audio_delay_us: duration_us(config.audio_delay),
|
||||||
|
video_delay_us: duration_us(config.video_delay),
|
||||||
pulse_period_ms: config.pulse_period.as_millis() as u64,
|
pulse_period_ms: config.pulse_period.as_millis() as u64,
|
||||||
pulse_width_ms: config.pulse_width.as_millis() as u64,
|
pulse_width_ms: config.pulse_width.as_millis() as u64,
|
||||||
warmup_us: duration_us(config.warmup),
|
warmup_us: duration_us(config.warmup),
|
||||||
@ -215,6 +221,8 @@ impl ProbeConfig {
|
|||||||
pulse_period: Duration::from_millis(u64::from(pulse_period_ms)),
|
pulse_period: Duration::from_millis(u64::from(pulse_period_ms)),
|
||||||
pulse_width: Duration::from_millis(u64::from(pulse_width_ms)),
|
pulse_width: Duration::from_millis(u64::from(pulse_width_ms)),
|
||||||
event_width_codes,
|
event_width_codes,
|
||||||
|
audio_delay: positive_delay(request.audio_delay_us, "audio_delay_us")?,
|
||||||
|
video_delay: positive_delay(request.video_delay_us, "video_delay_us")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +278,13 @@ fn non_zero_or_default(value: u32, default: u32, name: &str) -> Result<u32> {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn positive_delay(value_us: i64, name: &str) -> Result<Duration> {
|
||||||
|
if value_us < 0 {
|
||||||
|
bail!("{name} must be zero or positive for the direct output-delay probe");
|
||||||
|
}
|
||||||
|
Ok(Duration::from_micros(value_us as u64))
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_event_width_codes(raw: &str) -> Result<Vec<u32>> {
|
fn parse_event_width_codes(raw: &str) -> Result<Vec<u32>> {
|
||||||
let trimmed = raw.trim();
|
let trimmed = raw.trim();
|
||||||
if trimmed.is_empty() {
|
if trimmed.is_empty() {
|
||||||
@ -330,13 +345,24 @@ pub async fn run_server_output_delay_probe(
|
|||||||
loop {
|
loop {
|
||||||
let next_frame_pts = duration_mul(frame_step, frame_index);
|
let next_frame_pts = duration_mul(frame_step, frame_index);
|
||||||
let next_audio_pts = duration_mul(audio_chunk, audio_index);
|
let next_audio_pts = duration_mul(audio_chunk, audio_index);
|
||||||
let next_pts = next_frame_pts.min(next_audio_pts);
|
let frame_active = next_frame_pts <= config.duration;
|
||||||
if next_pts > config.duration {
|
let audio_active = next_audio_pts <= config.duration;
|
||||||
|
if !frame_active && !audio_active {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tokio::time::sleep_until(start + next_pts).await;
|
let next_frame_due = if frame_active {
|
||||||
|
next_frame_pts.saturating_add(config.video_delay)
|
||||||
|
} else {
|
||||||
|
Duration::MAX
|
||||||
|
};
|
||||||
|
let next_audio_due = if audio_active {
|
||||||
|
next_audio_pts.saturating_add(config.audio_delay)
|
||||||
|
} else {
|
||||||
|
Duration::MAX
|
||||||
|
};
|
||||||
|
tokio::time::sleep_until(start + next_frame_due.min(next_audio_due)).await;
|
||||||
|
|
||||||
if next_audio_pts <= next_frame_pts && next_audio_pts <= config.duration {
|
if audio_active && next_audio_due <= next_frame_due {
|
||||||
let pts_us = duration_us(next_audio_pts);
|
let pts_us = duration_us(next_audio_pts);
|
||||||
let event_slot = config.event_slot_at(next_audio_pts);
|
let event_slot = config.event_slot_at(next_audio_pts);
|
||||||
let data = render_audio_chunk(&config, next_audio_pts, samples_per_chunk);
|
let data = render_audio_chunk(&config, next_audio_pts, samples_per_chunk);
|
||||||
@ -358,7 +384,7 @@ pub async fn run_server_output_delay_probe(
|
|||||||
audio_index = audio_index.saturating_add(1);
|
audio_index = audio_index.saturating_add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if next_frame_pts <= next_audio_pts && next_frame_pts <= config.duration {
|
if frame_active && next_frame_due <= next_audio_due {
|
||||||
let pts_us = duration_us(next_frame_pts);
|
let pts_us = duration_us(next_frame_pts);
|
||||||
let event_slot = config.event_slot_at(next_frame_pts);
|
let event_slot = config.event_slot_at(next_frame_pts);
|
||||||
let code = event_slot.map(|slot| slot.code);
|
let code = event_slot.map(|slot| slot.code);
|
||||||
@ -658,6 +684,8 @@ mod tests {
|
|||||||
pulse_period_ms: 1_000,
|
pulse_period_ms: 1_000,
|
||||||
pulse_width_ms: 120,
|
pulse_width_ms: 120,
|
||||||
event_width_codes: "3".to_string(),
|
event_width_codes: "3".to_string(),
|
||||||
|
audio_delay_us: 0,
|
||||||
|
video_delay_us: 0,
|
||||||
})
|
})
|
||||||
.expect("config");
|
.expect("config");
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,8 @@ fn upstream_sync_script_tunnels_auto_server_addr_through_ssh() {
|
|||||||
"LESAVKA_OUTPUT_DELAY_MAX_ABS_SKEW_MS=${LESAVKA_OUTPUT_DELAY_MAX_ABS_SKEW_MS:-5000}",
|
"LESAVKA_OUTPUT_DELAY_MAX_ABS_SKEW_MS=${LESAVKA_OUTPUT_DELAY_MAX_ABS_SKEW_MS:-5000}",
|
||||||
"LESAVKA_OUTPUT_DELAY_MAX_DRIFT_MS=${LESAVKA_OUTPUT_DELAY_MAX_DRIFT_MS:-80}",
|
"LESAVKA_OUTPUT_DELAY_MAX_DRIFT_MS=${LESAVKA_OUTPUT_DELAY_MAX_DRIFT_MS:-80}",
|
||||||
"LESAVKA_OUTPUT_DELAY_MAX_STEP_US=${LESAVKA_OUTPUT_DELAY_MAX_STEP_US:-1500000}",
|
"LESAVKA_OUTPUT_DELAY_MAX_STEP_US=${LESAVKA_OUTPUT_DELAY_MAX_STEP_US:-1500000}",
|
||||||
|
"LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US=${LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US:-0}",
|
||||||
|
"LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US=${LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US:-0}",
|
||||||
"write_output_delay_calibration",
|
"write_output_delay_calibration",
|
||||||
"extract_server_timeline",
|
"extract_server_timeline",
|
||||||
"write_output_delay_correlation",
|
"write_output_delay_correlation",
|
||||||
@ -64,6 +66,8 @@ fn upstream_sync_script_tunnels_auto_server_addr_through_ssh() {
|
|||||||
"probe_media_path\": \"server generated signatures -> UVC/UAC sinks -> lab host capture\"",
|
"probe_media_path\": \"server generated signatures -> UVC/UAC sinks -> lab host capture\"",
|
||||||
"audio_after_video_positive",
|
"audio_after_video_positive",
|
||||||
"PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES:-1,2,1,3",
|
"PROBE_EVENT_WIDTH_CODES=${PROBE_EVENT_WIDTH_CODES:-1,2,1,3",
|
||||||
|
"\"${LESAVKA_OUTPUT_DELAY_PROBE_AUDIO_DELAY_US}\"",
|
||||||
|
"\"${LESAVKA_OUTPUT_DELAY_PROBE_VIDEO_DELAY_US}\"",
|
||||||
"REMOTE_PULSE_CAPTURE_TOOL=${REMOTE_PULSE_CAPTURE_TOOL:-gst}",
|
"REMOTE_PULSE_CAPTURE_TOOL=${REMOTE_PULSE_CAPTURE_TOOL:-gst}",
|
||||||
"output_delay_calibration_json",
|
"output_delay_calibration_json",
|
||||||
"direct UVC/UAC output-delay calibration",
|
"direct UVC/UAC output-delay calibration",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user