add audio slot lifecycle

This commit is contained in:
Dmitry Sergeev
2026-08-27 23:59:48 +03:00
parent bf062afd16
commit d4041af119
2 changed files with 295 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
package playback
import (
"context"
"errors"
"fmt"
)
var ErrAudioWorkerRequired = errors.New("audio worker is required")
type AudioSlot struct {
worker *AudioWorker
}
func NewAudioSlot(worker *AudioWorker) (*AudioSlot, error) {
if worker == nil {
return nil, ErrAudioWorkerRequired
}
return &AudioSlot{worker: worker}, nil
}
func (s *AudioSlot) Run(
ctx context.Context,
initial FeedConfig,
commands <-chan FeedConfig,
) error {
if err := initial.Validate(); err != nil {
return fmt.Errorf("validate initial audio config: %w", err)
}
var (
workerCancel context.CancelFunc
workerDone chan error
)
start := func(config FeedConfig) {
workerCtx, cancel := context.WithCancel(ctx)
done := make(chan error, 1)
workerCancel = cancel
workerDone = done
go func() {
done <- s.worker.Run(workerCtx, config)
}()
}
stop := func() {
if workerCancel == nil {
return
}
workerCancel()
<-workerDone
workerCancel = nil
workerDone = nil
}
if initial.Active {
start(initial)
}
for {
select {
case <-ctx.Done():
stop()
return ctx.Err()
case config, ok := <-commands:
if !ok {
stop()
return nil
}
if err := config.Validate(); err != nil {
// Ignore invalid commands without disturbing the current worker.
continue
}
stop()
if config.Active {
start(config)
}
case <-workerDone:
// The worker stopped naturally or exhausted its retries.
workerCancel()
workerCancel = nil
workerDone = nil
}
}
}