diff --git a/internal/native/cgo/ctrl.c b/internal/native/cgo/ctrl.c index 8ea06bd3..d8c4cdb2 100644 --- a/internal/native/cgo/ctrl.c +++ b/internal/native/cgo/ctrl.c @@ -393,6 +393,10 @@ jetkvm_video_state_t *jetkvm_video_get_status() { return &state; } +char *jetkvm_video_log_status() { + return videoc_log_status(); +} + int jetkvm_video_init() { return video_init(); } diff --git a/internal/native/cgo/ctrl.h b/internal/native/cgo/ctrl.h index 254fdf7b..a87070a0 100644 --- a/internal/native/cgo/ctrl.h +++ b/internal/native/cgo/ctrl.h @@ -59,6 +59,7 @@ int jetkvm_video_set_quality_factor(float quality_factor); float jetkvm_video_get_quality_factor(); int jetkvm_video_set_edid(const char *edid_hex); char *jetkvm_video_get_edid_hex(); +char *jetkvm_video_log_status(); jetkvm_video_state_t *jetkvm_video_get_status(); void video_report_format(bool ready, const char *error, u_int16_t width, u_int16_t height, double frame_per_second); diff --git a/internal/native/cgo_linux.go b/internal/native/cgo_linux.go index 54d57b55..b7ea7220 100644 --- a/internal/native/cgo_linux.go +++ b/internal/native/cgo_linux.go @@ -162,6 +162,16 @@ func videoStop() { C.jetkvm_video_stop() } +func videoLogStatus() string { + cgoLock.Lock() + defer cgoLock.Unlock() + + logStatus := C.jetkvm_video_log_status() + defer C.free(unsafe.Pointer(logStatus)) + + return C.GoString(logStatus) +} + func uiSetVar(name string, value string) { cgoLock.Lock() defer cgoLock.Unlock() diff --git a/internal/native/cgo_notlinux.go b/internal/native/cgo_notlinux.go index 1b23ab5e..6dc14c9c 100644 --- a/internal/native/cgo_notlinux.go +++ b/internal/native/cgo_notlinux.go @@ -108,6 +108,11 @@ func videoSetStreamQualityFactor(factor float64) error { return nil } +func videoLogStatus() string { + panicPlatformNotSupported() + return "" +} + func videoGetEDID() (string, error) { panicPlatformNotSupported() return "", nil diff --git a/internal/native/lib/libjknative.a b/internal/native/lib/libjknative.a index 91bb75c4..effa575e 100644 Binary files a/internal/native/lib/libjknative.a and b/internal/native/lib/libjknative.a differ diff --git a/internal/native/video.go b/internal/native/video.go index b354b2e5..77291eb7 100644 --- a/internal/native/video.go +++ b/internal/native/video.go @@ -36,6 +36,13 @@ func (n *Native) VideoGetEDID() (string, error) { return videoGetEDID() } +func (n *Native) VideoLogStatus() (string, error) { + n.videoLock.Lock() + defer n.videoLock.Unlock() + + return videoLogStatus(), nil +} + func (n *Native) VideoStop() error { n.videoLock.Lock() defer n.videoLock.Unlock() diff --git a/jsonrpc.go b/jsonrpc.go index 32f9bb8a..14faccc8 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -251,6 +251,10 @@ func rpcSetEDID(edid string) error { return nil } +func rpcGetVideoLogStatus() (string, error) { + return nativeInstance.VideoLogStatus() +} + func rpcGetDevChannelState() (bool, error) { return config.IncludePreRelease, nil } @@ -1207,6 +1211,7 @@ var rpcHandlers = map[string]RPCHandler{ "setAutoUpdateState": {Func: rpcSetAutoUpdateState, Params: []string{"enabled"}}, "getEDID": {Func: rpcGetEDID}, "setEDID": {Func: rpcSetEDID, Params: []string{"edid"}}, + "getVideoLogStatus": {Func: rpcGetVideoLogStatus}, "getDevChannelState": {Func: rpcGetDevChannelState}, "setDevChannelState": {Func: rpcSetDevChannelState, Params: []string{"enabled"}}, "getLocalVersion": {Func: rpcGetLocalVersion}, diff --git a/ui/src/routes/devices.$id.settings.video.tsx b/ui/src/routes/devices.$id.settings.video.tsx index ea1a101a..963b6d81 100644 --- a/ui/src/routes/devices.$id.settings.video.tsx +++ b/ui/src/routes/devices.$id.settings.video.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { Button } from "@/components/Button"; import { TextAreaWithLabel } from "@/components/TextArea"; @@ -52,7 +52,7 @@ export default function SettingsVideoRoute() { const [customEdidValue, setCustomEdidValue] = useState(null); const [edid, setEdid] = useState(null); const [edidLoading, setEdidLoading] = useState(false); - + const { debugMode } = useSettingsStore(); // Video enhancement settings from store const { videoSaturation, @@ -132,6 +132,26 @@ export default function SettingsVideoRoute() { }); }; + const [debugInfo, setDebugInfo] = useState(null); + const [debugInfoLoading, setDebugInfoLoading] = useState(false); + const getDebugInfo = useCallback(() => { + setDebugInfoLoading(true); + send("getVideoLogStatus", {}, (resp: JsonRpcResponse) => { + if ("error" in resp) { + notifications.error(`Failed to get debug info: ${resp.error.data || "Unknown error"}`); + setDebugInfoLoading(false); + return; + } + const data = resp.result as string; + setDebugInfo(data + .split("\n") + .map(line => line.trim().replace(/^\[\s*\d+\.\d+\]\s*/, "")) + .join("\n") + ); + setDebugInfoLoading(false); + }); + }, [send]); + return (
@@ -279,6 +299,30 @@ export default function SettingsVideoRoute() { )}
+ + + {debugMode && ( +
+ +
+ )}