package kvm import ( "os" "sync" "time" "github.com/Masterminds/semver/v3" "github.com/jetkvm/kvm/internal/native" "github.com/pion/webrtc/v4/pkg/media" ) var ( nativeInstance *native.Native nativeCmdLock = sync.Mutex{} ) func initNative(systemVersion *semver.Version, appVersion *semver.Version) { nativeInstance = native.NewNative(native.NativeOptions{ SystemVersion: systemVersion, AppVersion: appVersion, DisplayRotation: config.GetDisplayRotation(), DefaultQualityFactor: config.VideoQualityFactor, OnVideoStateChange: func(state native.VideoState) { lastVideoState = state triggerVideoStateUpdate() requestDisplayUpdate(true, "video_state_changed") }, OnIndevEvent: func(event string) { nativeLogger.Trace().Str("event", event).Msg("indev event received") wakeDisplay(false, "indev_event") }, OnRpcEvent: func(event string) { nativeCmdLock.Lock() defer nativeCmdLock.Unlock() nativeLogger.Trace().Str("event", event).Msg("rpc event received") switch event { case "resetConfig": err := rpcResetConfig() if err != nil { nativeLogger.Warn().Err(err).Msg("error resetting config") } _ = rpcReboot(true) case "reboot": _ = rpcReboot(true) case "toggleDHCPClient": _ = rpcToggleDHCPClient() default: nativeLogger.Warn().Str("event", event).Msg("unknown rpc event received") } }, OnVideoFrameReceived: func(frame []byte, duration time.Duration) { sessionManager.ForEachSession(func(s *Session) { if !sessionManager.CanReceiveVideo(s, currentSessionSettings) { return } if s.VideoTrack != nil { err := s.VideoTrack.WriteSample(media.Sample{Data: frame, Duration: duration}) if err != nil { nativeLogger.Warn(). Str("sessionID", s.ID). Err(err). Msg("error writing sample to session") } else { // Update LastActive when video frame successfully sent (prevents observer timeout) sessionManager.UpdateLastActive(s.ID) } } }) }, }) nativeInstance.Start() go func() { if err := nativeInstance.VideoSetEDID(config.EdidString); err != nil { nativeLogger.Warn().Err(err).Msg("error setting EDID") } }() if os.Getenv("JETKVM_CRASH_TESTING") == "1" { nativeInstance.DoNotUseThisIsForCrashTestingOnly() } }