jellyfin / jellyfin-plugin-dlna

GNU General Public License v3.0
24 stars 13 forks source link

NullReferenceException on FLAC playback #76

Closed FlashSystems closed 1 month ago

FlashSystems commented 2 months ago

Problem description

Playing back FLAC files via DLNA does not work. If a DLNA renderer is selected as a playback device, clicking play on any FLAC file does not do anything and logs an error message. MP3 files play without problems. I know that the DLNA renderer is capable of playing back FLAC content from Jellyfin, because I worked with previous Jellyfin versions.

Versions

Jellyfin 10.9.11 DLNA Plugin 3.0.0.0

Logs

Jellyfin logs the following error message each time a FLAC file should be added to the playlist:

[ERR] Error processing request. URL "POST" "/Sessions/c5d98d7344bdb20675f1e0a74008845a/Playing".
System.NullReferenceException: Object reference not set to an instance of an object.
   at Jellyfin.Plugin.Dlna.PlayTo.PlayToController2.CreatePlaylistItem(BaseItem item, User user, Int64 startPostionTicks, String mediaSourceId, Nullable`1 audioStreamIndex, Nullable`1 subtitleStreamIndex)
   at Jellyfin.Plugin.Dlna.PlayTo.PlayToController2.SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
   at Jellyfin.Plugin.Dlna.PlayTo.PlayToController2.SendMessage[T](SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken)
   at Emby.Server.Implementations.Session.SessionManager.SendMessageToSession[T](SessionInfo session, SessionMessageType name, T data, CancellationToken cancellationToken)
   at Emby.Server.Implementations.Session.SessionManager.SendPlayCommand(String controllingSessionId, String sessionId, PlayRequest command, CancellationToken cancellationToken)
   at Jellyfin.Api.Controllers.SessionController.Play(String sessionId, PlayCommand playCommand, Guid[] itemIds, Nullable`1 startPositionTicks, String mediaSourceId, Nullable`1 audioStreamIndex, Nullable`1 subtitleStreamIndex, Nullable`1 startIndex)
   at lambda_method1323(Closure, Object)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Jellyfin.Api.Middleware.ServerStartupMessageMiddleware.Invoke(HttpContext httpContext, IServerApplicationHost serverApplicationHost, ILocalizationManager localizationManager)
   at Jellyfin.Api.Middleware.WebSocketHandlerMiddleware.Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)
   at Jellyfin.Api.Middleware.IPBasedAccessValidationMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager)
   at Jellyfin.Api.Middleware.LanFilteringMiddleware.Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Jellyfin.Api.Middleware.QueryStringDecodingMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.ReDoc.ReDocMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Jellyfin.Api.Middleware.RobotsRedirectionMiddleware.Invoke(HttpContext httpContext)
   at Jellyfin.Api.Middleware.LegacyEmbyRouteRewriteMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
   at Jellyfin.Api.Middleware.ResponseTimeMiddleware.Invoke(HttpContext context, IServerConfigurationManager serverConfigurationManager)
   at Jellyfin.Api.Middleware.ExceptionMiddleware.Invoke(HttpContext context)

If you need more information, place let me know.

disgustipated commented 2 months ago

It looks like youre using the "PlayTo" functionality somehow. Can you describe your setup more? ive not used the "play to" functionality much and having trouble replicating this. I just used bubbleupnp, found a flac audio file, played back on bubbleupnp and played fine. I then selected a google speaker as renderer in bubbleupnp and was able to play the flac audio on the google speaker from bubbleupnp.

FlashSystems commented 2 months ago

Hallo @disgustipated,

thank you for looking into this problem. I've got a DLNA renderer (based on UPMPDCLI) connected to my amplifier. The renderer is announcing itself and I can simply select it via the "PlayTo" dialog. After the connection is made in the WebUI I can start playback like with the local media player. I've tried playing albums, single tracks and playlists. The error message is always the same.

I also tried my LG television as a "PlayTo" target, to make sure that it is not some incompatibility with UPMPDCLI. But the error is the same. Playing MP3s via this route works for both media renderers.

I think you should be able to reproduce the problem if you have any DLNA renderer (TV, Stereo, etc.) that can be selected in the play to dialog.

I hope this helps. If you have more questions please let me know.

disgustipated commented 2 months ago

ok, i was actually just doing that same process this morning while looking at the playto functionality on another issue. it was working and now it is posting that same message. trying to narrow down what i changed in the settings to make that start happening. i think this has something to do with the ssdp communications server

disgustipated commented 2 months ago

I think i see whats going on. Can you try putting a valid ip that is on your server which is the same network subnet as the device youre trying to play to in the "Bind to local network address" in the networking section? it looks like when that is not set the ssdp comms server binds to 0.0.0.0 which i dont think is correct. this may also be the problem here too https://github.com/jellyfin/jellyfin-plugin-dlna/issues/48

FlashSystems commented 2 months ago

There is already the IP address of my server on the local subnet, and the loop-back address configured there.

I don't know the code, but if it's an SSDP or networking issue, why do MP3s play correctly and only FLAC files are affected?

disgustipated commented 2 months ago

