mirror of https://github.com/jetkvm/kvm.git
162 lines
3.9 KiB
Go
162 lines
3.9 KiB
Go
package native
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
const sleepModeFile = "/sys/devices/platform/ff470000.i2c/i2c-4/4-000f/sleep_mode"
|
|
|
|
// DefaultEDID is the default EDID for the video stream.
|
|
const DefaultEDID = "00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b"
|
|
|
|
var extraLockTimeout = 5 * time.Second
|
|
|
|
// VideoState is the state of the video stream.
|
|
type VideoState struct {
|
|
Ready bool `json:"ready"`
|
|
Error string `json:"error,omitempty"` //no_signal, no_lock, out_of_range
|
|
Width int `json:"width"`
|
|
Height int `json:"height"`
|
|
FramePerSecond float64 `json:"fps"`
|
|
}
|
|
|
|
func isSleepModeSupported() bool {
|
|
_, err := os.Stat(sleepModeFile)
|
|
return err == nil
|
|
}
|
|
|
|
func (n *Native) setSleepMode(enabled bool) error {
|
|
if !n.sleepModeSupported {
|
|
return nil
|
|
}
|
|
|
|
bEnabled := "0"
|
|
if enabled {
|
|
bEnabled = "1"
|
|
}
|
|
return os.WriteFile(sleepModeFile, []byte(bEnabled), 0644)
|
|
}
|
|
|
|
func (n *Native) getSleepMode() (bool, error) {
|
|
if !n.sleepModeSupported {
|
|
return false, nil
|
|
}
|
|
|
|
data, err := os.ReadFile(sleepModeFile)
|
|
if err == nil {
|
|
return string(data) == "1", nil
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
// VideoSetSleepMode sets the sleep mode for the video stream.
|
|
func (n *Native) VideoSetSleepMode(enabled bool) error {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
return n.setSleepMode(enabled)
|
|
}
|
|
|
|
// VideoGetSleepMode gets the sleep mode for the video stream.
|
|
func (n *Native) VideoGetSleepMode() (bool, error) {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
return n.getSleepMode()
|
|
}
|
|
|
|
// VideoSleepModeSupported checks if the sleep mode is supported.
|
|
func (n *Native) VideoSleepModeSupported() bool {
|
|
return n.sleepModeSupported
|
|
}
|
|
|
|
// useExtraLock uses the extra lock to execute a function.
|
|
// if the lock is currently held by another goroutine, returns an error.
|
|
//
|
|
// it's used to ensure that only one change is made to the video stream at a time.
|
|
// as the change usually requires to restart video streaming
|
|
// TODO: check video streaming status instead of using a hardcoded timeout
|
|
func (n *Native) useExtraLock(fn func() error) error {
|
|
if !n.extraLock.TryLock() {
|
|
return fmt.Errorf("the previous change hasn't been completed yet")
|
|
}
|
|
err := fn()
|
|
if err == nil {
|
|
time.Sleep(extraLockTimeout)
|
|
}
|
|
n.extraLock.Unlock()
|
|
return err
|
|
}
|
|
|
|
// VideoSetQualityFactor sets the quality factor for the video stream.
|
|
func (n *Native) VideoSetQualityFactor(factor float64) error {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
return n.useExtraLock(func() error {
|
|
return videoSetStreamQualityFactor(factor)
|
|
})
|
|
}
|
|
|
|
// VideoGetQualityFactor gets the quality factor for the video stream.
|
|
func (n *Native) VideoGetQualityFactor() (float64, error) {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
return videoGetStreamQualityFactor()
|
|
}
|
|
|
|
// VideoSetEDID sets the EDID for the video stream.
|
|
func (n *Native) VideoSetEDID(edid string) error {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
if edid == "" {
|
|
edid = DefaultEDID
|
|
}
|
|
|
|
return n.useExtraLock(func() error {
|
|
return videoSetEDID(edid)
|
|
})
|
|
}
|
|
|
|
// VideoGetEDID gets the EDID for the video stream.
|
|
func (n *Native) VideoGetEDID() (string, error) {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
return videoGetEDID()
|
|
}
|
|
|
|
// VideoLogStatus gets the log status for the video stream.
|
|
func (n *Native) VideoLogStatus() (string, error) {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
return videoLogStatus(), nil
|
|
}
|
|
|
|
// VideoStop stops the video stream.
|
|
func (n *Native) VideoStop() error {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
videoStop()
|
|
return nil
|
|
}
|
|
|
|
// VideoStart starts the video stream.
|
|
func (n *Native) VideoStart() error {
|
|
n.videoLock.Lock()
|
|
defer n.videoLock.Unlock()
|
|
|
|
// disable sleep mode before starting video
|
|
_ = n.setSleepMode(false)
|
|
|
|
videoStart()
|
|
return nil
|
|
}
|