Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jellyfin Support #217

Closed
diabl0w opened this issue Oct 15, 2020 · 18 comments · Fixed by #241
Closed

Jellyfin Support #217

diabl0w opened this issue Oct 15, 2020 · 18 comments · Fixed by #241

Comments

@diabl0w
Copy link

diabl0w commented Oct 15, 2020

Jellyfin is a FOSS fork of Emby/Plex Media Server... it can serve audio files over DLNA. For devices such as my samsung TV, when I send media files, it is able to fully control the TV including queuing tracks, change volume, skip tracks, seek through tracks, play/pause/stop etc. However, when I point it to one of my many raspberry pi's running gmrender-resurrect, I can only play songs, change volume, and play pause... but I cannot do anything else like seek through the tracks or skip the currently playing track to the next one in the queue.

I am not sure if this is a jellyfin or gmrender issue, but jellyfin does have an advanced config section for adding compatibility to DLNA devices via "profiles". It matches via a manufacturer id among other things which I was able to find. Can you tell me maybe what other things I can add to this advanced config to make these other features work? An example of possible options you can see in this samsung TV config: https://github.com/jellyfin/jellyfin/blob/master/Emby.Dlna/Profiles/SamsungSmartTvProfile.cs. Things like extra headers

@hzeller
Copy link
Owner

hzeller commented Oct 15, 2020

This sounds probably more like a question for jellyfin then ?
If you want to debug a particular issue e.g. with skipping, maybe create a logfile and see what goes wrong in that case.

@diabl0w
Copy link
Author

diabl0w commented Oct 15, 2020

Thanks for the fast response, and I apologize for the duplicate issue. I am not sure if this is a jellyfin or gmrender issue, I really dont know much about the behind the scenes, I am just a user. I have attached logs from the jellyfin side as well as the gmrender side.

Exactly what I did while these logs were happening was: Add a playlist to the queue and start playing, skip to the next track, skip to the next track, stop playback, disconnect.

What happened in real life was: the queue was added and started playing, the track was skipped in the user interface and showed the next track playing, but in reality gmrender just kept playing the same song. Same thing happened for the next song ....
and the stop and disconnect worked properly.

Side note: when skipping tracks and the same track keeps actually playing in real life, the UI shows that the new track is playing from the same time position that the last track was skipped at. Meaning if I skipped a track that was 12 seconds into progress, the user interface then showed the next track playing at 12...13...14 seconds. I am assuming that is because gmrender is still feeding back the playback progress of the previous song.

jellyfin.txt
gmrender.txt

@diabl0w
Copy link
Author

diabl0w commented Oct 15, 2020

These logs should be better, use them instead:
gmrender2.txt
jellyfin2.txt

I am not really seeing anything going on with the logs, except maybe in the jellyfin logs it looks like maybe some kind of error is occuring during the skips and then jellyfin quickly disconnects and reconnects to gmrender? but I am honestly not sure

@mill1000
Copy link
Contributor

mill1000 commented Dec 7, 2020

Based on the log from gmrender it looks like Jellyfin only changes the media URI, but does not issue a "play" command so gmrender does not play the new file.

In comparison, my control point of choice stops playback, changes the uri, and then issues a play command.

I'd have to review the UPNP spec to know for sure, but it appears that Jellyfin isn't issuing the correct sequence of commands,

I stand corrected. It may be our end.
http://upnp.org/specs/av/UPnP-av-AVTransport-v1-Service.pdf

2.4.1. SetAVTransportURI

....
image

@mill1000
Copy link
Contributor

mill1000 commented Jan 2, 2021

If you've got the time to debug, I've got a branch here: https://github.com/mill1000/gmrender-resurrect/tree/issues/217_jellyfin you could try.

I've made a minor change to load the URI into the player if a SetAVTransportURI is received will the device is already playing.

This might fix your issues with skipping tracks.

@Ra72xx
Copy link

Ra72xx commented Mar 16, 2021

Is there any progress on this? I use both Jellyfin and Emby, and always run into this problem. Makes it impossible to stream more than one song at once...

