package main import ( "embed" "flag" "io/fs" "log" "net/http" "os" "os/signal" "syscall" "time" "imuslab.com/remdeskvm/remdeskd/mod/remdeshid" "imuslab.com/remdeskvm/remdeskd/mod/usbcapture" ) const defaultDevMode = true var ( developent = flag.Bool("dev", defaultDevMode, "Enable development mode with local static files") mode = flag.String("mode", "usbkvm", "Mode of operation: kvm or capture") usbKVMDeviceName = flag.String("usbkvm", "/dev/ttyUSB0", "USB KVM device file path") usbKVMBaudRate = flag.Int("baudrate", 115200, "USB KVM baud rate") captureDeviceName = flag.String("capture", "/dev/video0", "Video capture device file path") usbKVM *remdeshid.Controller videoCapture *usbcapture.Instance ) /* Web Server Static Files */ //go:embed www var embeddedFiles embed.FS var webfs http.FileSystem func init() { // Initiate the web server static files if *developent { webfs = http.Dir("./www") } else { // Embed the ./www folder and trim the prefix subFS, err := fs.Sub(embeddedFiles, "www") if err != nil { log.Fatal(err) } webfs = http.FS(subFS) } } func main() { flag.Parse() // Initiate the HID controller usbKVM = remdeshid.NewHIDController(&remdeshid.Config{ PortName: *usbKVMDeviceName, BaudRate: *usbKVMBaudRate, ScrollSensitivity: 0x01, // Set mouse scroll sensitivity }) switch *mode { case "cfgchip": //Start the HID controller err := usbKVM.Connect() if err != nil { log.Fatal(err) } /* log.Println("Starting in Configure Chip mode...") time.Sleep(2 * time.Second) // Wait for the controller to initialize _, err = usbKVM.WriteChipProperties() if err != nil { log.Fatalf("Failed to write chip properties: %v", err) return } */ time.Sleep(1 * time.Second) // Wait for the controller to initialize log.Println("Updating chip baudrate to 115200...") //Configure the HID controller err = usbKVM.ConfigureChipTo115200() if err != nil { log.Fatalf("Failed to configure chip baudrate: %v", err) return } time.Sleep(1 * time.Second) log.Println("Configuration command sent. Unplug the device and plug it back in to apply the changes.") case "usbkvm": log.Println("Starting in USB KVM mode...") //Start the HID controller err := usbKVM.Connect() if err != nil { log.Fatal(err) } // Initiate the video capture device videoCapture, err = usbcapture.NewInstance(&usbcapture.Config{ DeviceName: *captureDeviceName, AudioConfig: usbcapture.GetDefaultAudioConfig(), }) if err != nil { log.Fatalf("Failed to create video capture instance: %v", err) } //Get device information for debug usbcapture.PrintV4L2FormatInfo(*captureDeviceName) //Start the video capture device err = videoCapture.StartVideoCapture(&usbcapture.CaptureResolution{ Width: 1920, Height: 1080, FPS: 10, }) if err != nil { log.Fatal(err) } // Handle program exit to close the HID controller c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c log.Println("Shutting down usbKVM...") //usbKVM.Close() //To fix close stuck layer log.Println("Shutting down capture device...") videoCapture.Close() os.Exit(0) }() // Start the web server http.Handle("/", http.FileServer(webfs)) http.HandleFunc("/hid", usbKVM.HIDWebSocketHandler) http.HandleFunc("/audio", videoCapture.AudioStreamingHandler) http.HandleFunc("/stream", videoCapture.ServeVideoStream) addr := ":9000" log.Printf("Serving on http://localhost%s\n", addr) log.Fatal(http.ListenAndServe(addr, nil)) case "list-audio-devices": log.Println("Starting in List Audio Devices mode...") //Get the audio devices path, err := usbcapture.FindHDMICapturePCMPath() if err != nil { log.Fatalf("Failed to find HDMI capture PCM path: %v", err) } log.Printf("Found HDMI capture PCM path: %s\n", path) //List all audio capture devices captureDevs, err := usbcapture.ListCaptureDevices() if err != nil { log.Fatalf("Failed to list capture devices: %v", err) } log.Println("Available audio capture devices:") for _, dev := range captureDevs { log.Printf(" - %s\n", dev) } default: log.Fatalf("Unknown mode: %s. Supported modes are: usbkvm, capture", *mode) } }