diff --git a/core/playback/device.go b/core/playback/device.go index 358985ffffe..d7c7355f015 100644 --- a/core/playback/device.go +++ b/core/playback/device.go @@ -24,7 +24,6 @@ type PlaybackDevice struct { Default bool User string Name string - Method string DeviceName string PlaybackQueue *Queue Gain float32 @@ -60,12 +59,11 @@ func (pd *PlaybackDevice) getStatus() DeviceStatus { // NewPlaybackDevice creates a new playback device which implements all the basic Jukebox mode commands defined here: // http://www.subsonic.org/pages/api.jsp#jukeboxControl // Starts the trackSwitcher goroutine for the device. -func NewPlaybackDevice(playbackServer PlaybackServer, name string, method string, deviceName string) *PlaybackDevice { +func NewPlaybackDevice(playbackServer PlaybackServer, name string, deviceName string) *PlaybackDevice { return &PlaybackDevice{ ParentPlaybackServer: playbackServer, User: "", Name: name, - Method: method, DeviceName: deviceName, Gain: DefaultGain, PlaybackQueue: NewQueue(), @@ -146,12 +144,12 @@ func (pd *PlaybackDevice) Skip(ctx context.Context, index int, offset int) (Devi pd.ActiveTrack.Pause() } - if index != pd.PlaybackQueue.Index { - if pd.ActiveTrack != nil { - pd.ActiveTrack.Close() - pd.ActiveTrack = nil - } + if index != pd.PlaybackQueue.Index && pd.ActiveTrack != nil { + pd.ActiveTrack.Close() + pd.ActiveTrack = nil + } + if pd.ActiveTrack == nil { err := pd.switchActiveTrackByIndex(index) if err != nil { return pd.getStatus(), err @@ -278,7 +276,7 @@ func (pd *PlaybackDevice) switchActiveTrackByIndex(index int) error { return fmt.Errorf("could not get current track") } - track, err := mpv.NewTrack(pd.PlaybackDone, *currentTrack) + track, err := mpv.NewTrack(pd.PlaybackDone, pd.DeviceName, *currentTrack) if err != nil { return err } diff --git a/core/playback/mpv/mpv.go b/core/playback/mpv/mpv.go index a622f037670..85505f11d2b 100644 --- a/core/playback/mpv/mpv.go +++ b/core/playback/mpv/mpv.go @@ -19,7 +19,7 @@ import ( // mpv --no-audio-display --pause 'Jack Johnson/On And On/01 Times Like These.m4a' --input-ipc-server=/tmp/gonzo.socket const ( - mpvComdTemplate = "mpv --no-audio-display --pause %f --input-ipc-server=%s" + mpvComdTemplate = "mpv --audio-device=%d --no-audio-display --pause %f --input-ipc-server=%s" ) func start(args []string) (Executor, error) { @@ -81,9 +81,10 @@ func (j *Executor) wait() { } // Path will always be an absolute path -func createMPVCommand(cmd, filename string, socketName string) []string { +func createMPVCommand(cmd, deviceName string, filename string, socketName string) []string { split := strings.Split(fixCmd(cmd), " ") for i, s := range split { + s = strings.ReplaceAll(s, "%d", deviceName) s = strings.ReplaceAll(s, "%f", filename) s = strings.ReplaceAll(s, "%s", socketName) split[i] = s @@ -110,7 +111,7 @@ func fixCmd(cmd string) string { func mpvCommand() (string, error) { mpvOnce.Do(func() { if conf.Server.MPVPath != "" { - mpvPath = conf.Server.FFmpegPath + mpvPath = conf.Server.MPVPath mpvPath, mpvErr = exec.LookPath(mpvPath) } else { mpvPath, mpvErr = exec.LookPath("mpv") diff --git a/core/playback/mpv/track.go b/core/playback/mpv/track.go index 76da153d255..1008debc612 100644 --- a/core/playback/mpv/track.go +++ b/core/playback/mpv/track.go @@ -24,7 +24,7 @@ type MpvTrack struct { CloseCalled bool } -func NewTrack(playbackDoneChannel chan bool, mf model.MediaFile) (*MpvTrack, error) { +func NewTrack(playbackDoneChannel chan bool, deviceName string, mf model.MediaFile) (*MpvTrack, error) { log.Debug("loading track", "trackname", mf.Path, "mediatype", mf.ContentType()) if _, err := mpvCommand(); err != nil { @@ -33,7 +33,7 @@ func NewTrack(playbackDoneChannel chan bool, mf model.MediaFile) (*MpvTrack, err tmpSocketName := TempFileName("mpv-ctrl-", ".socket") - args := createMPVCommand(mpvComdTemplate, mf.Path, tmpSocketName) + args := createMPVCommand(mpvComdTemplate, deviceName, mf.Path, tmpSocketName) exe, err := start(args) if err != nil { log.Error("error starting mpv process", "error", err) diff --git a/core/playback/playbackserver.go b/core/playback/playbackserver.go index 451dc8446d5..4281700a349 100644 --- a/core/playback/playbackserver.go +++ b/core/playback/playbackserver.go @@ -46,8 +46,11 @@ func (ps *playbackServer) Run(ctx context.Context) error { if err != nil { return err } - log.Info(ctx, fmt.Sprintf("%d audio devices found", len(conf.Server.Jukebox.Devices))) - log.Info(ctx, "Using default audio device: "+conf.Server.Jukebox.Default) + log.Info(ctx, fmt.Sprintf("%d audio devices found", len(devices))) + + defaultDevice, _ := ps.getDefaultDevice() + + log.Info(ctx, "Using audio device: "+defaultDevice.DeviceName) ps.ctx = &ctx @@ -61,15 +64,37 @@ func (ps *playbackServer) GetCtx() *context.Context { } func (ps *playbackServer) initDeviceStatus(devices []conf.AudioDeviceDefinition, defaultDevice string) ([]PlaybackDevice, error) { - pbDevices := make([]PlaybackDevice, len(devices)) + pbDevices := make([]PlaybackDevice, max(1, len(devices))) defaultDeviceFound := false + if defaultDevice == "" { + // if there are no devices given and no default device, we create a sythetic device named "auto" + if len(devices) == 0 { + pbDevices[0] = *NewPlaybackDevice(ps, "auto", "auto") + } + + // if there is but only one entry and no default given, just use that. + if len(devices) == 1 { + if len(devices[0]) != 2 { + return []PlaybackDevice{}, fmt.Errorf("audio device definition ought to contain 2 fields, found: %d ", len(devices[0])) + } + pbDevices[0] = *NewPlaybackDevice(ps, devices[0][0], devices[0][1]) + } + + if len(devices) > 1 { + return []PlaybackDevice{}, fmt.Errorf("number of audio device found is %d, but no default device defined. Set Jukebox.Default", len(devices)) + } + + pbDevices[0].Default = true + return pbDevices, nil + } + for idx, audioDevice := range devices { - if len(audioDevice) != 3 { - return []PlaybackDevice{}, fmt.Errorf("audio device definition ought to contain 3 fields, found: %d ", len(audioDevice)) + if len(audioDevice) != 2 { + return []PlaybackDevice{}, fmt.Errorf("audio device definition ought to contain 2 fields, found: %d ", len(audioDevice)) } - pbDevices[idx] = *NewPlaybackDevice(ps, audioDevice[0], audioDevice[1], audioDevice[2]) + pbDevices[idx] = *NewPlaybackDevice(ps, audioDevice[0], audioDevice[1]) if audioDevice[0] == defaultDevice { pbDevices[idx].Default = true