add timer to fire track change event
This commit is contained in:
@@ -41,6 +41,7 @@ type DLNAPlayer struct {
|
|||||||
state int // stopped, playing, paused
|
state int // stopped, playing, paused
|
||||||
seeking bool
|
seeking bool
|
||||||
|
|
||||||
|
metaLock sync.Mutex
|
||||||
curTrackMeta mediaprovider.MediaItemMetadata
|
curTrackMeta mediaprovider.MediaItemMetadata
|
||||||
nextTrackMeta mediaprovider.MediaItemMetadata
|
nextTrackMeta mediaprovider.MediaItemMetadata
|
||||||
|
|
||||||
@@ -54,6 +55,10 @@ type DLNAPlayer struct {
|
|||||||
|
|
||||||
proxyURLLock sync.Mutex
|
proxyURLLock sync.Mutex
|
||||||
proxyURLs map[string]string
|
proxyURLs map[string]string
|
||||||
|
|
||||||
|
timerActive atomic.Bool
|
||||||
|
timer *time.Timer
|
||||||
|
resetChan chan (time.Duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDLNAPlayer(device *device.MediaRenderer) (*DLNAPlayer, error) {
|
func NewDLNAPlayer(device *device.MediaRenderer) (*DLNAPlayer, error) {
|
||||||
@@ -69,6 +74,7 @@ func NewDLNAPlayer(device *device.MediaRenderer) (*DLNAPlayer, error) {
|
|||||||
avTransport: avt,
|
avTransport: avt,
|
||||||
renderControl: rc,
|
renderControl: rc,
|
||||||
proxyURLs: make(map[string]string),
|
proxyURLs: make(map[string]string),
|
||||||
|
resetChan: make(chan time.Duration),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +92,9 @@ func (d *DLNAPlayer) PlayFile(urlstr string, meta mediaprovider.MediaItemMetadat
|
|||||||
|
|
||||||
log.Println("playing track " + meta.Name)
|
log.Println("playing track " + meta.Name)
|
||||||
|
|
||||||
|
d.metaLock.Lock()
|
||||||
d.curTrackMeta = meta
|
d.curTrackMeta = meta
|
||||||
|
d.metaLock.Unlock()
|
||||||
key := d.addURLToProxy(urlstr)
|
key := d.addURLToProxy(urlstr)
|
||||||
|
|
||||||
media := avtransport.MediaItem{
|
media := avtransport.MediaItem{
|
||||||
@@ -102,6 +110,7 @@ func (d *DLNAPlayer) PlayFile(urlstr string, meta mediaprovider.MediaItemMetadat
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.state = playing
|
d.state = playing
|
||||||
|
d.setTrackChangeTimer(time.Duration(meta.Duration) * time.Second)
|
||||||
d.stopwatch.Reset()
|
d.stopwatch.Reset()
|
||||||
d.stopwatch.Start()
|
d.stopwatch.Start()
|
||||||
d.lastStartTime = 0
|
d.lastStartTime = 0
|
||||||
@@ -112,7 +121,9 @@ func (d *DLNAPlayer) PlayFile(urlstr string, meta mediaprovider.MediaItemMetadat
|
|||||||
|
|
||||||
func (d *DLNAPlayer) SetNextFile(url string, meta mediaprovider.MediaItemMetadata) error {
|
func (d *DLNAPlayer) SetNextFile(url string, meta mediaprovider.MediaItemMetadata) error {
|
||||||
var media *avtransport.MediaItem
|
var media *avtransport.MediaItem
|
||||||
|
d.metaLock.Lock()
|
||||||
d.nextTrackMeta = meta
|
d.nextTrackMeta = meta
|
||||||
|
d.metaLock.Unlock()
|
||||||
if url != "" {
|
if url != "" {
|
||||||
d.ensureSetupProxy()
|
d.ensureSetupProxy()
|
||||||
|
|
||||||
@@ -129,7 +140,11 @@ func (d *DLNAPlayer) Continue() error {
|
|||||||
if err := d.avTransport.Play(context.Background()); err != nil {
|
if err := d.avTransport.Play(context.Background()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
d.metaLock.Lock()
|
||||||
|
nextTrackChange := time.Duration(d.curTrackMeta.Duration)*time.Second - d.curPlayPos()
|
||||||
|
d.metaLock.Unlock()
|
||||||
d.state = playing
|
d.state = playing
|
||||||
|
d.setTrackChangeTimer(nextTrackChange)
|
||||||
d.stopwatch.Start()
|
d.stopwatch.Start()
|
||||||
d.InvokeOnPlaying()
|
d.InvokeOnPlaying()
|
||||||
return nil
|
return nil
|
||||||
@@ -139,6 +154,7 @@ func (d *DLNAPlayer) Pause() error {
|
|||||||
if err := d.avTransport.Pause(context.Background()); err != nil {
|
if err := d.avTransport.Pause(context.Background()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
d.setTrackChangeTimer(0)
|
||||||
d.stopwatch.Stop()
|
d.stopwatch.Stop()
|
||||||
d.state = paused
|
d.state = paused
|
||||||
d.InvokeOnPaused()
|
d.InvokeOnPaused()
|
||||||
@@ -149,6 +165,7 @@ func (d *DLNAPlayer) Stop() error {
|
|||||||
if err := d.avTransport.Pause(context.Background()); err != nil {
|
if err := d.avTransport.Pause(context.Background()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
d.setTrackChangeTimer(0)
|
||||||
d.stopwatch.Reset()
|
d.stopwatch.Reset()
|
||||||
d.lastStartTime = 0
|
d.lastStartTime = 0
|
||||||
d.state = stopped
|
d.state = stopped
|
||||||
@@ -164,6 +181,10 @@ func (d *DLNAPlayer) SeekSeconds(secs float64) error {
|
|||||||
}
|
}
|
||||||
d.seeking = false
|
d.seeking = false
|
||||||
|
|
||||||
|
d.metaLock.Lock()
|
||||||
|
nextTrackChange := time.Duration(d.curTrackMeta.Duration)*time.Second - time.Duration(secs)*time.Second
|
||||||
|
d.metaLock.Unlock()
|
||||||
|
d.setTrackChangeTimer(nextTrackChange)
|
||||||
d.lastStartTime = int(secs)
|
d.lastStartTime = int(secs)
|
||||||
d.stopwatch.Reset()
|
d.stopwatch.Reset()
|
||||||
if d.state == playing {
|
if d.state == playing {
|
||||||
@@ -186,15 +207,17 @@ func (d *DLNAPlayer) GetStatus() player.Status {
|
|||||||
state = player.Paused
|
state = player.Paused
|
||||||
}
|
}
|
||||||
|
|
||||||
time := time.Duration(d.lastStartTime)*time.Second + d.stopwatch.Elapsed()
|
|
||||||
|
|
||||||
return player.Status{
|
return player.Status{
|
||||||
State: state,
|
State: state,
|
||||||
TimePos: time.Seconds(),
|
TimePos: d.curPlayPos().Seconds(),
|
||||||
Duration: float64(d.curTrackMeta.Duration),
|
Duration: float64(d.curTrackMeta.Duration),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DLNAPlayer) curPlayPos() time.Duration {
|
||||||
|
return time.Duration(d.lastStartTime)*time.Second + d.stopwatch.Elapsed()
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DLNAPlayer) Destroy() {
|
func (d *DLNAPlayer) Destroy() {
|
||||||
if d.proxyServer != nil {
|
if d.proxyServer != nil {
|
||||||
go d.proxyServer.Shutdown(context.Background())
|
go d.proxyServer.Shutdown(context.Background())
|
||||||
@@ -235,6 +258,78 @@ func (d *DLNAPlayer) addURLToProxy(url string) string {
|
|||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DLNAPlayer) setTrackChangeTimer(dur time.Duration) {
|
||||||
|
if d.timerActive.Swap(true) {
|
||||||
|
// was active
|
||||||
|
log.Println("timer was active")
|
||||||
|
d.resetChan <- dur
|
||||||
|
log.Println("and reset")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if dur == 0 {
|
||||||
|
d.timerActive.Store(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("starting timer")
|
||||||
|
|
||||||
|
d.timer = time.NewTimer(dur)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case dur := <-d.resetChan:
|
||||||
|
if dur == 0 {
|
||||||
|
d.timerActive.Store(false)
|
||||||
|
if !d.timer.Stop() {
|
||||||
|
select {
|
||||||
|
case <-d.timer.C:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.timer = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// reset the timer
|
||||||
|
if !d.timer.Stop() {
|
||||||
|
select {
|
||||||
|
case <-d.timer.C:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.timer.Reset(dur)
|
||||||
|
case <-d.timer.C:
|
||||||
|
d.timerActive.Store(false)
|
||||||
|
d.timer = nil
|
||||||
|
d.handleOnTrackChange()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DLNAPlayer) handleOnTrackChange() {
|
||||||
|
stopping := false
|
||||||
|
d.metaLock.Lock()
|
||||||
|
if d.nextTrackMeta.ID == "" {
|
||||||
|
stopping = true
|
||||||
|
}
|
||||||
|
d.curTrackMeta = d.nextTrackMeta
|
||||||
|
d.nextTrackMeta = mediaprovider.MediaItemMetadata{}
|
||||||
|
nextTrackChange := time.Duration(d.curTrackMeta.Duration) * time.Second
|
||||||
|
d.metaLock.Unlock()
|
||||||
|
|
||||||
|
if stopping {
|
||||||
|
d.lastStartTime = 0
|
||||||
|
d.stopwatch.Reset()
|
||||||
|
d.InvokeOnStopped()
|
||||||
|
} else {
|
||||||
|
d.lastStartTime = 0
|
||||||
|
d.stopwatch.Reset()
|
||||||
|
d.stopwatch.Start()
|
||||||
|
d.setTrackChangeTimer(nextTrackChange)
|
||||||
|
d.InvokeOnTrackChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DLNAPlayer) urlForItem(key string) string {
|
func (d *DLNAPlayer) urlForItem(key string) string {
|
||||||
return fmt.Sprintf("http://%s:%d/%s", d.localIP, d.proxyPort, key)
|
return fmt.Sprintf("http://%s:%d/%s", d.localIP, d.proxyPort, key)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user