feat: add bitrate measurement and quality presets
- sender tracks payload bytes; engine measures stream bitrate over a sliding window and exposes it in Status - GUI status label and tray tooltip show the live bitrate (e.g. 36 Mbps) - add a Preset dropdown (Low/Medium/High/Ultra) that sets quality+fps together and applies live via SetConfig Verified: 36 Mbps shown for Medium (quality 70 @ 30fps) matches the wire measurement.
This commit is contained in:
@@ -129,6 +129,63 @@ func TestValidate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestBitrateMeasurement verifies the engine reports a non-zero bitrate once
|
||||
// it has been streaming for a bit.
|
||||
func TestBitrateMeasurement(t *testing.T) {
|
||||
cfg := DefaultConfig()
|
||||
cfg.Source = "pattern"
|
||||
cfg.Port = 19759
|
||||
|
||||
eng, err := New(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("New: %v", err)
|
||||
}
|
||||
eng.Start()
|
||||
defer eng.Stop()
|
||||
|
||||
// Connect a receiver so packets actually flow, and wait for the bitrate
|
||||
// window to produce a measurement.
|
||||
conn, err := net.Dial("tcp", "127.0.0.1:"+itoa(eng.sender.Port()))
|
||||
if err != nil {
|
||||
t.Fatalf("dial: %v", err)
|
||||
}
|
||||
defer func() { _ = conn.Close() }()
|
||||
go func() {
|
||||
buf := make([]byte, 64*1024)
|
||||
for {
|
||||
if _, err := conn.Read(buf); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
deadline := time.Now().Add(4 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if eng.Status().Bitrate > 0 {
|
||||
return
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
t.Error("bitrate stayed 0 after 4s of streaming")
|
||||
}
|
||||
|
||||
// TestFormatBitrate checks the human-readable bitrate formatting.
|
||||
func TestFormatBitrate(t *testing.T) {
|
||||
cases := []struct {
|
||||
bps int64
|
||||
want string
|
||||
}{
|
||||
{500, "500 bps"},
|
||||
{5_000, "5 kbps"},
|
||||
{5_000_000, "5.0 Mbps"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := formatBitrate(c.bps); got != c.want {
|
||||
t.Errorf("formatBitrate(%d) = %q, want %q", c.bps, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func itoa(v int) string {
|
||||
if v == 0 {
|
||||
return "0"
|
||||
|
||||
Reference in New Issue
Block a user