161 lines
3.0 KiB
Go
161 lines
3.0 KiB
Go
package jukebox
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
|
"github.com/dweymouth/supersonic/backend/player"
|
|
)
|
|
|
|
const (
|
|
stopped = 0
|
|
playing = 1
|
|
paused = 2
|
|
)
|
|
|
|
type JukeboxPlayer struct {
|
|
player.BasePlayerCallbackImpl
|
|
|
|
provider mediaprovider.JukeboxProvider
|
|
|
|
state int // stopped, playing, paused
|
|
volume int
|
|
seeking bool
|
|
|
|
curTrack int
|
|
queueLength int
|
|
curTrackDuration float64
|
|
startTrackTime float64
|
|
startedAtUnixMilli int64
|
|
nextTrackTimer *time.Timer
|
|
}
|
|
|
|
func (j *JukeboxPlayer) SetVolume(vol int) error {
|
|
if err := j.provider.JukeboxSetVolume(vol); err != nil {
|
|
return err
|
|
}
|
|
j.volume = vol
|
|
return nil
|
|
}
|
|
|
|
func (j *JukeboxPlayer) GetVolume() int {
|
|
return j.volume
|
|
}
|
|
|
|
func (j *JukeboxPlayer) Continue() error {
|
|
if j.state == playing {
|
|
return nil
|
|
}
|
|
if err := j.startAndUpdateTime(); err != nil {
|
|
return err
|
|
}
|
|
|
|
j.state = playing
|
|
j.InvokeOnPlaying()
|
|
return nil
|
|
}
|
|
|
|
func (j *JukeboxPlayer) Pause() error {
|
|
if j.state != playing {
|
|
return nil
|
|
}
|
|
if err := j.provider.JukeboxStop(); err != nil {
|
|
return err
|
|
}
|
|
// TODO: calculate paused at time
|
|
j.state = paused
|
|
j.InvokeOnPaused()
|
|
return nil
|
|
}
|
|
|
|
func (j *JukeboxPlayer) Stop() error {
|
|
if j.state == stopped {
|
|
return nil
|
|
}
|
|
if err := j.provider.JukeboxStop(); err != nil {
|
|
return err
|
|
}
|
|
j.state = stopped
|
|
j.InvokeOnStopped()
|
|
return nil
|
|
}
|
|
|
|
func (j *JukeboxPlayer) PlayTrack(track *mediaprovider.Track) error {
|
|
if err := j.provider.JukeboxSet(track.ID); err != nil {
|
|
return err
|
|
}
|
|
j.startTrackTime = 0
|
|
if err := j.startAndUpdateTime(); err != nil {
|
|
return err
|
|
}
|
|
|
|
j.curTrack = 0
|
|
j.queueLength = 1
|
|
j.curTrackDuration = float64(track.Duration)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (j *JukeboxPlayer) SetNextTrack(track *mediaprovider.Track) error {
|
|
// we need to replace the last track in the queue, remove it first
|
|
if j.curTrack < j.queueLength-1 {
|
|
if err := j.provider.JukeboxRemove(j.curTrack + 1); err != nil {
|
|
return err
|
|
}
|
|
j.queueLength -= 1
|
|
}
|
|
// append the new track to the queue
|
|
if err := j.provider.JukeboxAdd(track.ID); err != nil {
|
|
return err
|
|
}
|
|
j.queueLength += 1
|
|
return nil
|
|
|
|
}
|
|
|
|
func (j *JukeboxPlayer) SeekSeconds(secs float64) error {
|
|
j.seeking = true
|
|
err := j.provider.JukeboxSeek(j.curTrack, int(secs))
|
|
j.seeking = false
|
|
j.InvokeOnSeek()
|
|
return err
|
|
}
|
|
|
|
func (j *JukeboxPlayer) IsSeeking() bool {
|
|
return j.seeking
|
|
}
|
|
|
|
func (j *JukeboxPlayer) GetStatus() player.Status {
|
|
state := player.Stopped
|
|
if j.state == playing {
|
|
state = player.Playing
|
|
} else if j.state == paused {
|
|
state = player.Paused
|
|
}
|
|
|
|
// TODO - the rest
|
|
|
|
return player.Status{
|
|
State: state,
|
|
}
|
|
}
|
|
|
|
func (j *JukeboxPlayer) Destroy() {}
|
|
|
|
func (j *JukeboxPlayer) startAndUpdateTime() error {
|
|
beforeStart := time.Now()
|
|
if err := j.provider.JukeboxStart(); err != nil {
|
|
return err
|
|
}
|
|
afterStart := time.Now()
|
|
|
|
// assume track started playing at (ie has been playing for)
|
|
// half the round-trip latency
|
|
j.startedAtUnixMilli = time.Now().Add(-afterStart.Sub(beforeStart)).UnixMilli()
|
|
return nil
|
|
}
|
|
|
|
func (j *JukeboxPlayer) handleNextTrack() {
|
|
|
|
}
|