optional playlist runtime composition
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"mxl-player/internal/playback"
|
||||
)
|
||||
|
||||
const playlistReadinessInterval = 10 * time.Millisecond
|
||||
|
||||
var (
|
||||
ErrPlayerPlaybackRequired = errors.New("player playback is required")
|
||||
ErrPlayerSessionControllerRequired = errors.New("player session controller is required")
|
||||
ErrPlayerStatusStoreRequired = errors.New("player status store is required")
|
||||
)
|
||||
|
||||
type playerPlaylist struct {
|
||||
Controller *playback.PlaylistController
|
||||
Coordinator *playback.PlaylistReadinessCoordinator
|
||||
Commands chan playback.PlaylistCommand
|
||||
Readiness chan playback.PlaylistReadiness
|
||||
}
|
||||
|
||||
func newPlayerPlaylist(
|
||||
playlist playback.Playlist,
|
||||
retry playback.RetryPolicy,
|
||||
player *playerPlayback,
|
||||
) (*playerPlaylist, error) {
|
||||
if player == nil {
|
||||
return nil, ErrPlayerPlaybackRequired
|
||||
}
|
||||
if player.Controller == nil {
|
||||
return nil, ErrPlayerSessionControllerRequired
|
||||
}
|
||||
if player.Status == nil {
|
||||
return nil, ErrPlayerStatusStoreRequired
|
||||
}
|
||||
|
||||
commands := make(chan playback.PlaylistCommand, 32)
|
||||
readiness := make(chan playback.PlaylistReadiness, 8)
|
||||
controller, err := playback.NewPlaylistController(
|
||||
playlist,
|
||||
retry,
|
||||
player.Commands,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
coordinator, err := playback.NewPlaylistReadinessCoordinator(
|
||||
controller,
|
||||
player.Controller,
|
||||
player.Status,
|
||||
readiness,
|
||||
playlistReadinessInterval,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &playerPlaylist{
|
||||
Controller: controller,
|
||||
Coordinator: coordinator,
|
||||
Commands: commands,
|
||||
Readiness: readiness,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *playerPlaylist) Run(ctx context.Context) error {
|
||||
runCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
results := make(chan error, 2)
|
||||
go func() {
|
||||
results <- p.Controller.Run(runCtx, p.Commands, p.Readiness)
|
||||
}()
|
||||
go func() {
|
||||
results <- p.Coordinator.Run(runCtx)
|
||||
}()
|
||||
|
||||
first := <-results
|
||||
cancel()
|
||||
second := <-results
|
||||
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
if err := playlistRuntimeError(first); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := playlistRuntimeError(second); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *playerPlaylist) Select(index int) bool {
|
||||
return p.enqueue(playback.PlaylistCommand{
|
||||
Kind: playback.PlaylistSelect,
|
||||
Index: index,
|
||||
})
|
||||
}
|
||||
|
||||
func (p *playerPlaylist) Next() bool {
|
||||
return p.enqueue(playback.PlaylistCommand{Kind: playback.PlaylistNext})
|
||||
}
|
||||
|
||||
func (p *playerPlaylist) Previous() bool {
|
||||
return p.enqueue(playback.PlaylistCommand{Kind: playback.PlaylistPrevious})
|
||||
}
|
||||
|
||||
func (p *playerPlaylist) enqueue(command playback.PlaylistCommand) bool {
|
||||
select {
|
||||
case p.Commands <- command:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func playlistRuntimeError(err error) error {
|
||||
if err == nil || errors.Is(err, context.Canceled) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user