Yeah, thats interesting. I was playing flac this way too and they played fine.

disgustipated commented 2 months ago

oh wait, you have loopback in the bind to local addess box like 127.0.0.1? that wont work, im pretty sure you should use an ip thats accessible from the clients in there

FlashSystems commented 2 months ago

I tested this and just put the local IP address into the input box. The issue and the error message stay the same.

FlashSystems commented 2 months ago

I've done some more testing:

MP3 file --> UPMPDCLI renderer: ✅ works FLAC file --> UPMPDCLI renderer: ❌ fails MP4 video file --> UPMPDCLI renderer: ✅ fails but with a different error message, because the renderer can not render video

MP3 file --> LG WebOS TV: ✅ works FLAC file --> LG WebOS TV: ❌ fails MP4 video file --> LG WebOS TV: ✅ works

I've event tested different FLAC files. Some have been bough directly from download stores (like qobuz), some have been transcoded from CD with different versions of FLAC encoders. Same result: FLAC does not work, everything else does.

FlashSystems commented 2 months ago

Ah, I found the issue. The user I'm using is not allowed to do transcoding. And jellyfin seems to think, that it has to do transcoding to play FLAC files. If I enable audio transcoding for my user, it works.

Now I have to figure out why suddenly Jellyfin wants to transcode FLAC files. This setting was always disabled and I know it worked...

FlashSystems commented 2 months ago

@disgustipated: I could not find a reason why Jellyfin wants to transcode FLAC files. Could you check if disabling transcoding for your user reproduces the problem?

disgustipated commented 2 months ago

im not 100% sure but I think that transcoding for dlna devices happens in the profiles when the profile tells it to transcode the file type. Can you tell in the logging which profile is being loaded? do you see a line like this when your device is turned on? For my LG tv i get this when the device registers Jellyfin.Plugin.Dlna.Main.DlnaHost: DLNA Session created for "goliath" - "LG TV" for my onkyo that does not have a profile it shows this [16:10:58] [INF] [23] Jellyfin.Plugin.Dlna.DlnaManager: No matching device profile found. The default will need to be used. {"FriendlyName": "Onkyo TX-NR656 DD4ED5", "ModelNumber": "Digital Media Client", "SerialNumber": null, "ModelName": "TX-NR656", "ModelDescription": null, "ModelUrl": "http://www.onkyo.com" , "Manufacturer": "Onkyo & Pioneer Corporation", "ManufacturerUrl": "http://www.onkyo.com", "Headers": [], "$type": "DeviceIdentification"} [16:10:58] [INF] [23] Jellyfin.Plugin.Dlna.Main.DlnaHost: DLNA Session created for Onkyo TX-NR656 DD4ED5 - TX-NR656

in the profile that is loaded you'll see some lines like this

  <TranscodingProfiles>
    <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
    <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
  </TranscodingProfiles>

not sure if that helps but might point you in the right direction. im back to getting the same message you are though and it seems related to my published url setting because when i take it out it works, both mp3 and flac dont play though.

FlashSystems commented 2 months ago

@disgustipated, thank you for the hint. With this information about profiles, I found the root cause of the problem: My audio-player gets the profile of an LG television and not the default profile. The cause is PR #60 . This PR removed the dot from the regular expression LG.*. Now the regex reads LG* which means L followed by zero or more Gs. My device's friendly name is Audio Player. The match is case insensitive so this PR makes every device where the friendly name contains an L an LG television. The profile for the LG television does not allow direct play of FLAC files.

disgustipated commented 2 months ago

Interesting, did this work in 10.8 before the move to the plugin? From what I found the . was removed in the profiles moving to the plugin which broke the profile. Your testing indicated that flac failed playing back to an lg tv too, did the tv not pick up that profile?

FlashSystems commented 2 months ago

It definitely worked before the move to the plugin. I must admit that I have not tried streaming FLAC to the TV before moving to the plugin. But this is the only device I have other than the UPMPDCLI based media player.

I've enabled the Jellyfin debug log on my current setup, and it shows that the media player is assigned to the "LG Smart TV" profile.

The code shows, that there is a regex match on the FriendlyName. See

https://github.com/jellyfin/jellyfin-plugin-dlna/blob/f7a4beaa5e12cfa40c38df49b97a23556a285773/src/Jellyfin.Plugin.Dlna/DlnaManager.cs#L135

and

https://github.com/jellyfin/jellyfin-plugin-dlna/blob/f7a4beaa5e12cfa40c38df49b97a23556a285773/src/Jellyfin.Plugin.Dlna/DlnaManager.cs#L162

I've for now created my own profile for the media player based on the default profile and put it into /var/lib/jellyfin/plugins/configurations/dlna/user. The profile matches on the ModelName of the player. This seems to be checked before the built-in profiles and fixes the problem.

disgustipated commented 2 months ago

Yeah, I renamed my onkyo to include an "l" in it, I do see its picking up a profile now in this version and and it was not back in the 10.8 version. I'll try to see if there was a change to how the dlna manager is pulling profiles, there was a lot that changed when they moved to the plugin. When I removed that . it was because it stopped my tv from being recognized and there was not a . in the old profiles.