add timer to fire track change event

This commit is contained in:
Drew Weymouth
2025-03-29 15:15:13 -07:00
parent 436df0f199
commit 417b1b262d
+98 -3
View File
@@ -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)
} }