diff --git a/server/src/video_support.rs b/server/src/video_support.rs index 6e8351a..53b3bf2 100644 --- a/server/src/video_support.rs +++ b/server/src/video_support.rs @@ -340,8 +340,9 @@ pub fn reserve_local_pts(counter: &AtomicU64, preferred_pts_us: u64, frame_step_ #[cfg(test)] mod tests { use super::{ - adjust_effective_fps, contains_hevc_irap, contains_idr, default_eye_fps, env_u32, - env_usize, next_local_pts, reserve_local_pts, should_send_frame, + SOFTWARE_VIDEO_FALLBACK_ENV, adjust_effective_fps, contains_hevc_irap, contains_idr, + default_eye_fps, env_u32, env_usize, is_hardware_h264_decoder, is_hardware_hevc_decoder, + next_local_pts, reserve_local_pts, should_send_frame, software_video_fallback_allowed, }; use serial_test::serial; use std::sync::atomic::AtomicU64; @@ -359,7 +360,9 @@ mod tests { fn contains_idr_finds_annex_b_keyframes() { let sample = [0, 0, 0, 1, 0x65, 0x88, 0x99]; assert!(contains_idr(&sample)); + assert!(contains_idr(&[0, 0, 1, 0x65, 0x88])); assert!(!contains_idr(&[0, 0, 0, 1, 0x41, 0x99])); + assert!(!contains_idr(&[0, 0, 2, 0x65, 0x88])); } #[test] @@ -381,6 +384,8 @@ mod tests { assert!(should_send_frame(0, 10, 25)); assert!(!should_send_frame(40_000, 50_000, 25)); assert!(should_send_frame(40_000, 90_000, 25)); + assert!(!should_send_frame(40_000, 40_001, 0)); + assert!(should_send_frame(40_000, 1_040_000, 0)); } #[test] @@ -415,6 +420,53 @@ mod tests { }); } + #[test] + #[serial] + fn software_video_fallback_requires_clear_operator_opt_in() { + for disabled in [ + None, + Some(""), + Some("0"), + Some("false"), + Some("no"), + Some("off"), + ] { + with_var(SOFTWARE_VIDEO_FALLBACK_ENV, disabled, || { + assert!(!software_video_fallback_allowed()); + }); + } + + for enabled in ["1", "true", "yes", "on", "lab"] { + with_var(SOFTWARE_VIDEO_FALLBACK_ENV, Some(enabled), || { + assert!(software_video_fallback_allowed()); + }); + } + } + + #[test] + fn hardware_decoder_classification_keeps_software_fallbacks_out() { + for name in [ + "v4l2h264dec", + "v4l2slh264dec", + "omxh264dec", + "vulkanh264dec", + ] { + assert!(is_hardware_h264_decoder(name)); + } + assert!(!is_hardware_h264_decoder("avdec_h264")); + + for name in [ + "v4l2slh265dec", + "v4l2h265dec", + "vulkanh265dec", + "nvh265dec", + "nvh265sldec", + ] { + assert!(is_hardware_hevc_decoder(name)); + } + assert!(!is_hardware_hevc_decoder("libde265dec")); + } + #[test] fn adjust_effective_fps_keeps_current_rate_when_no_samples() { assert_eq!(adjust_effective_fps(18, 12, 25, 0, 0), 18); diff --git a/tests/component/client/uplink/client_uplink_component_contract.rs b/tests/component/client/uplink/client_uplink_component_contract.rs index 921e3b7..bd1170f 100644 --- a/tests/component/client/uplink/client_uplink_component_contract.rs +++ b/tests/component/client/uplink/client_uplink_component_contract.rs @@ -23,6 +23,50 @@ const QUEUE_METADATA: &str = include_str!(concat!( "/client/src/app/uplink_media/uplink_queue_metadata.rs" )); +#[cfg(coverage)] +mod bundled_queue_runtime_knobs { + use std::time::Duration; + + include!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/client/src/app/uplink_media/bundled_media_queue.rs" + )); + + #[test] + fn bundled_audio_video_span_uses_default_when_unset_or_invalid() { + temp_env::with_var_unset("LESAVKA_BUNDLED_AUDIO_VIDEO_MAX_SPAN_MS", || { + assert_eq!( + bundled_audio_video_max_span(), + Duration::from_millis(DEFAULT_BUNDLED_AUDIO_VIDEO_MAX_SPAN_MS) + ); + }); + + for value in ["", "0", "-1", "not-a-number"] { + temp_env::with_var( + "LESAVKA_BUNDLED_AUDIO_VIDEO_MAX_SPAN_MS", + Some(value), + || { + assert_eq!( + bundled_audio_video_max_span(), + Duration::from_millis(DEFAULT_BUNDLED_AUDIO_VIDEO_MAX_SPAN_MS) + ); + }, + ); + } + } + + #[test] + fn bundled_audio_video_span_accepts_positive_operator_override() { + temp_env::with_var( + "LESAVKA_BUNDLED_AUDIO_VIDEO_MAX_SPAN_MS", + Some("125"), + || { + assert_eq!(bundled_audio_video_max_span(), Duration::from_millis(125)); + }, + ); + } +} + #[test] fn bundled_component_keeps_audio_video_and_hevc_recovery_on_the_same_path() { for marker in [