diff --git a/backend/playbackengine.go b/backend/playbackengine.go index ecd7719..9ae9a5d 100644 --- a/backend/playbackengine.go +++ b/backend/playbackengine.go @@ -9,6 +9,7 @@ import ( "github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/player" + "github.com/dweymouth/supersonic/backend/player/mpv" "github.com/dweymouth/supersonic/backend/util" "github.com/dweymouth/supersonic/sharedutil" ) @@ -154,6 +155,9 @@ func (p *playbackEngine) SetPlayer(pl player.BasePlayer) { } oldVol := p.player.GetVolume() + if _, isMPV := p.player.(*mpv.Player); !isMPV { + p.player.Destroy() + } p.player = pl p.registerPlayerCallbacks(pl) diff --git a/backend/player/dlna/dlnaplayer.go b/backend/player/dlna/dlnaplayer.go index b013a29..b9410ac 100644 --- a/backend/player/dlna/dlnaplayer.go +++ b/backend/player/dlna/dlnaplayer.go @@ -197,6 +197,12 @@ func (d *DLNAPlayer) GetStatus() player.Status { } } +func (d *DLNAPlayer) Destroy() { + if d.proxyServer != nil { + go d.proxyServer.Shutdown(context.Background()) + } +} + func getLocalIP() (string, error) { interfaces, err := net.Interfaces() if err != nil { diff --git a/backend/player/jukebox/jukeboxplayer.go b/backend/player/jukebox/jukeboxplayer.go index 3518beb..c3db780 100644 --- a/backend/player/jukebox/jukeboxplayer.go +++ b/backend/player/jukebox/jukeboxplayer.go @@ -140,6 +140,8 @@ func (j *JukeboxPlayer) GetStatus() player.Status { } } +func (j *JukeboxPlayer) Destroy() {} + func (j *JukeboxPlayer) startAndUpdateTime() error { beforeStart := time.Now() if err := j.provider.JukeboxStart(); err != nil { diff --git a/backend/player/player.go b/backend/player/player.go index eb855cc..9c941a5 100644 --- a/backend/player/player.go +++ b/backend/player/player.go @@ -27,6 +27,8 @@ type BasePlayer interface { GetStatus() Status + Destroy() + // Event API OnPaused(func()) OnStopped(func()) diff --git a/ui/widgets/auxcontrols.go b/ui/widgets/auxcontrols.go index 94b4ff4..bb50172 100644 --- a/ui/widgets/auxcontrols.go +++ b/ui/widgets/auxcontrols.go @@ -2,6 +2,7 @@ package widgets import ( "math" + "time" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" @@ -163,6 +164,10 @@ type VolumeControl struct { muted bool lastVol int + setVolDebouncer func() + delaySetVolume bool + pendingVolume int + container *fyne.Container } @@ -178,6 +183,15 @@ func NewVolumeControl(initialVol int) *VolumeControl { v.slider.Orientation = widget.Horizontal v.slider.Value = float64(v.lastVol) v.slider.OnChanged = v.onChanged + + // for players that are slow to respond to volume changes + // (e.g. DLNA), delay responding to the SetVolume call + // to avoid hiccuping from callback "echoes" + v.setVolDebouncer = util.NewDebouncer(100*time.Millisecond, func() { + v.delaySetVolume = false + v.SetVolume(v.pendingVolume) + }) + v.container = container.NewHBox(container.NewCenter(v.icon), v.slider) return v } @@ -185,6 +199,11 @@ func NewVolumeControl(initialVol int) *VolumeControl { // Sets the volume that is displayed in the slider. // Does not invoke OnSetVolume callback. func (v *VolumeControl) SetVolume(vol int) { + if v.delaySetVolume { + v.pendingVolume = vol + return + } + if (vol == v.lastVol && !v.muted) || (v.muted && vol == 0) { return } @@ -195,6 +214,8 @@ func (v *VolumeControl) SetVolume(vol int) { func (v *VolumeControl) onChanged(volume float64) { vol := int(volume) + v.delaySetVolume = true + v.setVolDebouncer() v.lastVol = vol v.muted = false v.updateIconForVolume(vol)