@mill1000
Copy link
Contributor

@Larx could you give the branch I linked a try? It that fixes the issue I can submit a PR

@Ra72xx
Copy link

Ra72xx commented Mar 17, 2021

Thanks for the quick reply.
After posting my question I found another approach for my problem (streaming client for Emby/Jellyfin in order to connect to bluetooth speakers). I now have been successfull using Mopidy as the bridge between media server and speakers, which also gives a bit more control. So currently my question has been settled otherwise ;-).

@hzeller
Copy link
Owner

hzeller commented Mar 17, 2021 via email

@mijofa
Copy link

mijofa commented Nov 4, 2021

I gave @mill1000's branch a try and it does solve the problem with skipping tracks.

The real problem I'm having with it is that gmediarender doesn't seem to send status updates back to Jellyfin. So when Jellyfin sends a pause signal gmediarender will actually pause, but Jellyfin thinks the media is still playing.

Seems like the same thing is causing weirdness when seeking through the media, I'll seek to say 50% in, the seek works but Jellyfin's progress continues from the beginning, but then I'll seek back to 25% in and it seeks correctly, but it seems gmediarender then sends a status update of the previous position as Jellyfin then shows progress from the 50% position of the previous seek.
[UPDATE 1: It does get seek updates, but it takes ~20 seconds (far too long in my opinion) pause state does not update though]
Is there a way for me to increase the upnp/dlna debugging of gmediarender? I'd like to see more info on what signals are being sent, but the only log-level arguments seem to be for gstreamer's log levels.

I'm not super confident in my C skills (Python dev normally) but this at least seems like it might be a simple fix which I'll try and take a look at once I figure out how this code is structured.

UPDATE 2: I've done some digging around using Wireshark to watch the network traffic. I think the issue with seek updates not being reflected in Jellyfin is because Jellyfin is asking for an update quicker than gmediarender has actually updated the seeked time, so it's effectively:

  1. JF: Hey gmrender, seek to 50%
  2. GM: Ok, gimme a sec
  3. JF: Hey gmrender, where are you seeked to?
  4. GM: 1%
  5. GM: Ok done

Jellyfin also checks in asking for an update every 15-30 seconds or so, just to make sure everything is where it expects. That's why I'm seeing the seek update get to Jellyfin eventually.
Not sure why the pause state isn't working, I can definitely see gmediarender sending "PAUSED_PLAYBACK" to the GetTransportInfo immediately after the pause command. Jellyfin also seems to stop doing the regular "check-in" every 15-30 seconds, so that might be a bug entirely on Jellyfin's end, but I'm not so sure about that yet.

UPDATE 3: Found this in the code at the seek function in upnp_transport.c. Sounds like it's exactly what I've run into:

// TODO(hzeller): Seeking might take some time,
// pretend to already be there. Should we go into
// TRANSITION mode ?
// (gstreamer will go into PAUSE, then PLAYING)

@mijofa
Copy link

mijofa commented Nov 5, 2021

Hrmm, is the output_gstreamer_seek function supposed to return -1 on success, or failure?

I believe that if statement is backwards as it's currently returning '-1' on success, and '0' on failure, which is the opposite of what I normally expect, and by the looks of things the opposite of what the seek function in upnp_transport seems to expect.
I think that is the main thing causing my problem, swapping them around makes things a lot smoother, not perfect, but a heck of a lot better.

Minor sidenote: Using gst_element_seek_simple would make that function a bit simpler, and easier to parse, given it's not making use of any of the extra things seek does which seek_simple doesn't anyway.

UPDATE: And for a final touch, replacing the "PAUSED_PLAYBACK" string with "PausedPlayback" lets Jellyfin properly recognise when the media is paused (also worked as "PAUSEDPLAYBACK"). So either Jellyfin or gmrender is probably breaking the DLNA spec there, not sure which, my bet's on Jellyfin there though. I'll ask around in their IRC channel on Monday

@mill1000
Copy link
Contributor

mill1000 commented Nov 6, 2021

I agree that output_gstreamer_seek looks like it returns the incorrect value. Probably just a copy-paste bug since other output module functions typically have the form of

