diff --git a/AGENTS.md b/AGENTS.md index 5e6c45a..61faec1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -655,3 +655,22 @@ Context: manual Tethys testing showed the desktop was awake and HDMI was on, but - [x] Add a first-frame watchdog for eye capture streams so opened-but-empty sources surface as explicit diagnostics. - [ ] Re-run a manual two-eye session and confirm right-eye failures now appear in the session log with the concrete source error. - [ ] If `eye-r` still reports `poll error ... EINVAL`, recover/reseat the right HDMI capture path or add a dedicated eye-capture soft recovery path separate from UVC/UAC. + +## 0.17.36 Call Media Stability Checklist + +Context: a manual Google Meet test on 0.17.34/0.17.35 was much worse than the earlier baseline: +remote audio sounded like choppy chunks/clicks and the video was visibly choppy. Live Theia +configuration showed the installer-generated UVC gadget was advertising `640x480 @ 20fps`, the +client camera pipeline was using that server profile as the outgoing packet profile even when the UI +selected `720p@30`, and the UAC speech path used a very tight 20ms/5ms sink buffer/latency with +downstream appsrc dropping. + +- [x] Treat probe/analyzer measurements as suspect until the copied Tethys capture is visually and audibly stable. +- [x] Make UI-selected camera quality king: the launcher camera profile now drives the outgoing uplink profile by default instead of being downscaled to stale server caps. +- [x] Keep an explicit `LESAVKA_CAM_LOCK_TO_SERVER_PROFILE=1` lab escape hatch for debugging the server UVC gadget contract. +- [x] Restore generated UVC gadget fallback defaults to `1280x720 @ 30fps` for sessions without an explicit UI/session profile. +- [x] Align runtime UVC fallback defaults with the generated 30fps gadget profile. +- [x] Raise UAC speech sink buffering and appsrc limits so speech favors intelligibility over bare-minimum latency under jitter. +- [x] Stop default downstream appsrc leaking on the UAC speech path; shredded chunks are worse than modest added latency for calls. +- [ ] Reinstall/restart Theia services so `/etc/lesavka/uvc.env` is refreshed from `640x480 @ 20fps` to `1280x720 @ 30fps`. +- [ ] Re-run manual Google Meet before trusting mirrored probe calibration; verify speech is intelligible and video cadence is stable by eye. diff --git a/Cargo.lock b/Cargo.lock index d459319..412d9a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lesavka_client" -version = "0.17.35" +version = "0.17.36" dependencies = [ "anyhow", "async-stream", @@ -1686,7 +1686,7 @@ dependencies = [ [[package]] name = "lesavka_common" -version = "0.17.35" +version = "0.17.36" dependencies = [ "anyhow", "base64", @@ -1698,7 +1698,7 @@ dependencies = [ [[package]] name = "lesavka_server" -version = "0.17.35" +version = "0.17.36" dependencies = [ "anyhow", "base64", diff --git a/client/Cargo.toml b/client/Cargo.toml index 36cbf0a..37d8b2b 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "lesavka_client" -version = "0.17.35" +version = "0.17.36" edition = "2024" [dependencies] diff --git a/client/src/app/session_lifecycle.rs b/client/src/app/session_lifecycle.rs index 15f02be..2cc89cb 100644 --- a/client/src/app/session_lifecycle.rs +++ b/client/src/app/session_lifecycle.rs @@ -237,7 +237,7 @@ impl LesavkaClientApp { width = cfg.width, height = cfg.height, fps = cfg.fps, - "📸 using camera settings from server" + "📸 using server camera caps as codec/fallback; launcher camera quality remains authoritative" ); } let ep = vid_ep.clone(); diff --git a/client/src/input/camera.rs b/client/src/input/camera.rs index efcc4db..adba9fd 100644 --- a/client/src/input/camera.rs +++ b/client/src/input/camera.rs @@ -82,7 +82,7 @@ mod tests { ("LESAVKA_CAM_WIDTH", Some("1280")), ("LESAVKA_CAM_HEIGHT", Some("720")), ("LESAVKA_CAM_FPS", Some("30")), - ("LESAVKA_CAM_ALLOW_PROFILE_OVERRIDE", None), + ("LESAVKA_CAM_LOCK_TO_SERVER_PROFILE", None), ], || assert_eq!(resolved_capture_profile(Some(cfg)), (1280, 720, 30)), ); @@ -90,8 +90,8 @@ mod tests { #[test] #[serial] - /// Guards the browser-facing UVC contract against launcher quality selection. - fn negotiated_output_profile_uses_server_uvc_contract_by_default() { + /// UI-selected launcher quality is the source of truth for the camera uplink. + fn negotiated_output_profile_follows_launcher_quality_by_default() { let cfg = CameraConfig { codec: CameraCodec::Mjpeg, width: 640, @@ -103,35 +103,7 @@ mod tests { ("LESAVKA_CAM_WIDTH", Some("1280")), ("LESAVKA_CAM_HEIGHT", Some("720")), ("LESAVKA_CAM_FPS", Some("30")), - ("LESAVKA_CAM_ALLOW_PROFILE_OVERRIDE", None), - ], - || { - let capture_profile = resolved_capture_profile(Some(cfg)); - assert_eq!(capture_profile, (1280, 720, 30)); - assert_eq!( - resolved_output_profile(Some(cfg), capture_profile), - (640, 480, 20) - ); - }, - ); - } - - #[test] - #[serial] - /// Keeps the explicit lab override available for controlled camera debugging. - fn explicit_profile_override_keeps_lab_mode_available() { - let cfg = CameraConfig { - codec: CameraCodec::Mjpeg, - width: 640, - height: 480, - fps: 20, - }; - temp_env::with_vars( - [ - ("LESAVKA_CAM_WIDTH", Some("1280")), - ("LESAVKA_CAM_HEIGHT", Some("720")), - ("LESAVKA_CAM_FPS", Some("30")), - ("LESAVKA_CAM_ALLOW_PROFILE_OVERRIDE", Some("1")), + ("LESAVKA_CAM_LOCK_TO_SERVER_PROFILE", None), ], || { let capture_profile = resolved_capture_profile(Some(cfg)); @@ -143,4 +115,32 @@ mod tests { }, ); } + + #[test] + #[serial] + /// Keeps the explicit lab lock available for controlled gadget debugging. + fn explicit_server_profile_lock_keeps_lab_mode_available() { + let cfg = CameraConfig { + codec: CameraCodec::Mjpeg, + width: 640, + height: 480, + fps: 20, + }; + temp_env::with_vars( + [ + ("LESAVKA_CAM_WIDTH", Some("1280")), + ("LESAVKA_CAM_HEIGHT", Some("720")), + ("LESAVKA_CAM_FPS", Some("30")), + ("LESAVKA_CAM_LOCK_TO_SERVER_PROFILE", Some("1")), + ], + || { + let capture_profile = resolved_capture_profile(Some(cfg)); + assert_eq!(capture_profile, (1280, 720, 30)); + assert_eq!( + resolved_output_profile(Some(cfg), capture_profile), + (640, 480, 20) + ); + }, + ); + } } diff --git a/client/src/input/camera/capture_pipeline.rs b/client/src/input/camera/capture_pipeline.rs index c7a932c..d96b725 100644 --- a/client/src/input/camera/capture_pipeline.rs +++ b/client/src/input/camera/capture_pipeline.rs @@ -291,7 +291,7 @@ fn resolved_output_profile( capture_profile: (u32, u32, u32), ) -> (u32, u32, u32) { match cfg { - Some(cfg) if !env_flag_enabled("LESAVKA_CAM_ALLOW_PROFILE_OVERRIDE") => { + Some(cfg) if env_flag_enabled("LESAVKA_CAM_LOCK_TO_SERVER_PROFILE") => { (cfg.width, cfg.height, cfg.fps.max(1)) } _ => capture_profile, diff --git a/common/Cargo.toml b/common/Cargo.toml index e6925c9..a1b3fe2 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lesavka_common" -version = "0.17.35" +version = "0.17.36" edition = "2024" build = "build.rs" diff --git a/scripts/daemon/lesavka-core.sh b/scripts/daemon/lesavka-core.sh index 18a66dc..b927053 100755 --- a/scripts/daemon/lesavka-core.sh +++ b/scripts/daemon/lesavka-core.sh @@ -162,7 +162,7 @@ UVC_MAXBURST=${LESAVKA_UVC_MAXBURST:-1} UVC_INTERVAL=${LESAVKA_UVC_INTERVAL:-} UVC_WIDTH=${LESAVKA_UVC_WIDTH:-1280} UVC_HEIGHT=${LESAVKA_UVC_HEIGHT:-720} -UVC_FPS=${LESAVKA_UVC_FPS:-25} +UVC_FPS=${LESAVKA_UVC_FPS:-30} UVC_DISABLE_IRQ=${LESAVKA_UVC_DISABLE_IRQ:-} UVC_BULK=${LESAVKA_UVC_BULK:-} UVC_CODEC=${LESAVKA_UVC_CODEC:-yuyv} diff --git a/scripts/install/server.sh b/scripts/install/server.sh index c2fb90e..0c2df7f 100755 --- a/scripts/install/server.sh +++ b/scripts/install/server.sh @@ -82,10 +82,10 @@ render_uvc_env_file() { LESAVKA_UVC_DEBUG=${LESAVKA_UVC_DEBUG:-1} LESAVKA_UVC_MAXPACKET=${LESAVKA_UVC_MAXPACKET:-1024} LESAVKA_UVC_LIMIT_PCT=${LESAVKA_UVC_LIMIT_PCT:-100} -LESAVKA_UVC_FPS=${LESAVKA_UVC_FPS:-20} -LESAVKA_UVC_INTERVAL=${LESAVKA_UVC_INTERVAL:-500000} -LESAVKA_UVC_WIDTH=${LESAVKA_UVC_WIDTH:-640} -LESAVKA_UVC_HEIGHT=${LESAVKA_UVC_HEIGHT:-480} +LESAVKA_UVC_FPS=${LESAVKA_UVC_FPS:-30} +LESAVKA_UVC_INTERVAL=${LESAVKA_UVC_INTERVAL:-333333} +LESAVKA_UVC_WIDTH=${LESAVKA_UVC_WIDTH:-1280} +LESAVKA_UVC_HEIGHT=${LESAVKA_UVC_HEIGHT:-720} LESAVKA_UVC_CODEC=${INSTALL_UVC_CODEC} LESAVKA_UVC_BLOCKING=${LESAVKA_UVC_BLOCKING:-1} LESAVKA_UVC_CONTROL_READ_ONLY=${LESAVKA_UVC_CONTROL_READ_ONLY:-0} diff --git a/server/Cargo.toml b/server/Cargo.toml index 950f843..a728539 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,7 @@ bench = false [package] name = "lesavka_server" -version = "0.17.35" +version = "0.17.36" edition = "2024" autobins = false diff --git a/server/src/audio/voice_input.rs b/server/src/audio/voice_input.rs index 8ac4267..01ca4a1 100644 --- a/server/src/audio/voice_input.rs +++ b/server/src/audio/voice_input.rs @@ -68,11 +68,11 @@ fn voice_input_caps() -> gst::Caps { } fn voice_sink_buffer_time_us() -> i64 { - positive_voice_sink_timing_env("LESAVKA_UAC_BUFFER_TIME_US", 20_000) + positive_voice_sink_timing_env("LESAVKA_UAC_BUFFER_TIME_US", 120_000) } fn voice_sink_latency_time_us() -> i64 { - positive_voice_sink_timing_env("LESAVKA_UAC_LATENCY_TIME_US", 5_000) + positive_voice_sink_timing_env("LESAVKA_UAC_LATENCY_TIME_US", 40_000) } fn voice_sink_compensation_us() -> i64 { @@ -129,15 +129,15 @@ fn voice_sink_delay_queue_enabled(compensation_us: i64) -> bool { } fn voice_appsrc_max_buffers() -> u64 { - positive_voice_appsrc_limit_env("LESAVKA_UAC_APP_MAX_BUFFERS", 8) + positive_voice_appsrc_limit_env("LESAVKA_UAC_APP_MAX_BUFFERS", 16) } fn voice_appsrc_max_bytes() -> u64 { - positive_voice_appsrc_limit_env("LESAVKA_UAC_APP_MAX_BYTES", 32_768) + positive_voice_appsrc_limit_env("LESAVKA_UAC_APP_MAX_BYTES", 65_536) } fn voice_appsrc_max_time_ns() -> u64 { - positive_voice_appsrc_limit_env("LESAVKA_UAC_APP_MAX_TIME_NS", 80_000_000) + positive_voice_appsrc_limit_env("LESAVKA_UAC_APP_MAX_TIME_NS", 200_000_000) } fn positive_voice_appsrc_limit_env(name: &str, default: u64) -> u64 { @@ -163,7 +163,7 @@ fn configure_voice_appsrc(appsrc: &gst_app::AppSrc) { appsrc.set_property("max-time", voice_appsrc_max_time_ns()); } if appsrc.has_property("leaky-type", None) { - appsrc.set_property_from_str("leaky-type", "downstream"); + appsrc.set_property_from_str("leaky-type", "none"); } } @@ -282,7 +282,7 @@ impl Voice { compensation_us, delay_queue_enabled, clock_align_enabled, - "🎤 UAC sink low-latency timing armed" + "🎤 UAC sink call-stability timing armed" ); if clock_align_enabled { crate::media_timing::prepare_pipeline_clock_sync(&pipeline); @@ -407,8 +407,8 @@ mod voice_sink_timing_tests { temp_env::with_var_unset("LESAVKA_UAC_HDMI_COMPENSATION_US", || { temp_env::with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || { update_camera_config(); - assert_eq!(voice_sink_buffer_time_us(), 20_000); - assert_eq!(voice_sink_latency_time_us(), 5_000); + assert_eq!(voice_sink_buffer_time_us(), 120_000); + assert_eq!(voice_sink_latency_time_us(), 40_000); assert_eq!(voice_sink_compensation_us(), 0); }); }); @@ -418,13 +418,13 @@ mod voice_sink_timing_tests { } #[test] - fn voice_appsrc_limits_default_to_a_short_freshness_window() { + fn voice_appsrc_limits_default_to_a_call_stability_window() { temp_env::with_var_unset("LESAVKA_UAC_APP_MAX_BUFFERS", || { temp_env::with_var_unset("LESAVKA_UAC_APP_MAX_BYTES", || { temp_env::with_var_unset("LESAVKA_UAC_APP_MAX_TIME_NS", || { - assert_eq!(voice_appsrc_max_buffers(), 8); - assert_eq!(voice_appsrc_max_bytes(), 32_768); - assert_eq!(voice_appsrc_max_time_ns(), 80_000_000); + assert_eq!(voice_appsrc_max_buffers(), 16); + assert_eq!(voice_appsrc_max_bytes(), 65_536); + assert_eq!(voice_appsrc_max_time_ns(), 200_000_000); }); }); }); @@ -445,9 +445,9 @@ mod voice_sink_timing_tests { temp_env::with_var("LESAVKA_UAC_APP_MAX_BUFFERS", Some("0"), || { temp_env::with_var("LESAVKA_UAC_APP_MAX_BYTES", Some("nope"), || { temp_env::with_var("LESAVKA_UAC_APP_MAX_TIME_NS", Some("0"), || { - assert_eq!(voice_appsrc_max_buffers(), 8); - assert_eq!(voice_appsrc_max_bytes(), 32_768); - assert_eq!(voice_appsrc_max_time_ns(), 80_000_000); + assert_eq!(voice_appsrc_max_buffers(), 16); + assert_eq!(voice_appsrc_max_bytes(), 65_536); + assert_eq!(voice_appsrc_max_time_ns(), 200_000_000); }); }); }); @@ -471,8 +471,8 @@ mod voice_sink_timing_tests { temp_env::with_var("LESAVKA_UAC_BUFFER_TIME_US", Some("0"), || { temp_env::with_var("LESAVKA_UAC_LATENCY_TIME_US", Some("-5"), || { temp_env::with_var("LESAVKA_UAC_COMPENSATION_US", Some("166667"), || { - assert_eq!(voice_sink_buffer_time_us(), 20_000); - assert_eq!(voice_sink_latency_time_us(), 5_000); + assert_eq!(voice_sink_buffer_time_us(), 120_000); + assert_eq!(voice_sink_latency_time_us(), 40_000); assert_eq!(voice_sink_compensation_us(), 166_667); }); }); @@ -484,8 +484,8 @@ mod voice_sink_timing_tests { temp_env::with_var("LESAVKA_UAC_COMPENSATION_US", Some("-5"), || { temp_env::with_var("LESAVKA_UAC_BUFFER_TIME_US", Some("0"), || { temp_env::with_var("LESAVKA_UAC_LATENCY_TIME_US", Some("-5"), || { - assert_eq!(voice_sink_buffer_time_us(), 20_000); - assert_eq!(voice_sink_latency_time_us(), 5_000); + assert_eq!(voice_sink_buffer_time_us(), 120_000); + assert_eq!(voice_sink_latency_time_us(), 40_000); assert_eq!(voice_sink_compensation_us(), 0); }); }); diff --git a/server/src/bin/lesavka-uvc.real.inc b/server/src/bin/lesavka-uvc.real.inc index e7fa56d..2fe31e5 100644 --- a/server/src/bin/lesavka-uvc.real.inc +++ b/server/src/bin/lesavka-uvc.real.inc @@ -670,7 +670,7 @@ impl UvcConfig { fn from_env() -> Self { let width = env_u32("LESAVKA_UVC_WIDTH", 1280); let height = env_u32("LESAVKA_UVC_HEIGHT", 720); - let fps = env_u32("LESAVKA_UVC_FPS", 25).max(1); + let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1); let interval = env_u32("LESAVKA_UVC_INTERVAL", 0); let mut max_packet = env_u32("LESAVKA_UVC_MAXPACKET", 1024); let frame_size = env_u32("LESAVKA_UVC_FRAME_SIZE", width * height * 2); diff --git a/server/src/bin/lesavka_uvc/coverage_startup.rs b/server/src/bin/lesavka_uvc/coverage_startup.rs index 0fe26e7..f4fed20 100644 --- a/server/src/bin/lesavka_uvc/coverage_startup.rs +++ b/server/src/bin/lesavka_uvc/coverage_startup.rs @@ -37,7 +37,7 @@ impl UvcConfig { fn from_env() -> Self { let width = env_u32("LESAVKA_UVC_WIDTH", 1280); let height = env_u32("LESAVKA_UVC_HEIGHT", 720); - let fps = env_u32("LESAVKA_UVC_FPS", 25).max(1); + let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1); let frame_size = env_u32("LESAVKA_UVC_FRAME_SIZE", width * height * 2); let interval = env_u32("LESAVKA_UVC_INTERVAL", 0); let bulk = env::var("LESAVKA_UVC_BULK").is_ok(); diff --git a/server/src/camera/selection.rs b/server/src/camera/selection.rs index 8430b0c..b92cbbb 100644 --- a/server/src/camera/selection.rs +++ b/server/src/camera/selection.rs @@ -152,7 +152,7 @@ fn select_uvc_config() -> CameraConfig { } }) }) - .unwrap_or(25); + .unwrap_or(30); let codec = select_uvc_codec(None); CameraConfig { @@ -191,7 +191,7 @@ fn select_uvc_config() -> CameraConfig { } }) }) - .unwrap_or(25); + .unwrap_or(30); let codec = select_uvc_codec(Some(&uvc_env)); CameraConfig { diff --git a/server/src/uvc_control/model.rs b/server/src/uvc_control/model.rs index 7382bc5..d3307be 100644 --- a/server/src/uvc_control/model.rs +++ b/server/src/uvc_control/model.rs @@ -130,7 +130,7 @@ impl UvcConfig { pub(crate) fn from_env() -> Self { let width = env_u32("LESAVKA_UVC_WIDTH", 1280); let height = env_u32("LESAVKA_UVC_HEIGHT", 720); - let fps = env_u32("LESAVKA_UVC_FPS", 25).max(1); + let fps = env_u32("LESAVKA_UVC_FPS", 30).max(1); let interval = env_u32("LESAVKA_UVC_INTERVAL", 0); let mut max_packet = env_u32("LESAVKA_UVC_MAXPACKET", 1024); let frame_size = env_u32("LESAVKA_UVC_FRAME_SIZE", width * height * 2); diff --git a/testing/tests/client_launcher_runtime_contract.rs b/testing/tests/client_launcher_runtime_contract.rs index 750ef57..6a232b1 100644 --- a/testing/tests/client_launcher_runtime_contract.rs +++ b/testing/tests/client_launcher_runtime_contract.rs @@ -106,10 +106,10 @@ fn relay_address_locks_but_media_staging_stays_available_while_relay_is_live() { ) ); assert!(UI_RUNTIME_SRC.contains("Soft-pause or resume this feed in the running relay")); - assert!(UI_SRC.contains("Camera selection staged for the next relay launch")); - assert!(UI_SRC.contains("Camera quality staged for the next relay launch")); - assert!(UI_SRC.contains("Microphone selection staged for the next relay launch")); - assert!(UI_SRC.contains("Speaker selection staged for the next relay launch")); + assert!(UI_SRC.contains("{feed_label} selection is staged for the next relay launch")); + assert!(UI_SRC.contains("Camera quality")); + assert!(UI_SRC.contains("Microphone")); + assert!(UI_SRC.contains("Speaker")); assert!(UI_RUNTIME_SRC.contains("\"Connect\"")); assert!(UI_RUNTIME_SRC.contains("\"Disconnect\"")); } @@ -170,7 +170,7 @@ fn launcher_webcam_quality_selection_reaches_preview_and_relay_env() { assert!(DEVICE_TEST_SRC.contains("build_camera_preview_pipeline(&device, mode)")); assert!(DEVICE_TEST_SRC.contains("capsfilter caps=\\\"video/x-raw")); assert!(CAMERA_SRC.contains("fn resolved_capture_profile")); - assert!(CAMERA_SRC.contains("LESAVKA_CAM_ALLOW_PROFILE_OVERRIDE")); + assert!(CAMERA_SRC.contains("LESAVKA_CAM_LOCK_TO_SERVER_PROFILE")); assert!(LAUNCHER_MOD_SRC.contains("\"LESAVKA_CAM_WIDTH\"")); assert!(LAUNCHER_MOD_SRC.contains("\"LESAVKA_CAM_H264_KBIT\"")); } diff --git a/testing/tests/server_camera_contract.rs b/testing/tests/server_camera_contract.rs index 1e3286c..e9a8818 100644 --- a/testing/tests/server_camera_contract.rs +++ b/testing/tests/server_camera_contract.rs @@ -65,7 +65,7 @@ fn camera_config_zero_interval_falls_back_to_default_fps() { assert_eq!(cfg.codec, CameraCodec::Mjpeg); assert_eq!(cfg.width, 800); assert_eq!(cfg.height, 600); - assert_eq!(cfg.fps, 25); + assert_eq!(cfg.fps, 30); }); }); }); @@ -169,7 +169,7 @@ fn camera_config_defaults_when_uvc_dimensions_and_rate_are_missing() { assert_eq!(cfg.codec, CameraCodec::Mjpeg); assert_eq!(cfg.width, 1280); assert_eq!(cfg.height, 720); - assert_eq!(cfg.fps, 25); + assert_eq!(cfg.fps, 30); }); }); }); diff --git a/testing/tests/server_install_script_contract.rs b/testing/tests/server_install_script_contract.rs index 50e8d79..731053a 100644 --- a/testing/tests/server_install_script_contract.rs +++ b/testing/tests/server_install_script_contract.rs @@ -93,9 +93,9 @@ fn server_install_pins_hdmi_camera_and_display_defaults() { assert!(SERVER_INSTALL.contains("${LESAVKA_UPSTREAM_STALE_DROP_MS:-80}")); assert!(SERVER_INSTALL.contains("${LESAVKA_INSTALL_SERVER_BIND_ADDR:-0.0.0.0:50051}")); assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_MAXPACKET:-1024}")); - assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_INTERVAL:-500000}")); - assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_WIDTH:-640}")); - assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_HEIGHT:-480}")); + assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_INTERVAL:-333333}")); + assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_WIDTH:-1280}")); + assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_HEIGHT:-720}")); assert!(SERVER_INSTALL.contains("${LESAVKA_UVC_CONTROL_READ_ONLY:-0}")); assert!( !SERVER_INSTALL.contains("LESAVKA_UVC_CODEC=${LESAVKA_UVC_CODEC:-mjpeg}"),