show current player in casting menu, show error toasts on failures

This commit is contained in:
Drew Weymouth
2025-03-29 15:15:14 -07:00
parent 90ddfb87b8
commit 084aa6cdba
4 changed files with 62 additions and 19 deletions
+8 -2
View File
@@ -3,6 +3,7 @@ package backend
import (
"context"
"errors"
"fmt"
"log"
"math/rand"
"time"
@@ -14,6 +15,8 @@ import (
"github.com/dweymouth/supersonic/sharedutil"
)
// TODO: make thread-safe
var (
ReplayGainNone = player.ReplayGainNone.String()
ReplayGainAlbum = player.ReplayGainAlbum.String()
@@ -138,7 +141,7 @@ func (p *playbackEngine) registerPlayerCallbacks(pl player.BasePlayer) {
})
}
func (p *playbackEngine) SetPlayer(pl player.BasePlayer) {
func (p *playbackEngine) SetPlayer(pl player.BasePlayer) error {
needToUnpause := false
stat := p.PlayerStatus()
@@ -150,7 +153,9 @@ func (p *playbackEngine) SetPlayer(pl player.BasePlayer) {
case player.Stopped:
// nothing
case player.Playing:
p.Pause()
if err := p.Pause(); err != nil {
return fmt.Errorf("failed to pause: %v", err)
}
needToUnpause = true
fallthrough
case player.Paused:
@@ -179,6 +184,7 @@ func (p *playbackEngine) SetPlayer(pl player.BasePlayer) {
cb(vol)
}
}
return nil
}
func (p *playbackEngine) PlayTrackAt(idx int) error {
+24 -10
View File
@@ -26,17 +26,19 @@ type PlaybackManager struct {
cmdQueue *playbackCommandQueue
cfg *AppConfig
localPlayer player.BasePlayer
remotePlayersLock sync.Mutex
remotePlayers []remotePlayer
localPlayer player.BasePlayer
remotePlayersLock sync.Mutex
remotePlayers []RemotePlaybackDevice
currentRemotePlayer *RemotePlaybackDevice
autoplay bool
lastPlayTime float64
}
type remotePlayer struct {
type RemotePlaybackDevice struct {
Name string
URL string
Protocol string
new func() (player.BasePlayer, error)
}
@@ -107,10 +109,11 @@ func (p *PlaybackManager) ScanRemotePlayers(ctx context.Context, fastScan bool)
func (p *PlaybackManager) scanRemotePlayers(ctx context.Context, waitSec int) {
devices, _ := device.SearchMediaRenderers(ctx, waitSec, services.AVTransport, services.RenderingControl)
var discovered []remotePlayer
var discovered []RemotePlaybackDevice
for _, d := range devices {
p := remotePlayer{
p := RemotePlaybackDevice{
Name: d.FriendlyName,
URL: d.URL,
Protocol: "DLNA",
new: func() (player.BasePlayer, error) {
return dlna.NewDLNAPlayer(d)
@@ -124,16 +127,23 @@ func (p *PlaybackManager) scanRemotePlayers(ctx context.Context, waitSec int) {
p.remotePlayersLock.Unlock()
}
func (p *PlaybackManager) RemotePlayers() []remotePlayer {
func (p *PlaybackManager) RemotePlayers() []RemotePlaybackDevice {
p.remotePlayersLock.Lock()
players := p.remotePlayers
p.remotePlayersLock.Unlock()
return players
}
func (p *PlaybackManager) SetRemotePlayer(rp *remotePlayer) error {
func (p *PlaybackManager) CurrentRemotePlayer() *RemotePlaybackDevice {
return p.currentRemotePlayer
}
func (p *PlaybackManager) SetRemotePlayer(rp *RemotePlaybackDevice) error {
if rp == nil {
p.engine.SetPlayer(p.localPlayer)
if err := p.engine.SetPlayer(p.localPlayer); err != nil {
return err
}
p.currentRemotePlayer = nil
return nil
}
@@ -141,7 +151,11 @@ func (p *PlaybackManager) SetRemotePlayer(rp *remotePlayer) error {
if err != nil {
return err
}
p.engine.SetPlayer(player)
if err := p.engine.SetPlayer(player); err != nil {
return err
}
p.currentRemotePlayer = rp
return nil
}
+8
View File
@@ -99,6 +99,14 @@ func NewDLNAPlayer(device *device.MediaRenderer) (*DLNAPlayer, error) {
return nil, err
}
rc.HTTPClient = cli
// ping to test connectivity
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if _, err := avt.GetTransportInfo(ctx); err != nil {
return nil, fmt.Errorf("failed to connect to %s", device.FriendlyName)
}
return &DLNAPlayer{
avTransport: avt,
renderControl: rc,
+22 -7
View File
@@ -152,16 +152,31 @@ func (m *Controller) HaveModal() bool {
}
func (m *Controller) ShowCastMenu() {
rp := m.App.PlaybackManager.CurrentRemotePlayer()
devices := m.App.PlaybackManager.RemotePlayers()
menu := fyne.NewMenu("")
menu.Items = append(menu.Items, fyne.NewMenuItem(lang.L("Local player"), func() {
m.App.PlaybackManager.SetRemotePlayer(nil)
}))
local := fyne.NewMenuItem(lang.L("Local player"), func() {
go func() {
if err := m.App.PlaybackManager.SetRemotePlayer(nil); err != nil {
fyne.Do(func() { m.ToastProvider.ShowErrorToast("Failed to disconnect from remote player") })
}
}()
})
local.Icon = theme.ComputerIcon()
local.Checked = rp == nil
menu := fyne.NewMenu("", local)
for _, d := range devices {
_d := d
menu.Items = append(menu.Items, fyne.NewMenuItem(d.Name, func() {
m.App.PlaybackManager.SetRemotePlayer(&_d)
}))
item := fyne.NewMenuItem(d.Name, func() {
go func() {
if err := m.App.PlaybackManager.SetRemotePlayer(&_d); err != nil {
fyne.Do(func() { m.ToastProvider.ShowErrorToast("Failed to connect to " + _d.Name) })
}
}()
})
item.Icon = myTheme.CastIcon
item.Checked = rp != nil && _d.URL == rp.URL
menu.Items = append(menu.Items, item)
}
pop := widget.NewPopUpMenu(menu, m.MainWindow.Canvas())
canvasSize := m.MainWindow.Canvas().Size()