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
240 lines
8.8 KiB
Go
240 lines
8.8 KiB
Go
package native
|
|
|
|
import (
|
|
"context"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
pb "github.com/jetkvm/kvm/internal/native/proto"
|
|
)
|
|
|
|
// Below are generated methods, do not edit manually
|
|
|
|
// Video methods
|
|
func (s *grpcServer) VideoSetSleepMode(ctx context.Context, req *pb.VideoSetSleepModeRequest) (*pb.Empty, error) {
|
|
if err := s.native.VideoSetSleepMode(req.Enabled); err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoGetSleepMode(ctx context.Context, req *pb.Empty) (*pb.VideoGetSleepModeResponse, error) {
|
|
enabled, err := s.native.VideoGetSleepMode()
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.VideoGetSleepModeResponse{Enabled: enabled}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoSleepModeSupported(ctx context.Context, req *pb.Empty) (*pb.VideoSleepModeSupportedResponse, error) {
|
|
return &pb.VideoSleepModeSupportedResponse{Supported: s.native.VideoSleepModeSupported()}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoSetQualityFactor(ctx context.Context, req *pb.VideoSetQualityFactorRequest) (*pb.Empty, error) {
|
|
if err := s.native.VideoSetQualityFactor(req.Factor); err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoGetQualityFactor(ctx context.Context, req *pb.Empty) (*pb.VideoGetQualityFactorResponse, error) {
|
|
factor, err := s.native.VideoGetQualityFactor()
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.VideoGetQualityFactorResponse{Factor: factor}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoSetCodecType(ctx context.Context, req *pb.VideoSetCodecTypeRequest) (*pb.Empty, error) {
|
|
if err := s.native.VideoSetCodecType(int(req.CodecType)); err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoGetCodecType(ctx context.Context, req *pb.Empty) (*pb.VideoGetCodecTypeResponse, error) {
|
|
codecType, err := s.native.VideoGetCodecType()
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.VideoGetCodecTypeResponse{CodecType: int32(codecType)}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoSetEDID(ctx context.Context, req *pb.VideoSetEDIDRequest) (*pb.Empty, error) {
|
|
if err := s.native.VideoSetEDID(req.Edid); err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoGetEDID(ctx context.Context, req *pb.Empty) (*pb.VideoGetEDIDResponse, error) {
|
|
edid, err := s.native.VideoGetEDID()
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.VideoGetEDIDResponse{Edid: edid}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoLogStatus(ctx context.Context, req *pb.Empty) (*pb.VideoLogStatusResponse, error) {
|
|
logStatus, err := s.native.VideoLogStatus()
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.VideoLogStatusResponse{Status: logStatus}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoStop(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
|
if err := s.native.VideoStop(); err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) VideoStart(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
|
if err := s.native.VideoStart(); err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
// UI methods
|
|
func (s *grpcServer) GetLVGLVersion(ctx context.Context, req *pb.Empty) (*pb.GetLVGLVersionResponse, error) {
|
|
version, err := s.native.GetLVGLVersion()
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.GetLVGLVersionResponse{Version: version}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjHide(ctx context.Context, req *pb.UIObjHideRequest) (*pb.UIObjHideResponse, error) {
|
|
success, err := s.native.UIObjHide(req.ObjName)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjHideResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjShow(ctx context.Context, req *pb.UIObjShowRequest) (*pb.UIObjShowResponse, error) {
|
|
success, err := s.native.UIObjShow(req.ObjName)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjShowResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UISetVar(ctx context.Context, req *pb.UISetVarRequest) (*pb.Empty, error) {
|
|
s.native.UISetVar(req.Name, req.Value)
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIGetVar(ctx context.Context, req *pb.UIGetVarRequest) (*pb.UIGetVarResponse, error) {
|
|
value := s.native.UIGetVar(req.Name)
|
|
return &pb.UIGetVarResponse{Value: value}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjAddState(ctx context.Context, req *pb.UIObjAddStateRequest) (*pb.UIObjAddStateResponse, error) {
|
|
success, err := s.native.UIObjAddState(req.ObjName, req.State)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjAddStateResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjClearState(ctx context.Context, req *pb.UIObjClearStateRequest) (*pb.UIObjClearStateResponse, error) {
|
|
success, err := s.native.UIObjClearState(req.ObjName, req.State)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjClearStateResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjAddFlag(ctx context.Context, req *pb.UIObjAddFlagRequest) (*pb.UIObjAddFlagResponse, error) {
|
|
success, err := s.native.UIObjAddFlag(req.ObjName, req.Flag)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjAddFlagResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjClearFlag(ctx context.Context, req *pb.UIObjClearFlagRequest) (*pb.UIObjClearFlagResponse, error) {
|
|
success, err := s.native.UIObjClearFlag(req.ObjName, req.Flag)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjClearFlagResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjSetOpacity(ctx context.Context, req *pb.UIObjSetOpacityRequest) (*pb.UIObjSetOpacityResponse, error) {
|
|
success, err := s.native.UIObjSetOpacity(req.ObjName, int(req.Opacity))
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjSetOpacityResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjFadeIn(ctx context.Context, req *pb.UIObjFadeInRequest) (*pb.UIObjFadeInResponse, error) {
|
|
success, err := s.native.UIObjFadeIn(req.ObjName, req.Duration)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjFadeInResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjFadeOut(ctx context.Context, req *pb.UIObjFadeOutRequest) (*pb.UIObjFadeOutResponse, error) {
|
|
success, err := s.native.UIObjFadeOut(req.ObjName, req.Duration)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjFadeOutResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjSetLabelText(ctx context.Context, req *pb.UIObjSetLabelTextRequest) (*pb.UIObjSetLabelTextResponse, error) {
|
|
success, err := s.native.UIObjSetLabelText(req.ObjName, req.Text)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjSetLabelTextResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UIObjSetImageSrc(ctx context.Context, req *pb.UIObjSetImageSrcRequest) (*pb.UIObjSetImageSrcResponse, error) {
|
|
success, err := s.native.UIObjSetImageSrc(req.ObjName, req.Image)
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.UIObjSetImageSrcResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) DisplaySetRotation(ctx context.Context, req *pb.DisplaySetRotationRequest) (*pb.DisplaySetRotationResponse, error) {
|
|
success, err := s.native.DisplaySetRotation(uint16(req.Rotation))
|
|
if err != nil {
|
|
return nil, status.Error(codes.Internal, err.Error())
|
|
}
|
|
return &pb.DisplaySetRotationResponse{Success: success}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UpdateLabelIfChanged(ctx context.Context, req *pb.UpdateLabelIfChangedRequest) (*pb.Empty, error) {
|
|
s.native.UpdateLabelIfChanged(req.ObjName, req.NewText)
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) UpdateLabelAndChangeVisibility(ctx context.Context, req *pb.UpdateLabelAndChangeVisibilityRequest) (*pb.Empty, error) {
|
|
s.native.UpdateLabelAndChangeVisibility(req.ObjName, req.NewText)
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) SwitchToScreenIf(ctx context.Context, req *pb.SwitchToScreenIfRequest) (*pb.Empty, error) {
|
|
s.native.SwitchToScreenIf(req.ScreenName, req.ShouldSwitch)
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) SwitchToScreenIfDifferent(ctx context.Context, req *pb.SwitchToScreenIfDifferentRequest) (*pb.Empty, error) {
|
|
s.native.SwitchToScreenIfDifferent(req.ScreenName)
|
|
return &pb.Empty{}, nil
|
|
}
|
|
|
|
func (s *grpcServer) DoNotUseThisIsForCrashTestingOnly(ctx context.Context, req *pb.Empty) (*pb.Empty, error) {
|
|
s.native.DoNotUseThisIsForCrashTestingOnly()
|
|
return &pb.Empty{}, nil
|
|
}
|