if (gst_element_do_something() == GST_STATE_CHANGE_FAILURE)
  return -1;

I can make the change in my branch and create a PR.

According to the spec I attached above "PAUSED_PLAYBACK" is the correct form.
image

@mijofa
Copy link

mijofa commented Nov 6, 2021

Thanks for making the Jellyfin issue, I was happy to do a PR for all the Jellyfin fixes, wanted to get 1 last thing solved first though.

When Jellyfin tries to "Continue watching" a media file from half way through, gmrender doesn't seek to that half way mark. But if I press stop then start it again from the beginning, gmrender starts it back where it should have the first time.
I haven't done much further investigation into this, I actually suspect they're 2 separate issues but haven't done enough testing to have any more evidence than a gut feeling there.
First being that Jellyfin might be telling it to seek before gmrender is ready.
Second being that gmrender isn't properly closing the player object when stopping the media playback, so it's still remember the previous state such as seek time despite not properly seeking to it previously.

@mill1000
Copy link
Contributor

mill1000 commented Nov 6, 2021

Oh well you're more than welcome to. I can close the one I just opened. Just let me know what you want to do.

I wonder if Jellyfin might be sending the "seek" command first, and then the "play" command. Not sure exactly what order gstreamer needs. A review of this might be in order: https://gstreamer.freedesktop.org/documentation/application-development/advanced/queryevents.html?gi-language=c

@mijofa
Copy link

mijofa commented Nov 6, 2021

You're all good, stick with yours I'll do another if necessary. :)

Yeah that was my thinking, haven't done any packet sniffing yet to confirm that though as I'm away for the weekend.
If that is the case, it's might be another issue for Jellyfin, although a workaround here could be to cache the seek instruction until gstreamer starts playing. That's fairly hacking though.
Will investigate, thanks for the help! :)

This should be the last thing I need to get rid of my near decade old home made media system

@mijofa
Copy link

mijofa commented Nov 7, 2021

First issue is that the play() function is returning before gstreamer has actually started playing the stream. This is because gst_element_set_state(...) is triggering an async change and we're supposed to wait for a "GST_MESSAGE_STATE_CHANGED" message before reporting that we're in playback state.
I've bodged together a hacky fix for this but it's a wait-loop rather than figuring out the async stuff. I'm attaching it here as a patch for documentation purposes, but I'm not currently happy enough with it to make a PR because it really should be doing async stuff.

I can't reproduce the 2nd half of that anymore, so I guess my suspicion of it being 2 separate issues was probably incorrect.

@mijofa
Copy link

mijofa commented Nov 10, 2021

I've been using that messy patched version the past couple days and it's working well.
Couple general video issues I've run into that I should probably spawn off into a separate issue once I've done some extra investigation:

  • Subtitles don't work at all, I think this is just a matter of setting the playbin element's "suburi" property, but I don't yet know the right way to get that from the UPnP communication
    [UPDATE: Confirmed setting suburi is enough. Still don't know about the UPnP side of it. Did find the subtitles URI in a <res...> element under AVTransportURIMetaData. Still figuring out how to get that as an object on its own though]
  • When a stream finishes and there's no "next uri" lined up the output sinks don't get closed even though the UPnP controller does get told the playback got stopped. This is also an issue with audio only as pulseaudio thinks audio is still playing when it isn't, but it's definitely more noticable with video playback because the X11 window doesn't close.
    Probably need to run output_gstreamer_stop() when recieving the GST_MESSAGE_EOS signal. Will do some testing.
    [UPDATE: confirmed, patch made, will PR both together once I get ^ solved]

@mijofa
Copy link

mijofa commented Nov 10, 2021

After many hours of trying to parse the XMl, I determined that a) I don't know what I'm doing, and b) It won't really work anyway because Jellyfin (at least) sends all subtitle streams in that metadata, and gives no indication of what should/shouldn't be enabled.

Also ran into an entirely unrelated issue in Jellyfin's design that means this probably can't work for me the way I wanted it to anyway. So I probably won't be working on it much more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants