Closed certuna closed 6 months ago
This is the implementation of the Jukebox mode I talk about in other issues (ex: #250), but didn't have an open issue for it. I'll keep this open to track the Jukebox work.
for what it's worth, Jukebox mode would be amazing.
I'd love to be able to have my server playing musically locally (goes to an FM transmitter) that I control remotely but if I could also stream my music as well to my phone for when I'm remote....it would really be a game changer (for me :)
going back into my hole now...
@bitva77, why not use a Subsonic client on your phone?
Oh I do and it works for one or the other. I can use two different clients to get that effect when using Airsonic (for example).
I'm wondering if using MPD for jukebox mode and then Navidrome (*sonic) for streaming is really the best option at the moment. All MPD clients pretty much suck. What you've done with Navidrome is really nice and ticks off most feature boxes :)
To play Spotify in jukebox mode would be the ultimate as I could then get my wife using all this as well (mopidy comes close but it's buggy).
I'm also wondering if a combination of pulse and jack may be an option to get the sound going everywhere. Need to research that some more as well
Hi I have ample knowledge of web dev that will be required for this project Can I pick some open issue to get familiar with the codebase?
Sure
More than jukebox mode, IMHO this should be modeled after logitech media server, which has the paradigm of 'control from anywhere, play from anywhere'. The react web UI should be able not only control the 'jukebox client' but actually any connected client to the server.
For what is worth here is a minimal go subsonic client that could be used for this. https://github.com/wildeyedskies/stmp
@deluan has any work been done on this? Would you have the time and interest to mentor me in this project?
More than jukebox mode, IMHO this should be modeled after logitech media server, which has the paradigm of 'control from anywhere, play from anywhere'. The react web UI should be able not only control the 'jukebox client' but actually any connected client to the server.
Hey @crisclacerda , yes, thats the plan.
And yes, this contribution would be awesome, ping me on Discord and we can chat about this.
hello, today I got Navidrome running on my pi3 and I'd like to join this topic :headphones:
Implementing the frontend part to select the jukebox mode and control the subsonic client – gsoc
In the past month I tested kodi again and had a look at the web-ui Chorus 2. Maybe it serves as a good demo, on how the UI could be presented:
1: The Playlist-Panel has two tabs. Remote (blue) and Local (red). Switching target sets the highlight color 2: The Player shows the active song + controls for the selected target 3: An additional visual indicator shows by highlight color what mode is active. This can prevent accidentally changing remote playback when intention is to act locally
A similar strategy should work with Navidrome - what do you think?
I have 5+ yrs hypertext frontend exp. React, Angular :unamused: , Svelte :relaxed:; See you in discord ^^
That's awesome. I also run navidrome on a pi3. I also have a pi1 that runs squeezeplay quite smoothly. So with LMS, I can make a neat multi-room setup. That go client I mentioned above should also do the trick. Maybe we can have a tab for each player @gitbreaker222 ?
I'll try getting the development environment running upcoming weekend. The documentation looks exceptionally well, so I'm confident that it will be fun and successful :smiley: If not, I'll get easily distracted and will replay 6 months later ^^
Any updates on this? Or any builds to test this feature?
I'm also interested to know if there are any updates on this. I'd be interested in working on it if other folks haven't been able to get to it. @deluan do you know what the status is?
Hi, today I test navidrome on my nas and works nicely. I am however looking for MoodeAudio replacement that can play music locally preferably using attached dac so I can control music from my phone or tablet. Moode audio also have some Impressive parametric and convolver plugin which I like a lot. however, they are primarily intended for RPi. Navidrome looks promising. looking forward to this jukebox function. TQ
I'm running Navidrome on my docker host. I use a subsonic client on my phone while I'm on the go but I am looking at doing whole house audio with raspberry pi's with DAC hats. Need a way to have some type of client that can be controlled and synced for different zones. It looks like this thread is working on something like this. If there are any suggestions on how to accomplish this please let me know.
Plexamp has a nice app and a raspberry pi install that you can control. Looking to do this same thing with the freedom of Navidrome instead of Plex.
I wanted to jump in to say that streaming from a server is a very interesting option for me and I'll be glad iff it is released. I use Navidrome on a Docker in my Synology NAS - initially, Synology had its own player/organizer that streamed via USB but since version 7 of their OS they cut off all USB support (there are informal methods to add serial USB drivers back but not audio). Actually, that's how I went seeking for alternatives and after several unsuccessful tries ended up with Navidrome on PC and playing via PC USB on DAC - not the best solution but workable
Just chiming in here because I haven't seen much talk of Snapcast which is what I am currently using in my home to play from my NAS via Mopidy. I do really love the Navidrome UI though, IMO it's a bit cleaner than some of the Mopidy front-ends (no disrespect to those projects).
Anyhow, this weekend I was messing around with transcoding commands and got Navidrome to successfully output to a pipe file located on my nas which streamed to the snapserver. Unfortunately because of how the UI works you can't pause/stop the stream and when you select another song to play the stream gets muxed all weird.
I would propose to create a plugin-system here to register various output systems and a moniker-scheme to address the system in the configuration file.
Something like:
alsa:hw:0,0 osx:Cambridge Audio USB 1.0 Audio Out win:BEHRINGER UMC 202HD 192k mpd:soundserver.exmple.com:6600
There must be a level of indirection to avoid hardcoding the first sound-output-device.
Perhaps relevant, another *sonic compatible (paid) app is doing it: https://support.symfonium.app/t/wiki-symfonium-api-allow-control-from-other-apps-like-tasker/643
Perhaps relevant, another *sonic compatible (paid) app is doing it: https://support.symfonium.app/t/wiki-symfonium-api-allow-control-from-other-apps-like-tasker/643
Not really relevant, Symfonium is a Subsonic client, not a server as Navidrome. Both actually works well together, but what Synfonium is implementing is something else, not related to what we call "jukebox mode" in the context of Subsonic applications.
More than jukebox mode, IMHO this should be modeled after logitech media server, which has the paradigm of 'control from anywhere, play from anywhere'. The react web UI should be able not only control the 'jukebox client' but actually any connected client to the server.
I have my Navidrome server running on a Raspberry Pi 4 NAS (on Docker) and I'd like to have another Raspberry Pi zero W connected to some speakers. It would probably run some kind of headless client and output audio via the audio jack of a USB dongle. It would be cool to control it from the webui of Navidrome (just like things like Spotify Connect or LMS).
For now, I think the only option is to create a subsonic client with its own webui or control an existing terminal client via ssh.
Merged! For those waiting for this, please let me know if you bump into any issues, thanks for the patience :)
Hmmm, I pulled the latest deluan/navidrome:develop docker image, but I do not see anywhere how to activate the jukebox mode. Also checked the https://github.com/navidrome/navidrome/pull/2289 merge request but it's only code changes, no help files edited... :(
How do I try this out? (Btw, I'm running on a PI4) Thanks!!!
it got merged but doesn't look like a new build happened
Downloaded develop, but i do not see a change. Also, is there a timeline for a new latest?
From what I can tell with some testing and looking at the code, much of the backend work for a jukebox mode was done, but it's not really complete yet. A partial list of issues:
getUser
endpoint returns a hardcoded "jukeboxRole": false
. Clients I've tested (e.g. Ultrasonic) interpret this as jukebox mode being unavailable or not allowed for the user. This appears to be correct behavior according to the spec.jukebox.enabled = true
with the error error="default device name not found: "
. You can at least get the server to start with the following (probably bogus) configuration:jukebox.enabled = true
jukebox.devices = [["default", "default", "default"]]
jukebox.default = "default"
Unfortunately, I have no idea what appropriate values for a device would be. Since navidrome is just using mpv under the hood, I kind of hoped it would work with no configuration.
I edited the user endpoint to enable the jukebox role and recompiled navidrome, but it doesn't play any music in jukebox mode (probably unsurprising).
@deluan if I've accurately described the state of this feature, could we get this issue re-opened until some of the problems are fixed? Apologies if I've misunderstood something, I know I'm tinkering with brand new work here but I really wanted to get it working.
Thanks for the review!
- It's not implemented in the web UI yet.
And won't be there any time soon, unfortunately. I need to finish the new UI, and adding Jukebox support to it is not a priority ATM. The feature will be available only from Subsonic clients for now.
- It's not available to any clients because the
getUser
endpoint returns a hardcoded"jukeboxRole": false
. Clients I've tested (e.g. Ultrasonic) interpret this as jukebox mode being unavailable or not allowed for the user. This appears to be correct behavior according to the spec.
Ops, my bad. Will fix that tonight!
- It's not clear how to use the configuration
@ms140569 is working on a documentation page, maybe he can post some examples here?
@deluan if I've accurately described the state of this feature, could we get this issue re-opened until some of the problems are fixed? Apologies if I've misunderstood something, I know I'm tinkering with brand new work here but I really wanted to get it working.
Thanks for the feedback. I'll reopen until we get a doc page (or a reply from @ms140569 with some examples)
- It's not available to any clients because the
getUser
endpoint returns a hardcoded"jukeboxRole": false
. Clients I've tested (e.g. Ultrasonic) interpret this as jukebox mode being unavailable or not allowed for the user. This appears to be correct behavior according to the spec.
Fixed in 2cd43581
Thanks for the very quick response @deluan!
I've been digging a little further and found some more issues.
This means I was wrong about the configuration being the reason the jukebox didn't play anything in my tests. The real reason is a combination of two additional issues:
The jukebox doesn't seem to receive a start request from Ultrasonic in a format that it likes. Sending action=start
with curl seems to work. I'll have to dig into this further at some point. Once the play queue has been started manually with curl, everything seems to work OK from Ultrasonic. (Weirdly, it works even after restarting navidrome. Not sure what's happening here.)
The code fails to launch mpv when you have a MPVPath
set in your config. I figured something complicatedly wrong was happening here, but then I discovered this: https://github.com/navidrome/navidrome/blob/master/core/playback/mpv/mpv.go#L113
if conf.Server.MPVPath != "" {
mpvPath = conf.Server.FFmpegPath
mpvPath, mpvErr = exec.LookPath(mpvPath)
}
I think you want conf.Server.MPVPath
there?
Skip
action, and the first few lines of traceback follow: -> github.com/navidrome/navidrome/core/playback.(*PlaybackDevice).Skip
-> /home/user/navidrome/core/playback/device.go:161
github.com/navidrome/navidrome/server/subsonic.(*Router).JukeboxControl
/home/user/navidrome/server/subsonic/jukebox.go:85
github.com/navidrome/navidrome/server/subsonic.(*Router).routes.func16.h.func1
/home/user/navidrome/server/subsonic/api.go:205
github.com/navidrome/navidrome/server/subsonic.hr.func1
/home/user/navidrome/server/subsonic/api.go:212
net/http.HandlerFunc.ServeHTTP
Okay, a little addition. I think I understand the cause of the panic. It happens when you've just reset the play queue with a set
action and a song id
, and then you skip
to the song you just added. The code looks like this:
if index != pd.PlaybackQueue.Index {
if pd.ActiveTrack != nil {
pd.ActiveTrack.Close()
pd.ActiveTrack = nil
}
err := pd.switchActiveTrackByIndex(index)
if err != nil {
return pd.getStatus(), err
}
}
err := pd.ActiveTrack.SetPosition(offset)
if err != nil {
log.Error(ctx, "error setting position", err)
return pd.getStatus(), err
}
The logic here is that if the request asks us to change the index, we set a new active track, and if this fails, we bail out early. If we aren't changing the index, then we ought to be able to change the playhead (offset), since a track is presumably already active.
The problem with this reasoning is that if we've rewritten the queue with set
but haven't started playing yet, we don't have an active track.
I think this fix should be reasonable:
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
}
}
err := pd.ActiveTrack.SetPosition(offset)
if err != nil {
log.Error(ctx, "error setting position", err)
return pd.getStatus(), err
}
Happy to send in a PR if that would help.
It's worth noting that Ultrasonic seems to send a set
action with no id
, probably to clear to the queue, right before calling set again with id
to add an album. The first request seems to fail harmlessly, causing a log entry in Navidrome. It's not obvious to me why they do this, I might want to chase this down with Ultrasonic at some point.
@afontenot Thanks for your valuable feedback! I was pretty busy in the last time. I'm working on bugfixes and an overhaul of the configuration. We changed to mpv playback, but this is no at all reflected in the config file syntax. Besides this, I'm seeing a couple of bugs when running on an rpi4.
To keep things short: I'm working on it, bear with me.
State of the union: I'm facing bugs/different behaviour in the MPV-IPC package we are using:
https://github.com/dexterlb/mpvipc
This worked without any flaws on MacOSX, but shows a quite different behaviour and timing on Linux. I've tested on x86_64 and aarch64 (rpi4).
Could someone please doublecheck on Windows?
Okay, a little addition. I think I understand the cause of the panic. It happens when you've just reset the play queue with a
set
action and a songid
, and then youskip
to the song you just added. The code looks like this:if index != pd.PlaybackQueue.Index { if pd.ActiveTrack != nil { pd.ActiveTrack.Close() pd.ActiveTrack = nil } err := pd.switchActiveTrackByIndex(index) if err != nil { return pd.getStatus(), err } } err := pd.ActiveTrack.SetPosition(offset) if err != nil { log.Error(ctx, "error setting position", err) return pd.getStatus(), err }
The logic here is that if the request asks us to change the index, we set a new active track, and if this fails, we bail out early. If we aren't changing the index, then we ought to be able to change the playhead (offset), since a track is presumably already active.
The problem with this reasoning is that if we've rewritten the queue with
set
but haven't started playing yet, we don't have an active track.I think this fix should be reasonable:
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 } } err := pd.ActiveTrack.SetPosition(offset) if err != nil { log.Error(ctx, "error setting position", err) return pd.getStatus(), err }
Happy to send in a PR if that would help.
It's worth noting that Ultrasonic seems to send a
set
action with noid
, probably to clear to the queue, right before calling set again withid
to add an album. The first request seems to fail harmlessly, causing a log entry in Navidrome. It's not obvious to me why they do this, I might want to chase this down with Ultrasonic at some point.
Youre patch did the trick, thanks! It will be included in my PR with other fixes and configfile cleanups.
@ms140569 Suggestion: id
should be treated as an optional parameter for the set
operation. set
is just clear
followed by an add
for each id
, so not providing an id
should be equivalent to clear
.
I realize this may seem pointless since clear
already exists, but Ultrasonic appears to actually use this instead of clear
, because it handles all playlist operations in the same way (by building an internal lists of songs and then calling set). Unless you think it is (or ought to be) inconsistent with the spec to call clear
without an id
?
Also: I reported the issue with Ultrasonic failing to send the start
command. https://gitlab.com/ultrasonic/ultrasonic/-/issues/1266
Would it be possible to update the documentation with how to link this to snapcast via MPV? https://www.navidrome.org/docs/usage/jukebox/ https://github.com/badaix/snapcast/blob/develop/doc/player_setup.md#mpv
Also linking the meta_mopidy.py file for sending metadata to snapcast if anyone wants to take a stab at making one for Navidrome
https://github.com/badaix/snapcast/blob/develop/server/etc/plug-ins/meta_mopidy.py
@daredoes I'm not sure it's trivial to get get MPV playing to Snapcast without further code mods in Navidrome. This probably needs to be it's own ticket about adding support for Snapcast as a separate feature to the Jukebox it's self.
From what I can see you'd need to;
Add a special playback device class in Navidrome to handle the following, as it looks like the current design is around physical sound output devices;
Documents on MPV Audio Out Drivers here and Snapcast Sources here
Navidrome would need file https://github.com/navidrome/navidrome/blob/master/core/playback/mpv/mpv.go
modified to change:
mpvComdTemplate = "mpv --audio-device=%d --no-audio-display --pause %f --input-ipc-server=%s"
To something like:
mpvComdTemplate "mpv --audio-display=no --pause %f --input-ipc-server=%s --audio-channels=stereo --audio-samplerate=48000 --audio-format=s16 --ao=pcm --ao-pcm-file=/var/run/snapcast/navidromefifo"
track.go
It's something I'm also interested in but I don't have the time to invest beyond investigating a proof of concept for now. It would also be nice to see Jukebox control from the main webui rather than a Subsonic client.
I was already musing about the idea to externalize the mpv shellout template into the configuration file. This is yet another use case. @deluan
Am So., 19. Nov. 2023 um 23:33 Uhr schrieb MindrustUK < @.***>:
@daredoes https://github.com/daredoes I'm not sure it's trivial to get get MPV playing to Snapcast without further code mods in Navidrome. This probably needs to be it's own ticket about adding support for Snapcast as a separate feature to the Jukebox it's self.
From what I can see you'd need to;
-
Add a special device class in Navidrome to handle;
fifopipe (Assuming Snapcast is local to the Navidrome process) or
- have MPV play to an ipaddress:socket for Snapcast in ingest (it looks like Pulse may work for this but I'm not sure of the practical implementation).
Documents on MPV Audio Out Drivers here https://github.com/mpv-player/mpv/blob/master/DOCS/man/ao.rst and Snapcast Sources here https://github.com/badaix/snapcast/blob/develop/doc/configuration.md#tcp-server
Navidrome would need file https://github.com/navidrome/navidrome/blob/master/core/playback/mpv/mpv.go modified to change: mpvComdTemplate = "mpv --audio-device=%d --no-audio-display --pause %f --input-ipc-server=%s"
To something like:
mpvComdTemplate "mpv --audio-display=no --pause %f --input-ipc-server=%s --audio-channels=stereo --audio-samplerate=48000 --audio-format=s16 --ao=pcm --ao-pcm-file=/var/run/snapcast/navidromefifo"
- Then using the device handler mentioned above select this 'device' (Fifopipe or Socket) for playback. Looks like this happens in track.go
It's something I'm also interested in but I don't have the time to invest beyond investigating a proof of concept for now. It would also be nice to see Jukebox control from the main webui rather than a Subsonic client.
— Reply to this email directly, view it on GitHub https://github.com/navidrome/navidrome/issues/364#issuecomment-1817998938, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACLJJPUH7CDHFPI5N5V3K3YFKCKLAVCNFSM4OEO6AZ2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOBRG44TSOBZGM4A . You are receiving this because you were mentioned.Message ID: @.***>
-- Matthias Schmidt Marienstraße 14
67346 Speyer
++49 6232 6842676 ++49 171 5767209
484C 1E1E 71B4 1389 900B 3C07 8901 C978 4D8F 66CF
Public Key: matthias-schmidt-gmail-com.asc https://www.dropbox.com/s/k4liuahxfzbveg7/matthias-schmidt-gmail-com.asc?dl=1
I've found when using Mopidy with Snapcast, I get the best quality and least amount of errors when streaming the audio by having Mopidy run a TCP server, and Snapcast being the client. Could technically do this locally or over a public IP, which might be a better end product for Navidrome than modifying MPV
https://github.com/badaix/snapcast/blob/develop/doc/configuration.md#tcp-server
@ms140569 +1 for moving the MPV shellout template into config. This adds some desirable functionality without having to recompile from source.
I was already musing about the idea to externalize the mpv shellout template into the configuration file. This is yet another use case. @deluan - what do you think?
I'm ok with that.
Closing this as we now have the Jukebox functionality released. Any requests for improvements should be open in Discussions and bugs should be reported as a new issue.
Looking for buy in on the following discussion https://github.com/navidrome/navidrome/discussions/2875
Currently the web UI allows clients to navigate the library, but always streams to the client browser and outputs the sound there. Feature request: add the option (speaker icon on the bottom) to output the sound on the server instead.