Beginning of reworked PlaybackManager - PARTIAL

This commit is contained in:
Drew Weymouth
2023-12-22 15:50:39 -08:00
parent 0cd58cb51b
commit d9eca8d807
3 changed files with 93 additions and 219 deletions
+18 -129
View File
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"log"
"math"
"strconv"
@@ -58,9 +57,9 @@ type Player struct {
haveRGainOpts bool
audioExclusive bool
status player.Status
loopMode player.LoopMode
seeking bool
curPlaylistPos int64
lenPlaylist int64
prePausedState player.State
clientName string
equalizer Equalizer
@@ -72,7 +71,7 @@ type Player struct {
onStopped []func()
onPlaying []func()
onSeek []func()
onTrackChange []func(int)
onTrackChange []func()
}
// Returns a new player.
@@ -133,38 +132,19 @@ func (p *Player) Init(maxCacheMB int) error {
return nil
}
// Appends the given file to the play queue.
// Note that the Player API does not provide methods to read
// the play queue. Clients are expected to maintain their own play queue model.
func (p *Player) AppendFile(url string) error {
log.Printf("Adding playback URL: %s", url)
if !p.initialized {
return ErrUnitialized
}
return p.mpv.Command([]string{"loadfile", url, "append"})
}
// Plays the specified file, clearing the previous play queue, if any.
func (p *Player) PlayFile(url string) error {
log.Printf("Adding playback URL: %s", url)
if !p.initialized {
return ErrUnitialized
}
err := p.mpv.Command([]string{"loadfile", url, "replace"})
if err == nil {
p.setState(player.Playing)
p.lenPlaylist = 1
}
return err
}
// Removes the item at the given index from the internal playqueue.
func (p *Player) RemoveTrackAt(idx int) error {
if !p.initialized {
return ErrUnitialized
}
return p.mpv.Command([]string{"playlist-remove", strconv.Itoa(idx)})
}
// Stops playback and clears the play queue.
func (p *Player) Stop() error {
if !p.initialized {
@@ -180,30 +160,24 @@ func (p *Player) Stop() error {
}
}
if err == nil {
p.lenPlaylist = 0
p.setState(player.Stopped)
}
return err
}
// Clears the play queue, except for the currently playing file.
func (p *Player) ClearPlayQueue() error {
if !p.initialized {
return ErrUnitialized
func (p *Player) SetNextFile(url string) error {
if p.lenPlaylist > p.curPlaylistPos+1 {
if err := p.mpv.Command([]string{"playlist-remove", strconv.Itoa(int(p.curPlaylistPos) + 1)}); err != nil {
return err
}
p.lenPlaylist--
}
return p.mpv.Command([]string{"playlist-clear"})
}
func (p *Player) SetFile(url string) error {
if !p.initialized {
return ErrUnitialized
err := p.mpv.Command([]string{"loadfile", url, "append"})
if err == nil {
p.lenPlaylist++
}
if err := p.mpv.Command([]string{"stop"}); err != nil {
return err
}
if err := p.mpv.Command([]string{"playlist-clear"}); err != nil {
return err
}
return p.mpv.Command([]string{"loadfile", url, "append"})
return err
}
// Seeks within the currently playing track.
@@ -218,27 +192,6 @@ func (p *Player) SeekSeconds(secs float64) error {
return err
}
// Seeks to the beginning of the previous track,
// or if no previous track, seeks to the beginning of the current track.
func (p *Player) SeekPrevious() error {
if !p.initialized {
return ErrUnitialized
}
if pos, err := p.getInt64Property("playlist-pos"); err == nil && pos == 0 {
return p.SeekSeconds(0)
}
return p.mpv.Command([]string{"playlist-prev"})
}
// Seeks to the next track in the play queue, if any.
func (p *Player) SeekNext() error {
if !p.initialized {
return ErrUnitialized
}
return p.mpv.Command([]string{"playlist-next"})
}
// Sets the volume of the player (0-100).
// Unlike most Player functions, SetVolume can be called before Init,
// to set the initial volume of the player on startup.
@@ -325,22 +278,6 @@ func (p *Player) setPaused(paused bool) error {
return err
}
// Start playback from the specified track index in the play queue.
func (p *Player) PlayTrackAt(idx int) error {
// check if we have anything to play
if c, err := p.getInt64Property("playlist-count"); err == nil && c <= int64(idx) {
return nil
}
err := p.mpv.Command([]string{"playlist-play-index", strconv.Itoa(idx)})
if p.GetStatus().State == player.Paused {
err = p.setPaused(false)
}
if err == nil {
p.setState(player.Playing)
}
return err
}
// Pause playback and update the player state
func (p *Player) Pause() error {
if p.status.State != player.Playing {
@@ -362,57 +299,11 @@ func (p *Player) Continue() error {
p.setState(p.prePausedState)
}
return err
} else if p.status.State == player.Stopped {
return p.PlayTrackAt(0)
}
return nil
}
// Get the loop mode of the player.
func (p *Player) GetLoopMode() player.LoopMode {
return p.loopMode
}
// Set the loop mode of the player.
func (p *Player) SetLoopMode(mode player.LoopMode) error {
if !p.initialized {
return ErrUnitialized
}
// Return early if player is already in specified mode
if mode == p.loopMode {
return nil
}
switch mode {
case player.LoopNone:
if err := p.mpv.SetOptionString("loop-playlist", "no"); err != nil {
return err
}
if err := p.mpv.SetOptionString("loop-file", "no"); err != nil {
return err
}
case player.LoopAll:
if err := p.mpv.SetOptionString("loop-playlist", "inf"); err != nil {
return err
}
if err := p.mpv.SetOptionString("loop-file", "no"); err != nil {
return err
}
case player.LoopOne:
if err := p.mpv.SetOptionString("loop-playlist", "no"); err != nil {
return err
}
if err := p.mpv.SetOptionString("loop-file", "inf"); err != nil {
return err
}
}
p.loopMode = mode
return nil
}
// Get the current status of the player.
func (p *Player) GetStatus() player.Status {
if !p.initialized {
@@ -539,7 +430,7 @@ func (p *Player) OnSeek(cb func()) {
// Registers a callback which is invoked when the currently playing track changes,
// or when playback begins at any time from the Stopped state.
// Callback is invoked with the index of the currently playing track (zero-based).
func (p *Player) OnTrackChange(cb func(int)) {
func (p *Player) OnTrackChange(cb func()) {
p.onTrackChange = append(p.onTrackChange, cb)
}
@@ -600,6 +491,7 @@ func (p *Player) eventHandler(ctx context.Context) {
cb()
}
case mpv.EVENT_FILE_LOADED:
p.curPlaylistPos, _ = p.getInt64Property("playlist-pos")
if p.status.State == player.Paused {
// seek while paused switches to a new file
// mpv does not fire seek event in this case
@@ -607,11 +499,8 @@ func (p *Player) eventHandler(ctx context.Context) {
cb()
}
}
if pos, err := p.getInt64Property("playlist-pos"); err == nil {
p.curPlaylistPos = pos
for _, cb := range p.onTrackChange {
cb(int(pos))
}
for _, cb := range p.onTrackChange {
cb()
}
case mpv.EVENT_IDLE:
p.status.Duration = 0
+4 -44
View File
@@ -4,57 +4,17 @@ import "github.com/dweymouth/supersonic/backend/mediaprovider"
type URLPlayer interface {
BasePlayer
AppendFile(url string) error
}
type URLPlayerNew interface {
BasePlayer
SetFile(url string)
SetNextFile(url string)
PlayFile(url string) error
SetNextFile(url string) error
}
type TrackPlayer interface {
BasePlayer
AppendTrack(track *mediaprovider.Track) error
}
type TrackPlayerNew interface {
BasePlayer
SetTrack(track *mediaprovider.Track) error
PlayTrack(track *mediaprovider.Track) error
SetNextTrack(track *mediaprovider.Track) error
}
type BasePlayer interface {
// Transport
PlayTrackAt(idx int) error
Continue() error
Pause() error
Stop() error
SeekPrevious() error
SeekNext() error
SeekSeconds(secs float64) error
IsSeeking() bool
SetVolume(int) error
GetVolume() int
GetStatus() Status
ClearPlayQueue() error
RemoveTrackAt(idx int) error
SetLoopMode(LoopMode) error
GetLoopMode() LoopMode
// Event API
OnPaused(func())
OnStopped(func())
OnPlaying(func())
OnSeek(func())
OnTrackChange(func(int))
}
type BasePlayerNew interface {
Continue() error
Pause() error
Stop() error
@@ -72,7 +32,7 @@ type BasePlayerNew interface {
OnStopped(func())
OnPlaying(func())
OnSeek(func())
OnTrackChange(func(int))
OnTrackChange(func())
}
type ReplayGainPlayer interface {