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:
@@ -128,27 +128,23 @@ func (d *clientDialer) claim(instance string) bool {
|
||||
}
|
||||
|
||||
// release updates the instance slot after a dial attempt completes.
|
||||
// On success (dialErr == nil) the instance stays latched in the active
|
||||
// set — we never re-dial a successfully-connected instance. On error
|
||||
// it frees the slot and schedules an exponentially-backed-off cooldown
|
||||
// before the next retry.
|
||||
// The slot is always freed — dial() only returns after handleConnection
|
||||
// has returned, so the connection is already dead by the time we get
|
||||
// here, and a future mDNS re-emission should be free to redial. On
|
||||
// error it also schedules an exponentially-backed-off cooldown before
|
||||
// the next retry.
|
||||
func (d *clientDialer) release(instance string, dialErr error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
delete(d.active, instance)
|
||||
|
||||
if dialErr == nil {
|
||||
// Latch: keep active[instance] = true so future discovery
|
||||
// events for this instance are silently ignored. The server
|
||||
// already handled the connection; re-dialing would create a
|
||||
// duplicate session.
|
||||
delete(d.failures, instance)
|
||||
delete(d.cooldown, instance)
|
||||
return
|
||||
}
|
||||
|
||||
// Dial failed — release the slot so the instance can be retried
|
||||
// after the backoff period.
|
||||
delete(d.active, instance)
|
||||
d.failures[instance]++
|
||||
backoff := d.baseBackoff * time.Duration(1<<(d.failures[instance]-1))
|
||||
if backoff > d.maxBackoff || backoff <= 0 {
|
||||
|
||||
Reference in New Issue
Block a user