mirror of
https://github.com/jetkvm/kvm.git
synced 2026-05-21 05:20:35 +00:00
cb7746fb78
* feat(video): add H.265 codec support with auto-negotiation Add H.265 (HEVC) encoding support to the RV1106 hardware encoder alongside existing H.264. The codec is negotiated per-WebRTC session based on browser capabilities. - Add codec preference setting (Auto/H.265/H.264) to config, RPC, and UI - Auto mode inspects the browser's SDP offer and prefers H.265 when supported, with graceful fallback to H.264 for browsers without H.265 (e.g. Firefox) - Move WebRTC video track creation from newSession() to ExchangeOffer() so the codec can be resolved after seeing the browser's offer - Set encoder codec type in onFirstSessionConnected() before VideoStart() - Show active codec in the status bar when troubleshooting mode is enabled - Remove quality factor >1.0 ceiling from ctrl.c to allow bitrate testing - Fix Go wrapper to check return value from C quality factor setter - Add e2e tests: video quality bitrate measurement, codec negotiation, codec preference persistence, and a quality factor sweep benchmark - Add visual noise helpers (remote host terminal) to e2e test infrastructure * chore(e2e): remove video quality benchmark tests and helpers Remove video-quality-sweep and video-quality spec files — these are benchmarking tools, not regression tests. Also removes the visual noise helpers and hardcoded developer SSH address from helpers.ts. * feat(video): bump bitrate cap to 4000 kbps and tighten VBR ceiling - Increase base_bitrate_high from 2000 to 4000 kbps, giving users better image quality at every quality factor setting. - Tighten VBR max_bitrate from 2x to 1.5x target, reducing encoder overshoot while still allowing headroom for dynamic content. - Add frames dropped, decode time, freeze count to WebRTC test hooks for pipeline health monitoring. - Move bitrate sweep benchmark to ui/benchmarks/ with its own playwright config, separate from the e2e test suite. Sweep results (visual noise, H.264, 1080p): factor=0.1: 3082 kbps, 60fps, 0 dropped, 2.9ms decode factor=0.5: 6357 kbps, 60fps, 0 dropped, 3.6ms decode factor=1.0: 9445 kbps, 59fps, 0 dropped, 4.3ms decode
226 lines
6.9 KiB
Go
226 lines
6.9 KiB
Go
package native
|
|
|
|
import (
|
|
"context"
|
|
|
|
pb "github.com/jetkvm/kvm/internal/native/proto"
|
|
)
|
|
|
|
// Below are generated methods, do not edit manually
|
|
|
|
// Video methods
|
|
func (c *GRPCClient) VideoSetSleepMode(enabled bool) error {
|
|
_, err := c.client.VideoSetSleepMode(context.Background(), &pb.VideoSetSleepModeRequest{Enabled: enabled})
|
|
return err
|
|
}
|
|
|
|
func (c *GRPCClient) VideoGetSleepMode() (bool, error) {
|
|
resp, err := c.client.VideoGetSleepMode(context.Background(), &pb.Empty{})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Enabled, nil
|
|
}
|
|
|
|
func (c *GRPCClient) VideoSleepModeSupported() bool {
|
|
resp, err := c.client.VideoSleepModeSupported(context.Background(), &pb.Empty{})
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return resp.Supported
|
|
}
|
|
|
|
func (c *GRPCClient) VideoSetQualityFactor(factor float64) error {
|
|
_, err := c.client.VideoSetQualityFactor(context.Background(), &pb.VideoSetQualityFactorRequest{Factor: factor})
|
|
return err
|
|
}
|
|
|
|
func (c *GRPCClient) VideoGetQualityFactor() (float64, error) {
|
|
resp, err := c.client.VideoGetQualityFactor(context.Background(), &pb.Empty{})
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return resp.Factor, nil
|
|
}
|
|
|
|
func (c *GRPCClient) VideoSetCodecType(codecType int) error {
|
|
_, err := c.client.VideoSetCodecType(context.Background(), &pb.VideoSetCodecTypeRequest{CodecType: int32(codecType)})
|
|
return err
|
|
}
|
|
|
|
func (c *GRPCClient) VideoGetCodecType() (int, error) {
|
|
resp, err := c.client.VideoGetCodecType(context.Background(), &pb.Empty{})
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(resp.CodecType), nil
|
|
}
|
|
|
|
func (c *GRPCClient) VideoSetEDID(edid string) error {
|
|
_, err := c.client.VideoSetEDID(context.Background(), &pb.VideoSetEDIDRequest{Edid: edid})
|
|
return err
|
|
}
|
|
|
|
func (c *GRPCClient) VideoGetEDID() (string, error) {
|
|
resp, err := c.client.VideoGetEDID(context.Background(), &pb.Empty{})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return resp.Edid, nil
|
|
}
|
|
|
|
func (c *GRPCClient) VideoLogStatus() (string, error) {
|
|
resp, err := c.client.VideoLogStatus(context.Background(), &pb.Empty{})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return resp.Status, nil
|
|
}
|
|
|
|
func (c *GRPCClient) VideoStop() error {
|
|
_, err := c.client.VideoStop(context.Background(), &pb.Empty{})
|
|
return err
|
|
}
|
|
|
|
func (c *GRPCClient) VideoStart() error {
|
|
_, err := c.client.VideoStart(context.Background(), &pb.Empty{})
|
|
return err
|
|
}
|
|
|
|
// UI methods
|
|
func (c *GRPCClient) GetLVGLVersion() (string, error) {
|
|
resp, err := c.client.GetLVGLVersion(context.Background(), &pb.Empty{})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return resp.Version, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjHide(objName string) (bool, error) {
|
|
resp, err := c.client.UIObjHide(context.Background(), &pb.UIObjHideRequest{ObjName: objName})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjShow(objName string) (bool, error) {
|
|
resp, err := c.client.UIObjShow(context.Background(), &pb.UIObjShowRequest{ObjName: objName})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UISetVar(name string, value string) {
|
|
_, _ = c.client.UISetVar(context.Background(), &pb.UISetVarRequest{Name: name, Value: value})
|
|
}
|
|
|
|
func (c *GRPCClient) UIGetVar(name string) string {
|
|
resp, err := c.client.UIGetVar(context.Background(), &pb.UIGetVarRequest{Name: name})
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return resp.Value
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjAddState(objName string, state string) (bool, error) {
|
|
resp, err := c.client.UIObjAddState(context.Background(), &pb.UIObjAddStateRequest{ObjName: objName, State: state})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjClearState(objName string, state string) (bool, error) {
|
|
resp, err := c.client.UIObjClearState(context.Background(), &pb.UIObjClearStateRequest{ObjName: objName, State: state})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjAddFlag(objName string, flag string) (bool, error) {
|
|
resp, err := c.client.UIObjAddFlag(context.Background(), &pb.UIObjAddFlagRequest{ObjName: objName, Flag: flag})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjClearFlag(objName string, flag string) (bool, error) {
|
|
resp, err := c.client.UIObjClearFlag(context.Background(), &pb.UIObjClearFlagRequest{ObjName: objName, Flag: flag})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjSetOpacity(objName string, opacity int) (bool, error) {
|
|
resp, err := c.client.UIObjSetOpacity(context.Background(), &pb.UIObjSetOpacityRequest{ObjName: objName, Opacity: int32(opacity)})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjFadeIn(objName string, duration uint32) (bool, error) {
|
|
resp, err := c.client.UIObjFadeIn(context.Background(), &pb.UIObjFadeInRequest{ObjName: objName, Duration: duration})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjFadeOut(objName string, duration uint32) (bool, error) {
|
|
resp, err := c.client.UIObjFadeOut(context.Background(), &pb.UIObjFadeOutRequest{ObjName: objName, Duration: duration})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjSetLabelText(objName string, text string) (bool, error) {
|
|
resp, err := c.client.UIObjSetLabelText(context.Background(), &pb.UIObjSetLabelTextRequest{ObjName: objName, Text: text})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UIObjSetImageSrc(objName string, image string) (bool, error) {
|
|
resp, err := c.client.UIObjSetImageSrc(context.Background(), &pb.UIObjSetImageSrcRequest{ObjName: objName, Image: image})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) DisplaySetRotation(rotation uint16) (bool, error) {
|
|
resp, err := c.client.DisplaySetRotation(context.Background(), &pb.DisplaySetRotationRequest{Rotation: uint32(rotation)})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Success, nil
|
|
}
|
|
|
|
func (c *GRPCClient) UpdateLabelIfChanged(objName string, newText string) {
|
|
_, _ = c.client.UpdateLabelIfChanged(context.Background(), &pb.UpdateLabelIfChangedRequest{ObjName: objName, NewText: newText})
|
|
}
|
|
|
|
func (c *GRPCClient) UpdateLabelAndChangeVisibility(objName string, newText string) {
|
|
_, _ = c.client.UpdateLabelAndChangeVisibility(context.Background(), &pb.UpdateLabelAndChangeVisibilityRequest{ObjName: objName, NewText: newText})
|
|
}
|
|
|
|
func (c *GRPCClient) SwitchToScreenIf(screenName string, shouldSwitch []string) {
|
|
_, _ = c.client.SwitchToScreenIf(context.Background(), &pb.SwitchToScreenIfRequest{ScreenName: screenName, ShouldSwitch: shouldSwitch})
|
|
}
|
|
|
|
func (c *GRPCClient) SwitchToScreenIfDifferent(screenName string) {
|
|
_, _ = c.client.SwitchToScreenIfDifferent(context.Background(), &pb.SwitchToScreenIfDifferentRequest{ScreenName: screenName})
|
|
}
|
|
|
|
func (c *GRPCClient) DoNotUseThisIsForCrashTestingOnly() {
|
|
_, _ = c.client.DoNotUseThisIsForCrashTestingOnly(context.Background(), &pb.Empty{})
|
|
}
|