130 lines
4.2 KiB
Rust
130 lines
4.2 KiB
Rust
use super::{UpstreamMediaRuntime, play};
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn wait_for_audio_master_releases_video_once_audio_catches_up() {
|
|
let runtime = Arc::new(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
|
|
));
|
|
let _audio_first = play(runtime.plan_audio_pts(1_000_000));
|
|
let video_first = play(runtime.plan_video_pts(1_000_000, 16_666));
|
|
|
|
let waiter = tokio::spawn({
|
|
let runtime = runtime.clone();
|
|
async move {
|
|
runtime
|
|
.wait_for_audio_master(video_first.local_pts_us + 10_000, video_first.due_at)
|
|
.await
|
|
}
|
|
});
|
|
|
|
tokio::time::sleep(Duration::from_millis(5)).await;
|
|
let _audio_next = play(runtime.plan_audio_pts(1_010_000));
|
|
|
|
assert!(waiter.await.expect("audio master waiter should finish"));
|
|
}
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn wait_for_audio_master_times_out_when_audio_never_catches_up() {
|
|
let runtime = Arc::new(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
|
|
));
|
|
let _audio_first = play(runtime.plan_audio_pts(1_000_000));
|
|
let video_first = play(runtime.plan_video_pts(1_000_000, 16_666));
|
|
|
|
let due_at = tokio::time::Instant::now() + Duration::from_millis(20);
|
|
assert!(
|
|
!runtime
|
|
.wait_for_audio_master(video_first.local_pts_us + 100_000, due_at)
|
|
.await
|
|
);
|
|
}
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn wait_for_audio_master_returns_true_when_no_microphone_stream_is_active() {
|
|
let runtime = Arc::new(UpstreamMediaRuntime::new());
|
|
let camera = runtime.activate_camera();
|
|
let microphone = runtime.activate_microphone();
|
|
runtime.close_microphone(microphone.generation);
|
|
|
|
assert!(runtime.is_camera_active(camera.generation));
|
|
assert!(
|
|
runtime
|
|
.wait_for_audio_master(
|
|
123_456,
|
|
tokio::time::Instant::now() + Duration::from_millis(10)
|
|
)
|
|
.await
|
|
);
|
|
}
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn new_microphone_owner_waits_for_the_previous_sink_to_release() {
|
|
let runtime = Arc::new(UpstreamMediaRuntime::new());
|
|
let first = runtime.activate_microphone();
|
|
let first_permit = runtime
|
|
.reserve_microphone_sink(first.generation)
|
|
.await
|
|
.expect("first owner should acquire the sink gate");
|
|
let second = runtime.activate_microphone();
|
|
|
|
let waiter = tokio::spawn({
|
|
let runtime = runtime.clone();
|
|
async move {
|
|
runtime
|
|
.reserve_microphone_sink(second.generation)
|
|
.await
|
|
.is_some()
|
|
}
|
|
});
|
|
|
|
tokio::time::sleep(Duration::from_millis(25)).await;
|
|
assert!(!waiter.is_finished());
|
|
|
|
drop(first_permit);
|
|
assert!(waiter.await.expect("waiter task should finish"));
|
|
}
|
|
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn superseded_microphone_waiter_stands_down_before_opening_a_sink() {
|
|
let runtime = Arc::new(UpstreamMediaRuntime::new());
|
|
let first = runtime.activate_microphone();
|
|
let first_permit = runtime
|
|
.reserve_microphone_sink(first.generation)
|
|
.await
|
|
.expect("first owner should acquire the sink gate");
|
|
let second = runtime.activate_microphone();
|
|
|
|
let superseded_waiter = tokio::spawn({
|
|
let runtime = runtime.clone();
|
|
async move {
|
|
runtime
|
|
.reserve_microphone_sink(second.generation)
|
|
.await
|
|
.is_some()
|
|
}
|
|
});
|
|
|
|
tokio::time::sleep(Duration::from_millis(25)).await;
|
|
let _third = runtime.activate_microphone();
|
|
drop(first_permit);
|
|
|
|
assert!(
|
|
!superseded_waiter
|
|
.await
|
|
.expect("superseded waiter task should finish"),
|
|
"older waiter should stand down instead of opening a sink after supersession"
|
|
);
|
|
}
|