fix fps toggle
This commit is contained in:
@@ -432,3 +432,29 @@ func TestCaptureAndSend_CancelledContext(t *testing.T) {
|
|||||||
// SHOULD handle gracefully, may or may not send depending on timing :sob:
|
// SHOULD handle gracefully, may or may not send depending on timing :sob:
|
||||||
_ = CaptureAndSend(ctx, env)
|
_ = CaptureAndSend(ctx, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetFrameFlowTargetFPSScalesHighFPS(t *testing.T) {
|
||||||
|
t.Setenv("OVERLORD_DESKTOP_IN_FLIGHT_FRAMES", "")
|
||||||
|
ResetFrameSlots()
|
||||||
|
SetFrameFlowTargetFPS(60)
|
||||||
|
if got := activeFrameSlotLimit(); got != 2 {
|
||||||
|
t.Fatalf("expected 60 fps slot limit 2, got %d", got)
|
||||||
|
}
|
||||||
|
SetFrameFlowTargetFPS(120)
|
||||||
|
if got := activeFrameSlotLimit(); got != 4 {
|
||||||
|
t.Fatalf("expected 120 fps slot limit 4, got %d", got)
|
||||||
|
}
|
||||||
|
SetFrameFlowTargetFPS(240)
|
||||||
|
if got := activeFrameSlotLimit(); got != 8 {
|
||||||
|
t.Fatalf("expected 240 fps slot limit 8, got %d", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetFrameFlowTargetFPSEnvOverride(t *testing.T) {
|
||||||
|
t.Setenv("OVERLORD_DESKTOP_IN_FLIGHT_FRAMES", "12")
|
||||||
|
ResetFrameSlots()
|
||||||
|
SetFrameFlowTargetFPS(240)
|
||||||
|
if got := activeFrameSlotLimit(); got != 12 {
|
||||||
|
t.Fatalf("expected env slot limit 12, got %d", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
package capture
|
package capture
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxInFlightFrames int64 = 2
|
const defaultMaxInFlightFrames int64 = 2
|
||||||
|
|
||||||
var (
|
var (
|
||||||
inFlightFrames atomic.Int64
|
inFlightFrames atomic.Int64
|
||||||
frameAckSeen atomic.Bool
|
frameAckSeen atomic.Bool
|
||||||
lastAckNano atomic.Int64
|
lastAckNano atomic.Int64
|
||||||
|
maxFrameSlots atomic.Int64
|
||||||
)
|
)
|
||||||
|
|
||||||
func AcquireFrameSlot() bool {
|
func AcquireFrameSlot() bool {
|
||||||
@@ -20,7 +24,7 @@ func AcquireFrameSlot() bool {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
cur := inFlightFrames.Load()
|
cur := inFlightFrames.Load()
|
||||||
if cur >= maxInFlightFrames {
|
if cur >= activeFrameSlotLimit() {
|
||||||
lastAck := lastAckNano.Load()
|
lastAck := lastAckNano.Load()
|
||||||
if lastAck > 0 && time.Since(time.Unix(0, lastAck)) > time.Second {
|
if lastAck > 0 && time.Since(time.Unix(0, lastAck)) > time.Second {
|
||||||
inFlightFrames.Store(0)
|
inFlightFrames.Store(0)
|
||||||
@@ -47,3 +51,33 @@ func ResetFrameSlots() {
|
|||||||
frameAckSeen.Store(false)
|
frameAckSeen.Store(false)
|
||||||
lastAckNano.Store(0)
|
lastAckNano.Store(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetFrameFlowTargetFPS(fps int) {
|
||||||
|
limit := defaultMaxInFlightFrames
|
||||||
|
switch {
|
||||||
|
case fps >= 180:
|
||||||
|
limit = 8
|
||||||
|
case fps >= 120:
|
||||||
|
limit = 4
|
||||||
|
}
|
||||||
|
if env := strings.TrimSpace(os.Getenv("OVERLORD_DESKTOP_IN_FLIGHT_FRAMES")); env != "" {
|
||||||
|
if v, err := strconv.Atoi(env); err == nil {
|
||||||
|
switch {
|
||||||
|
case v < 1:
|
||||||
|
limit = 1
|
||||||
|
case v > 32:
|
||||||
|
limit = 32
|
||||||
|
default:
|
||||||
|
limit = int64(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxFrameSlots.Store(limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func activeFrameSlotLimit() int64 {
|
||||||
|
if limit := maxFrameSlots.Load(); limit > 0 {
|
||||||
|
return limit
|
||||||
|
}
|
||||||
|
return defaultMaxInFlightFrames
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ func DesktopStart(ctx context.Context, env *rt.Env) error {
|
|||||||
fps := activeDesktopTargetFPS()
|
fps := activeDesktopTargetFPS()
|
||||||
interval := time.Second / time.Duration(fps)
|
interval := time.Second / time.Duration(fps)
|
||||||
capture.SetH264TargetFPS(fps)
|
capture.SetH264TargetFPS(fps)
|
||||||
|
capture.SetFrameFlowTargetFPS(fps)
|
||||||
log.Printf("desktop: starting stream (target fps %d)", fps)
|
log.Printf("desktop: starting stream (target fps %d)", fps)
|
||||||
ticker := time.NewTicker(interval)
|
ticker := time.NewTicker(interval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
@@ -47,6 +48,7 @@ func DesktopStart(ctx context.Context, env *rt.Env) error {
|
|||||||
if fps != currentFPS {
|
if fps != currentFPS {
|
||||||
currentFPS = fps
|
currentFPS = fps
|
||||||
capture.SetH264TargetFPS(fps)
|
capture.SetH264TargetFPS(fps)
|
||||||
|
capture.SetFrameFlowTargetFPS(fps)
|
||||||
ticker.Reset(time.Second / time.Duration(fps))
|
ticker.Reset(time.Second / time.Duration(fps))
|
||||||
log.Printf("desktop: target fps changed to %d", fps)
|
log.Printf("desktop: target fps changed to %d", fps)
|
||||||
}
|
}
|
||||||
@@ -73,6 +75,7 @@ func SetDesktopTargetFPS(fps int) int {
|
|||||||
fps = clampDesktopTargetFPS(fps)
|
fps = clampDesktopTargetFPS(fps)
|
||||||
desktopTargetFPS.Store(int64(fps))
|
desktopTargetFPS.Store(int64(fps))
|
||||||
capture.SetH264TargetFPS(fps)
|
capture.SetH264TargetFPS(fps)
|
||||||
|
capture.SetFrameFlowTargetFPS(fps)
|
||||||
return fps
|
return fps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -788,6 +788,7 @@ import { createKeyboardCapture } from "./keyboard-capture.js";
|
|||||||
pushInputToggles();
|
pushInputToggles();
|
||||||
pushCaptureToggles();
|
pushCaptureToggles();
|
||||||
if (qualitySlider) pushQuality(qualitySlider.value);
|
if (qualitySlider) pushQuality(qualitySlider.value);
|
||||||
|
pushTargetFps();
|
||||||
pushResolution();
|
pushResolution();
|
||||||
} else {
|
} else {
|
||||||
setStreamState("idle", "Stopped");
|
setStreamState("idle", "Stopped");
|
||||||
|
|||||||
Reference in New Issue
Block a user