From 0168fcbdbdc7ea841ebbcffa1d4afe6cb7f48431 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 19 Nov 2025 11:08:32 +0200 Subject: [PATCH] Make config.EdidString the single source of truth for EDID - Set DefaultEDID in config defaults instead of empty string - Pass config EDID to Native.Start() to fix initialization race condition - Update DefaultEDID to MacBook-compatible value (2ch, 48kHz, 16/20/24-bit) - Add getDefaultEDID RPC endpoint for UI to fetch backend constant - Update UI to dynamically fetch default EDID instead of hardcoding - Remove all EDID fallback logic now that config always has a value - Simplify rpcGetEDID to return config value directly This ensures the configured EDID is used from startup and eliminates sync issues between backend constant, config, and UI. --- config.go | 2 + internal/native/native.go | 7 ++- internal/native/video.go | 8 +-- jsonrpc.go | 14 ++--- native.go | 7 +-- ui/src/hooks/useJsonRpc.ts | 1 + ui/src/routes/devices.$id.settings.video.tsx | 54 ++++++++++++-------- 7 files changed, 48 insertions(+), 45 deletions(-) diff --git a/config.go b/config.go index 2deee268..37e8906a 100644 --- a/config.go +++ b/config.go @@ -9,6 +9,7 @@ import ( "github.com/jetkvm/kvm/internal/confparser" "github.com/jetkvm/kvm/internal/logging" + "github.com/jetkvm/kvm/internal/native" "github.com/jetkvm/kvm/internal/network/types" "github.com/jetkvm/kvm/internal/usbgadget" "github.com/prometheus/client_golang/prometheus" @@ -174,6 +175,7 @@ func getDefaultConfig() Config { KeyboardMacros: []KeyboardMacro{}, DisplayRotation: "270", KeyboardLayout: "en-US", + EdidString: native.DefaultEDID, DisplayMaxBrightness: 64, DisplayDimAfterSec: 120, // 2 minutes DisplayOffAfterSec: 1800, // 30 minutes diff --git a/internal/native/native.go b/internal/native/native.go index 458c8df6..0d21083b 100644 --- a/internal/native/native.go +++ b/internal/native/native.go @@ -94,7 +94,7 @@ func NewNative(opts NativeOptions) *Native { } } -func (n *Native) Start() { +func (n *Native) Start(initialEDID string) { if n.disable { nativeLogger.Warn().Msg("native is disabled, skipping initialization") setCgoDisabled(true) @@ -105,9 +105,8 @@ func (n *Native) Start() { setInstance(n) setUpNativeHandlers() - // set EDID before video init so source sees audio capabilities immediately - if err := videoSetEDID(DefaultEDID); err != nil { - n.l.Warn().Err(err).Msg("failed to set default EDID before video init") + if err := videoSetEDID(initialEDID); err != nil { + n.l.Warn().Err(err).Msg("failed to set EDID before video init") } // start the native video diff --git a/internal/native/video.go b/internal/native/video.go index 30790f68..cabf2231 100644 --- a/internal/native/video.go +++ b/internal/native/video.go @@ -8,9 +8,7 @@ import ( const sleepModeFile = "/sys/devices/platform/ff470000.i2c/i2c-4/4-000f/sleep_mode" -// DefaultEDID is the default EDID (identifies as "JetKVM HDMI" with full TC358743 audio/video capabilities). -// Updated with 24-inch display dimensions (52x32cm) and Dell manufacturer ID for compatibility. -const DefaultEDID = "00ffffffffffff0010ac01000100000001230104803420782ec9a05747982712484c00000000d1c081c0a9c0b3000101010101010101083a801871382d40582c450000000000001e011d007251d01e206e28550000000000001e000000fc004a65746b564d2048444d490a20000000fd00187801ff1d000a202020202020016602032e7229097f070d07070f0707509005040302011f132220111214061507831f000068030c0010003021e2050700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047" +const DefaultEDID = "00ffffffffffff0010ac01000100000001230104803420782ec9a05747982712484c00000000d1c081c0a9c0b3000101010101010101083a801871382d40582c450000000000001e011d007251d01e206e28550000000000001e000000fc004a65746b564d2048444d490a20000000fd00187801ff1d000a20202020202001660203287223090407509005040302011f1322201112140615078301000068030c0010003021e20507000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c800000000005c" var extraLockTimeout = 5 * time.Second @@ -115,10 +113,6 @@ func (n *Native) VideoSetEDID(edid string) error { n.videoLock.Lock() defer n.videoLock.Unlock() - if edid == "" { - edid = DefaultEDID - } - return n.useExtraLock(func() error { return videoSetEDID(edid) }) diff --git a/jsonrpc.go b/jsonrpc.go index bbbb65e5..6c03916c 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -19,6 +19,7 @@ import ( "go.bug.st/serial" "github.com/jetkvm/kvm/internal/hidrpc" + "github.com/jetkvm/kvm/internal/native" "github.com/jetkvm/kvm/internal/usbgadget" "github.com/jetkvm/kvm/internal/utils" ) @@ -208,15 +209,16 @@ func rpcSetAutoUpdateState(enabled bool) (bool, error) { } func rpcGetEDID() (string, error) { - resp, err := nativeInstance.VideoGetEDID() - if err != nil { - return "", err - } - return resp, nil + return config.EdidString, nil +} + +func rpcGetDefaultEDID() (string, error) { + return native.DefaultEDID, nil } func rpcSetEDID(edid string) error { if edid == "" { + edid = native.DefaultEDID logger.Info().Msg("Restoring EDID to default") } else { logger.Info().Str("edid", edid).Msg("Setting EDID") @@ -226,7 +228,6 @@ func rpcSetEDID(edid string) error { return err } - // Save EDID to config, allowing it to be restored on reboot. config.EdidString = edid _ = SaveConfig() return nil @@ -1370,6 +1371,7 @@ var rpcHandlers = map[string]RPCHandler{ "getAutoUpdateState": {Func: rpcGetAutoUpdateState}, "setAutoUpdateState": {Func: rpcSetAutoUpdateState, Params: []string{"enabled"}}, "getEDID": {Func: rpcGetEDID}, + "getDefaultEDID": {Func: rpcGetDefaultEDID}, "setEDID": {Func: rpcSetEDID, Params: []string{"edid"}}, "getVideoLogStatus": {Func: rpcGetVideoLogStatus}, "getVideoSleepMode": {Func: rpcGetVideoSleepMode}, diff --git a/native.go b/native.go index 81a0e50d..0eb01bf3 100644 --- a/native.go +++ b/native.go @@ -64,12 +64,7 @@ func initNative(systemVersion *semver.Version, appVersion *semver.Version) { }, }) - nativeInstance.Start() - go func() { - if err := nativeInstance.VideoSetEDID(config.EdidString); err != nil { - nativeLogger.Warn().Err(err).Msg("error setting EDID") - } - }() + nativeInstance.Start(config.EdidString) if os.Getenv("JETKVM_CRASH_TESTING") == "1" { nativeInstance.DoNotUseThisIsForCrashTestingOnly() diff --git a/ui/src/hooks/useJsonRpc.ts b/ui/src/hooks/useJsonRpc.ts index e01dcbc7..0d7e6763 100644 --- a/ui/src/hooks/useJsonRpc.ts +++ b/ui/src/hooks/useJsonRpc.ts @@ -39,6 +39,7 @@ const blockedMethodsByReason: Record = { video: [ 'setStreamQualityFactor', 'getEDID', + 'getDefaultEDID', 'setEDID', 'getVideoLogStatus', 'setDisplayRotation', diff --git a/ui/src/routes/devices.$id.settings.video.tsx b/ui/src/routes/devices.$id.settings.video.tsx index a2834c05..f8ab52e5 100644 --- a/ui/src/routes/devices.$id.settings.video.tsx +++ b/ui/src/routes/devices.$id.settings.video.tsx @@ -11,13 +11,7 @@ import Fieldset from "@components/Fieldset"; import notifications from "@/notifications"; import { m } from "@localizations/messages.js"; -const defaultEdid = - "00ffffffffffff0010ac01000100000001230104803420782ec9a05747982712484c00000000d1c081c0a9c0b3000101010101010101083a801871382d40582c450000000000001e011d007251d01e206e28550000000000001e000000fc004a65746b564d2048444d490a20000000fd00187801ff1d000a202020202020016602032e7229097f070d07070f0707509005040302011f132220111214061507831f000068030c0010003021e2050700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047"; -const edids = [ - { - value: defaultEdid, - label: m.video_edid_jetkvm_default(), - }, +const otherEdids = [ { value: "00FFFFFFFFFFFF00047265058A3F6101101E0104A53420783FC125A8554EA0260D5054BFEF80714F8140818081C081008B009500B300283C80A070B023403020360006442100001A000000FD00304C575716010A202020202020000000FC0042323436574C0A202020202020000000FF0054384E4545303033383532320A01F802031CF14F90020304050607011112131415161F2309070783010000011D8018711C1620582C250006442100009E011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E9600064421000018C344806E70B028401720A80406442100001E00000000000000000000000000000000000000000000000000000096", @@ -52,6 +46,8 @@ export default function SettingsVideoRoute() { const [customEdidValue, setCustomEdidValue] = useState(null); const [edid, setEdid] = useState(null); const [edidLoading, setEdidLoading] = useState(true); + const [defaultEdid, setDefaultEdid] = useState(""); + const [edids, setEdids] = useState>([]); const { debugMode } = useSettingsStore(); // Video enhancement settings from store const { @@ -69,28 +65,42 @@ export default function SettingsVideoRoute() { setStreamQuality(String(resp.result)); }); - send("getEDID", {}, (resp: JsonRpcResponse) => { - setEdidLoading(false); + send("getDefaultEDID", {}, (resp: JsonRpcResponse) => { if ("error" in resp) { notifications.error(m.video_failed_get_edid({ error: resp.error.data || m.unknown_error() })); return; } - const receivedEdid = resp.result as string; + const fetchedDefaultEdid = resp.result as string; + setDefaultEdid(fetchedDefaultEdid); - const matchingEdid = edids.find( - x => x.value.toLowerCase() === receivedEdid.toLowerCase(), - ); + const allEdids = [ + { value: fetchedDefaultEdid, label: m.video_edid_jetkvm_default() }, + ...otherEdids + ]; + setEdids(allEdids); - if (matchingEdid) { - // EDID is stored in uppercase in the UI - setEdid(matchingEdid.value.toUpperCase()); - // Reset custom EDID value - setCustomEdidValue(null); - } else { - setEdid("custom"); - setCustomEdidValue(receivedEdid); - } + send("getEDID", {}, (resp: JsonRpcResponse) => { + setEdidLoading(false); + if ("error" in resp) { + notifications.error(m.video_failed_get_edid({ error: resp.error.data || m.unknown_error() })); + return; + } + + const receivedEdid = resp.result as string; + + const matchingEdid = allEdids.find( + x => x.value.toLowerCase() === receivedEdid.toLowerCase(), + ); + + if (matchingEdid) { + setEdid(matchingEdid.value.toUpperCase()); + setCustomEdidValue(null); + } else { + setEdid("custom"); + setCustomEdidValue(receivedEdid); + } + }); }); }, [send]);