fix(media): auto-enable HDMI mirror for detected connector

This commit is contained in:
Brad Stein 2026-07-19 05:08:24 -03:00
parent 432cb96164
commit 7011b5c3ef
7 changed files with 78 additions and 19 deletions

6
Cargo.lock generated
View File

@ -1658,7 +1658,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "lesavka_client"
version = "0.27.0"
version = "0.27.1"
dependencies = [
"anyhow",
"async-stream",
@ -1692,7 +1692,7 @@ dependencies = [
[[package]]
name = "lesavka_common"
version = "0.27.0"
version = "0.27.1"
dependencies = [
"anyhow",
"base64",
@ -1704,7 +1704,7 @@ dependencies = [
[[package]]
name = "lesavka_server"
version = "0.27.0"
version = "0.27.1"
dependencies = [
"anyhow",
"base64",

View File

@ -4,7 +4,7 @@ path = "src/main.rs"
[package]
name = "lesavka_client"
version = "0.27.0"
version = "0.27.1"
edition = "2024"
[dependencies]

View File

@ -1,6 +1,6 @@
[package]
name = "lesavka_common"
version = "0.27.0"
version = "0.27.1"
edition = "2024"
build = "build.rs"

View File

@ -1621,7 +1621,7 @@ SERVER_ENV_TMP=$(mktemp)
printf 'LESAVKA_HDMI_CONNECTOR=%s\n' "$HDMI_CONNECTOR"
fi
printf 'LESAVKA_CAM_OUTPUT=%s\n' "${LESAVKA_INSTALL_CAM_OUTPUT:-uvc}"
printf 'LESAVKA_CAM_HDMI_MIRROR=%s\n' "${LESAVKA_INSTALL_CAM_HDMI_MIRROR:-${LESAVKA_CAM_HDMI_MIRROR:-0}}"
printf 'LESAVKA_CAM_HDMI_MIRROR=%s\n' "${LESAVKA_INSTALL_CAM_HDMI_MIRROR:-${LESAVKA_CAM_HDMI_MIRROR:-auto}}"
printf 'LESAVKA_CAM_CODEC=%s\n' "${INSTALL_CAM_CODEC}"
printf 'LESAVKA_UPLINK_CAMERA_CODEC=%s\n' "${INSTALL_CAM_CODEC}"
if [[ -n "$INSTALL_HEVC_DECODER" ]]; then

View File

@ -16,7 +16,7 @@ bench = false
[package]
name = "lesavka_server"
version = "0.27.0"
version = "0.27.1"
edition = "2024"
autobins = false

View File

@ -249,8 +249,16 @@ pub fn camera_cfg_eq(a: &camera::CameraConfig, b: &camera::CameraConfig) -> bool
}
fn camera_relay_profile(cfg: &camera::CameraConfig) -> CameraRelayProfile {
let hdmi_mirror = (cfg.output == camera::CameraOutput::Uvc && hdmi_mirror_enabled())
.then(|| camera::hdmi_mirror_config(cfg));
let hdmi_mirror = (cfg.output == camera::CameraOutput::Uvc)
.then(|| match hdmi_mirror_setting() {
HdmiMirrorSetting::Enabled => Some(camera::hdmi_mirror_config(cfg)),
HdmiMirrorSetting::Auto if hdmi_mirror_connector_is_configured() => {
let mirror = camera::hdmi_mirror_config(cfg);
mirror.hdmi.is_some().then_some(mirror)
}
HdmiMirrorSetting::Auto | HdmiMirrorSetting::Disabled => None,
})
.flatten();
CameraRelayProfile {
primary: cfg.clone(),
hdmi_mirror,
@ -266,22 +274,33 @@ fn camera_relay_profile_eq(a: &CameraRelayProfile, b: &CameraRelayProfile) -> bo
}
}
fn hdmi_mirror_enabled() -> bool {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum HdmiMirrorSetting {
Disabled,
Enabled,
Auto,
}
fn hdmi_mirror_setting() -> HdmiMirrorSetting {
std::env::var("LESAVKA_CAM_HDMI_MIRROR")
.ok()
.map(|value| {
let trimmed = value.trim();
trimmed.eq_ignore_ascii_case("1")
|| trimmed.eq_ignore_ascii_case("true")
|| trimmed.eq_ignore_ascii_case("yes")
|| trimmed.eq_ignore_ascii_case("on")
.map(|value| match value.trim().to_ascii_lowercase().as_str() {
"1" | "true" | "yes" | "on" => HdmiMirrorSetting::Enabled,
"auto" => HdmiMirrorSetting::Auto,
_ => HdmiMirrorSetting::Disabled,
})
.unwrap_or(false)
.unwrap_or(HdmiMirrorSetting::Disabled)
}
fn hdmi_mirror_connector_is_configured() -> bool {
std::env::var("LESAVKA_HDMI_CONNECTOR")
.ok()
.is_some_and(|value| !value.trim().is_empty())
}
#[cfg(test)]
mod tests {
use super::{camera_cfg_eq, camera_relay_profile, camera_relay_profile_eq};
use super::{HdmiMirrorSetting, camera_cfg_eq, camera_relay_profile, camera_relay_profile_eq};
use crate::camera::{CameraCodec, CameraConfig, CameraOutput, HdmiConnector};
use serial_test::serial;
@ -342,6 +361,46 @@ mod tests {
});
}
#[test]
#[serial]
fn camera_relay_profile_auto_mirrors_only_when_hdmi_is_detected() {
let base = CameraConfig {
output: CameraOutput::Uvc,
codec: CameraCodec::Mjpeg,
width: 1280,
height: 720,
fps: 20,
hdmi: None,
};
temp_env::with_vars(
[
("LESAVKA_CAM_HDMI_MIRROR", Some("auto")),
("LESAVKA_HDMI_CONNECTOR", None::<&str>),
],
|| {
assert_eq!(super::hdmi_mirror_setting(), HdmiMirrorSetting::Auto);
assert!(camera_relay_profile(&base).hdmi_mirror.is_none());
},
);
temp_env::with_vars(
[
("LESAVKA_CAM_HDMI_MIRROR", Some("auto")),
("LESAVKA_HDMI_CONNECTOR", Some("card1-HDMI-A-1")),
],
|| {
let profile = camera_relay_profile(&base);
let mirror = profile
.hdmi_mirror
.as_ref()
.expect("auto HDMI mirror config");
assert_eq!(mirror.output, CameraOutput::Hdmi);
assert_eq!(mirror.hdmi.as_ref().unwrap().name, "card1-HDMI-A-1");
},
);
}
#[test]
#[serial]
fn camera_relay_profile_reuse_requires_same_mirror_connector() {

View File

@ -86,7 +86,7 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
assert!(SERVER_INSTALL.contains("${LESAVKA_INSTALL_CAM_OUTPUT:-uvc}"));
assert!(
SERVER_INSTALL
.contains("${LESAVKA_INSTALL_CAM_HDMI_MIRROR:-${LESAVKA_CAM_HDMI_MIRROR:-0}}")
.contains("${LESAVKA_INSTALL_CAM_HDMI_MIRROR:-${LESAVKA_CAM_HDMI_MIRROR:-auto}}")
);
assert!(SERVER_INSTALL.contains("normalize_cam_codec()"));
assert!(