fix(sync): refresh playout budget after pairing
This commit is contained in:
parent
a35c1bb1d4
commit
71b44521ef
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1676,7 +1676,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@ -1688,7 +1688,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ bench = false
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
||||||
|
|||||||
@ -326,6 +326,7 @@ impl UpstreamMediaRuntime {
|
|||||||
let pairing_deadline = *state
|
let pairing_deadline = *state
|
||||||
.pairing_anchor_deadline
|
.pairing_anchor_deadline
|
||||||
.get_or_insert_with(|| now + upstream_playout_delay());
|
.get_or_insert_with(|| now + upstream_playout_delay());
|
||||||
|
let playout_delay = upstream_playout_delay();
|
||||||
|
|
||||||
if state.session_base_remote_pts_us.is_none() {
|
if state.session_base_remote_pts_us.is_none() {
|
||||||
if state.first_camera_remote_pts_us.is_some()
|
if state.first_camera_remote_pts_us.is_some()
|
||||||
@ -337,7 +338,9 @@ impl UpstreamMediaRuntime {
|
|||||||
state.first_microphone_remote_pts_us.unwrap_or_default();
|
state.first_microphone_remote_pts_us.unwrap_or_default();
|
||||||
state.session_base_remote_pts_us =
|
state.session_base_remote_pts_us =
|
||||||
Some(first_camera_remote_pts_us.max(first_microphone_remote_pts_us));
|
Some(first_camera_remote_pts_us.max(first_microphone_remote_pts_us));
|
||||||
state.playout_epoch = Some(pairing_deadline);
|
let overlap_epoch = now + playout_delay;
|
||||||
|
state.playout_epoch = Some(overlap_epoch);
|
||||||
|
state.pairing_anchor_deadline = Some(overlap_epoch);
|
||||||
if !state.startup_anchor_logged {
|
if !state.startup_anchor_logged {
|
||||||
let startup_delta_us =
|
let startup_delta_us =
|
||||||
first_camera_remote_pts_us as i128 - first_microphone_remote_pts_us as i128;
|
first_camera_remote_pts_us as i128 - first_microphone_remote_pts_us as i128;
|
||||||
@ -377,7 +380,9 @@ impl UpstreamMediaRuntime {
|
|||||||
.unwrap_or(remote_pts_us),
|
.unwrap_or(remote_pts_us),
|
||||||
};
|
};
|
||||||
state.session_base_remote_pts_us = Some(single_stream_base_remote_pts_us);
|
state.session_base_remote_pts_us = Some(single_stream_base_remote_pts_us);
|
||||||
state.playout_epoch = Some(pairing_deadline);
|
let one_sided_epoch = now + playout_delay;
|
||||||
|
state.playout_epoch = Some(one_sided_epoch);
|
||||||
|
state.pairing_anchor_deadline = Some(one_sided_epoch);
|
||||||
info!(
|
info!(
|
||||||
session_id,
|
session_id,
|
||||||
?kind,
|
?kind,
|
||||||
|
|||||||
@ -339,6 +339,34 @@ fn catastrophic_lateness_reanchors_the_shared_playout_epoch() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn overlap_anchor_gets_a_fresh_playout_budget_when_pairing_finishes_late() {
|
||||||
|
temp_env::with_var("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS", Some("20"), || {
|
||||||
|
let runtime = UpstreamMediaRuntime::new();
|
||||||
|
let _camera = runtime.activate_camera();
|
||||||
|
let _microphone = runtime.activate_microphone();
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
runtime.plan_video_pts(1_000_000, 16_666),
|
||||||
|
super::UpstreamPlanDecision::AwaitingPair
|
||||||
|
));
|
||||||
|
|
||||||
|
std::thread::sleep(Duration::from_millis(15));
|
||||||
|
let before_pair = tokio::time::Instant::now();
|
||||||
|
let audio_first = play(runtime.plan_audio_pts(1_000_000));
|
||||||
|
let video_first = play(runtime.plan_video_pts(1_000_000, 16_666));
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
audio_first.due_at.saturating_duration_since(before_pair) >= Duration::from_millis(15),
|
||||||
|
"audio should keep most of the configured playout budget after late pairing"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
video_first.due_at.saturating_duration_since(before_pair) >= Duration::from_millis(15),
|
||||||
|
"video should keep most of the configured playout budget after late pairing"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn catastrophic_lateness_reanchors_only_once_per_session() {
|
fn catastrophic_lateness_reanchors_only_once_per_session() {
|
||||||
temp_env::with_var("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS", Some("20"), || {
|
temp_env::with_var("LESAVKA_UPSTREAM_PLAYOUT_DELAY_MS", Some("20"), || {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user