show current player in casting menu, show error toasts on failures
This commit is contained in:
@@ -3,6 +3,7 @@ package backend
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
@@ -14,6 +15,8 @@ import (
|
|||||||
"github.com/dweymouth/supersonic/sharedutil"
|
"github.com/dweymouth/supersonic/sharedutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: make thread-safe
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ReplayGainNone = player.ReplayGainNone.String()
|
ReplayGainNone = player.ReplayGainNone.String()
|
||||||
ReplayGainAlbum = player.ReplayGainAlbum.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
|
needToUnpause := false
|
||||||
|
|
||||||
stat := p.PlayerStatus()
|
stat := p.PlayerStatus()
|
||||||
@@ -150,7 +153,9 @@ func (p *playbackEngine) SetPlayer(pl player.BasePlayer) {
|
|||||||
case player.Stopped:
|
case player.Stopped:
|
||||||
// nothing
|
// nothing
|
||||||
case player.Playing:
|
case player.Playing:
|
||||||
p.Pause()
|
if err := p.Pause(); err != nil {
|
||||||
|
return fmt.Errorf("failed to pause: %v", err)
|
||||||
|
}
|
||||||
needToUnpause = true
|
needToUnpause = true
|
||||||
fallthrough
|
fallthrough
|
||||||
case player.Paused:
|
case player.Paused:
|
||||||
@@ -179,6 +184,7 @@ func (p *playbackEngine) SetPlayer(pl player.BasePlayer) {
|
|||||||
cb(vol)
|
cb(vol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *playbackEngine) PlayTrackAt(idx int) error {
|
func (p *playbackEngine) PlayTrackAt(idx int) error {
|
||||||
|
|||||||
+24
-10
@@ -26,17 +26,19 @@ type PlaybackManager struct {
|
|||||||
cmdQueue *playbackCommandQueue
|
cmdQueue *playbackCommandQueue
|
||||||
cfg *AppConfig
|
cfg *AppConfig
|
||||||
|
|
||||||
localPlayer player.BasePlayer
|
localPlayer player.BasePlayer
|
||||||
remotePlayersLock sync.Mutex
|
remotePlayersLock sync.Mutex
|
||||||
remotePlayers []remotePlayer
|
remotePlayers []RemotePlaybackDevice
|
||||||
|
currentRemotePlayer *RemotePlaybackDevice
|
||||||
|
|
||||||
autoplay bool
|
autoplay bool
|
||||||
|
|
||||||
lastPlayTime float64
|
lastPlayTime float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type remotePlayer struct {
|
type RemotePlaybackDevice struct {
|
||||||
Name string
|
Name string
|
||||||
|
URL string
|
||||||
Protocol string
|
Protocol string
|
||||||
new func() (player.BasePlayer, error)
|
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) {
|
func (p *PlaybackManager) scanRemotePlayers(ctx context.Context, waitSec int) {
|
||||||
devices, _ := device.SearchMediaRenderers(ctx, waitSec, services.AVTransport, services.RenderingControl)
|
devices, _ := device.SearchMediaRenderers(ctx, waitSec, services.AVTransport, services.RenderingControl)
|
||||||
|
|
||||||
var discovered []remotePlayer
|
var discovered []RemotePlaybackDevice
|
||||||
for _, d := range devices {
|
for _, d := range devices {
|
||||||
p := remotePlayer{
|
p := RemotePlaybackDevice{
|
||||||
Name: d.FriendlyName,
|
Name: d.FriendlyName,
|
||||||
|
URL: d.URL,
|
||||||
Protocol: "DLNA",
|
Protocol: "DLNA",
|
||||||
new: func() (player.BasePlayer, error) {
|
new: func() (player.BasePlayer, error) {
|
||||||
return dlna.NewDLNAPlayer(d)
|
return dlna.NewDLNAPlayer(d)
|
||||||
@@ -124,16 +127,23 @@ func (p *PlaybackManager) scanRemotePlayers(ctx context.Context, waitSec int) {
|
|||||||
p.remotePlayersLock.Unlock()
|
p.remotePlayersLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PlaybackManager) RemotePlayers() []remotePlayer {
|
func (p *PlaybackManager) RemotePlayers() []RemotePlaybackDevice {
|
||||||
p.remotePlayersLock.Lock()
|
p.remotePlayersLock.Lock()
|
||||||
players := p.remotePlayers
|
players := p.remotePlayers
|
||||||
p.remotePlayersLock.Unlock()
|
p.remotePlayersLock.Unlock()
|
||||||
return players
|
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 {
|
if rp == nil {
|
||||||
p.engine.SetPlayer(p.localPlayer)
|
if err := p.engine.SetPlayer(p.localPlayer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.currentRemotePlayer = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +151,11 @@ func (p *PlaybackManager) SetRemotePlayer(rp *remotePlayer) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.engine.SetPlayer(player)
|
if err := p.engine.SetPlayer(player); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.currentRemotePlayer = rp
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,14 @@ func NewDLNAPlayer(device *device.MediaRenderer) (*DLNAPlayer, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rc.HTTPClient = cli
|
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{
|
return &DLNAPlayer{
|
||||||
avTransport: avt,
|
avTransport: avt,
|
||||||
renderControl: rc,
|
renderControl: rc,
|
||||||
|
|||||||
@@ -152,16 +152,31 @@ func (m *Controller) HaveModal() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Controller) ShowCastMenu() {
|
func (m *Controller) ShowCastMenu() {
|
||||||
|
rp := m.App.PlaybackManager.CurrentRemotePlayer()
|
||||||
devices := m.App.PlaybackManager.RemotePlayers()
|
devices := m.App.PlaybackManager.RemotePlayers()
|
||||||
menu := fyne.NewMenu("")
|
local := fyne.NewMenuItem(lang.L("Local player"), func() {
|
||||||
menu.Items = append(menu.Items, fyne.NewMenuItem(lang.L("Local player"), func() {
|
go func() {
|
||||||
m.App.PlaybackManager.SetRemotePlayer(nil)
|
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 {
|
for _, d := range devices {
|
||||||
_d := d
|
_d := d
|
||||||
menu.Items = append(menu.Items, fyne.NewMenuItem(d.Name, func() {
|
item := fyne.NewMenuItem(d.Name, func() {
|
||||||
m.App.PlaybackManager.SetRemotePlayer(&_d)
|
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())
|
pop := widget.NewPopUpMenu(menu, m.MainWindow.Canvas())
|
||||||
canvasSize := m.MainWindow.Canvas().Size()
|
canvasSize := m.MainWindow.Canvas().Size()
|
||||||
|
|||||||
Reference in New Issue
Block a user