Procházet zdrojové kódy

Add buffered duration metric for audio stream stats

tags/v0.9.0
Jan Svabenik před 4 měsíci
rodič
revize
1d20e798d1
3 změnil soubory, kde provedl 45 přidání a 12 odebrání
  1. +3
    -0
      docs/API.md
  2. +26
    -12
      internal/audio/stream.go
  3. +16
    -0
      internal/audio/stream_test.go

+ 3
- 0
docs/API.md Zobrazit soubor

@@ -298,6 +298,7 @@ Requires `--audio-stdin`, `--audio-http`, or another configured stream source to
"available": 12000, "available": 12000,
"capacity": 131072, "capacity": 131072,
"buffered": 0.09, "buffered": 0.09,
"bufferedDurationSeconds": 0.27,
"written": 890000, "written": 890000,
"underruns": 0, "underruns": 0,
"overflows": 0 "overflows": 0
@@ -366,6 +367,7 @@ The stream uses a lock-free ring buffer (default: 2 seconds at input rate). Buff
"available": 12000, "available": 12000,
"capacity": 131072, "capacity": 131072,
"buffered": 0.09, "buffered": 0.09,
"bufferedDurationSeconds": 0.27,
"written": 890000, "written": 890000,
"underruns": 0, "underruns": 0,
"overflows": 0 "overflows": 0
@@ -376,5 +378,6 @@ The stream uses a lock-free ring buffer (default: 2 seconds at input rate). Buff
- **underruns**: DSP consumed faster than audio arrived (silence inserted) - **underruns**: DSP consumed faster than audio arrived (silence inserted)
- **overflows**: Audio arrived faster than DSP consumed (data dropped) - **overflows**: Audio arrived faster than DSP consumed (data dropped)
- **buffered**: Fill ratio (0.0 = empty, 1.0 = full) - **buffered**: Fill ratio (0.0 = empty, 1.0 = full)
- **bufferedDurationSeconds**: Approximate seconds of audio queued in the buffer (`available` frames divided by the sample rate)


When no audio is streaming, the transmitter falls back to the configured tone generator or silence. When no audio is streaming, the transmitter falls back to the configured tone generator or silence.

+ 26
- 12
internal/audio/stream.go Zobrazit soubor

@@ -109,24 +109,38 @@ func (s *StreamSource) Buffered() float64 {


// Stats returns diagnostic counters. // Stats returns diagnostic counters.
func (s *StreamSource) Stats() StreamStats { func (s *StreamSource) Stats() StreamStats {
available := s.Available()
buffered := 0.0
if s.size > 0 {
buffered = float64(available) / float64(s.size)
}
return StreamStats{ return StreamStats{
Available: s.Available(),
Capacity: s.size,
Buffered: s.Buffered(),
Written: s.Written.Load(),
Underruns: s.Underruns.Load(),
Overflows: s.Overflows.Load(),
Available: available,
Capacity: s.size,
Buffered: buffered,
BufferedDurationSeconds: s.bufferedDurationSeconds(available),
Written: s.Written.Load(),
Underruns: s.Underruns.Load(),
Overflows: s.Overflows.Load(),
} }
} }


// StreamStats exposes runtime telemetry for the stream buffer. // StreamStats exposes runtime telemetry for the stream buffer.
type StreamStats struct { type StreamStats struct {
Available int `json:"available"`
Capacity int `json:"capacity"`
Buffered float64 `json:"buffered"`
Written uint64 `json:"written"`
Underruns uint64 `json:"underruns"`
Overflows uint64 `json:"overflows"`
Available int `json:"available"`
Capacity int `json:"capacity"`
Buffered float64 `json:"buffered"`
BufferedDurationSeconds float64 `json:"bufferedDurationSeconds"`
Written uint64 `json:"written"`
Underruns uint64 `json:"underruns"`
Overflows uint64 `json:"overflows"`
}

func (s *StreamSource) bufferedDurationSeconds(available int) float64 {
if s.SampleRate <= 0 {
return 0
}
return float64(available) / float64(s.SampleRate)
} }


// --- StreamResampler --- // --- StreamResampler ---


+ 16
- 0
internal/audio/stream_test.go Zobrazit soubor

@@ -205,6 +205,22 @@ func TestStreamSource_ConcurrentSPSC(t *testing.T) {
} }
} }


func TestStreamSource_StatsBufferedDuration(t *testing.T) {
rate := 48000
s := NewStreamSource(128, rate)
for i := 0; i < 24; i++ {
s.WriteFrame(NewFrame(0, 0))
}
stats := s.Stats()
if stats.BufferedDurationSeconds <= 0 {
t.Fatalf("expected buffered duration > 0, got %.6f", stats.BufferedDurationSeconds)
}
expected := float64(stats.Available) / float64(rate)
if math.Abs(stats.BufferedDurationSeconds-expected) > 1e-9 {
t.Fatalf("buffered duration %.9f != expected %.9f", stats.BufferedDurationSeconds, expected)
}
}

// --- StreamResampler tests --- // --- StreamResampler tests ---


func TestStreamResampler_1to1(t *testing.T) { func TestStreamResampler_1to1(t *testing.T) {


Načítá se…
Zrušit
Uložit