Fix ESP32 audio dropouts and improve streaming reliability

FLAC encoder now tracks frame numbers and reuses per-channel sample
buffers to reduce allocations. Client dialer always frees the active
slot on release so mDNS re-emissions can reconnect cleanly. Server
send buffer uses drop-oldest instead of hard failure, with lateness
tracking. Added engine stats logging (chunks/sec, kbps) and writer
diagnostics. UI simplified to a single play/pause toggle that
auto-starts playback on preset selection. Added --preset CLI flag
for headless startup. Removed stale systemd service files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 14:50:30 +02:00
parent d72e439fd9
commit 6e22834c5c
12 changed files with 158 additions and 82 deletions

View File

@@ -18,6 +18,8 @@ func (s *Server) streamAudio() {
tickBudget := time.Duration(ChunkDurationMs) * time.Millisecond
var lastTick time.Time
var chunkCount int
rateWindowStart := time.Now()
for {
select {
case t := <-ticker.C:
@@ -35,6 +37,21 @@ func (s *Server) streamAudio() {
lastTick = t
s.generateAndSendChunk()
chunkCount++
if elapsed := time.Since(rateWindowStart); elapsed >= 10*time.Second {
rate := float64(chunkCount) / elapsed.Seconds()
avgBytes := 0
if chunkCount > 0 {
avgBytes = int(s.lastWindowBytes) / chunkCount
}
kbps := float64(s.lastWindowBytes) * 8 / 1000.0 / elapsed.Seconds()
log.Printf("ENGINE STATS: %.3f chunks/sec, avg %d bytes/chunk, %.1f kbps over %s (%d chunks)",
rate, avgBytes, kbps, elapsed.Round(time.Millisecond), chunkCount)
chunkCount = 0
s.lastWindowBytes = 0
rateWindowStart = time.Now()
}
case <-s.stopChan:
log.Printf("Audio streaming stopping")
return
@@ -100,6 +117,10 @@ func (s *Server) generateAndSendChunk() {
tracker := c.bufferTracker
c.mu.RUnlock()
if codec == "" {
continue
}
switch codec {
case "opus":
if opusEncoder != nil {
@@ -139,6 +160,7 @@ func (s *Server) generateAndSendChunk() {
}
chunk := CreateAudioChunk(playbackTime, audioData)
s.lastWindowBytes += int64(len(chunk))
if tracker != nil {
chunkDurationUs := int64(ChunkDurationMs) * 1000