package playback import ( "context" "errors" "fmt" ) type audioSinkError struct { err error } func (e *audioSinkError) Error() string { return fmt.Sprintf("consume audio: %v", e.err) } func (e *audioSinkError) Unwrap() error { return e.err } func runAudioAttempt( ctx context.Context, factory AudioReaderFactory, sink AudioSink, config FeedConfig, ) (resultErr error) { reader, err := factory.OpenAudio(ctx, config) if err != nil { return fmt.Errorf("open audio: %w", err) } defer func() { if closeErr := reader.Close(); closeErr != nil { closeErr = fmt.Errorf("close audio: %w", closeErr) resultErr = errors.Join(resultErr, closeErr) } }() for { frame, err := reader.ReadAudio(ctx) if err != nil { if ctx.Err() != nil { return ctx.Err() } return fmt.Errorf("read audio: %w", err) } if err := sink.ConsumeAudio(ctx, frame); err != nil { if ctx.Err() != nil { return ctx.Err() } return &audioSinkError{err: err} } } }