Skip to content

[Enhancement] UPnP/DLNA Media Renderer Plugin: use HTTP/1.1 and always proxy thru LMS - #1615

Merged
michaelherger merged 1 commit into
LMS-Community:public/9.2from
stsichler:feature/http1.1-dlna-streaming
Jul 30, 2026
Merged

[Enhancement] UPnP/DLNA Media Renderer Plugin: use HTTP/1.1 and always proxy thru LMS#1615
michaelherger merged 1 commit into
LMS-Community:public/9.2from
stsichler:feature/http1.1-dlna-streaming

Conversation

@stsichler

Copy link
Copy Markdown
Contributor

This is a follow-up of my comment to #1121.

Testing inter-operation with pa-dlna revealed that LMS's UPnP/DLNA Media Renderer Plugin needs an update to support HTTP/1.1 with chunked transfer encoding to be compatible to up-to-date DLNA Streaming Servers like pa-dlna.
In order to limit the changes required to LMS's DLNA plugin itself and not requiring any changes to Squeezebox Device Firmwares, this implies to also disable direct streaming for DLNA streams in general, meaning always routing the data through LMS and do the translation from HTTP/1.1 chunked transfers to raw HTTP/1.0 there.
Currently, direct streaming is only used when streaming to a single Squeezebox (not a synchronized group).

This PR addresses this.

Note: this PR is generated with the help of AI, since I'm not capable of Perl and I know too little about LMS' internal structures, so please carefully review the code.

In my local tests, this PR seems to work correctly.

I have tested: pa-dlna as server, a single Squeezebox as renderer, a synchronized group of Squeezeboxes as renderer.

Comment thread Slim/Player/Protocols/HTTP.pm Outdated
@stsichler
stsichler force-pushed the feature/http1.1-dlna-streaming branch from f49a07d to 5cf54e3 Compare July 27, 2026 07:14
@stsichler

Copy link
Copy Markdown
Contributor Author

@michaelherger Thanks for your input. Now, the change is strictly local to the Media renderer Plugin.

@stsichler

Copy link
Copy Markdown
Contributor Author

Note: I'm currently only testing against pa-dlna.

While this change addresses the primary issues of missing HTTP/1.1 chunked-transfer encoding support and the direct-streaming-related difference in connect source IP, there is at least another issue that may be harder to solve:

By default, pa-dlna sends SetAVTransportURI messages on track changes to update track metadata and trigger a "re-connect". This currently causes the connection to break, because the Squeezebox' delayed reaction on this doesn't work well together with pa-dlna's internal connection handling.
But I'll have to further analyze this and look for a separate solution for it. I think that this will be a separate issue from this.

@michaelherger michaelherger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this is to be able to stream from pa-dlna to a Squeezebox? I neither have any decent experience with the UPnP plugin (user or developer), nor with this level of networking code changes 😖. I must admit that I don't care too much about UPnP/DLNA, as I believe this addition to LMS really was a rushed thing to satisfy one specific commercial product requirement many, many years back. And it's never been a popular feature. Maybe I'm wrong.

Therefore I'd have to rely on you to put some extra effort into testing these changes. Could you please pick up some of the more popular choices (I'm not familiar with, but Google suggested eg. BubbleUPnP, Serviio, Minimserver) and give them a quick run-through?

I would also be happy if @philippe44 could give the _sysread a quick review, as he's the guy who introduced the canEnhanceHTTP mechanism.

Comment thread Slim/Plugin/UPnP/MediaRenderer/ProtocolHandler.pm Outdated
@simonwiles

simonwiles commented Jul 29, 2026

Copy link
Copy Markdown

I too am very interested in being able to stream to LMS from a DLNA server. I also tried and failed to use pa-dlna for this purpose (hitting the same problems), and I ended up rigged up a hacky icecast/darkice/pa-sink monstrosity that is less than perfect and that I'd be delighted to retire :) I've also been frustrated with difficulties doing similar things from the AirMusic Android app which I think this might help with.

I'm travelling and away from my LMS server for another couple of weeks, but I look forward to testing this once I'm home. Would love to see this get fixed -- thanks to you both, and especially @stsichler for working on this :)

@stsichler

Copy link
Copy Markdown
Contributor Author

Could you please pick up some of the more popular choices (I'm not familiar with, but Google suggested eg. BubbleUPnP, Serviio, Minimserver) and give them a quick run-through?

Results of my tests:

  • BubbleUPnP seems to still work with this modification (but it was working before anyway, so it seems to still support HTTP/1.0)
  • Playing back media from a ReadyMedia (Minidlna) Server seems to work
  • Serviio: I was unable to properly run it at all
  • pa-dlna is working with the modifications and by now seems to be the only DLNA server that is actually using chunked transfer encoding
  • AirMusic is NOT working, because of some incompatibility in Audio MIME type (LPCM seems not properly supported).

AI-based effort estimate to get LPCM working:

"Low to medium, no fundamental architectural issue – the infrastructure (proxy streaming, chunked-dechunking, sink protocol advertising) is already in place. Essentially, the following would be required:
_DIDLLiteToHash: Read the MIME parameters (rate, channels) or DIDL-res attributes and store them in the meta-hash.
When calling SetAVTransportURI/SetNextAVTransportURI: call Slim::Music::Info::setContentType() with the actual (mapped) type and set the sample rate, channels and sample size on the RemoteTrack object (using updateOrCreate/setAttributes, similar to Volatile.pm:31).
Adapt ProtocolHandler::getFormatForURL and new() so that they use the actual type instead of the fixed values mp3/audio/mpeg."

... But that would be the subject of a different pull request. ;-)

@stsichler

Copy link
Copy Markdown
Contributor Author

Would love to see this get fixed -- thanks to you both, and especially @stsichler for working on this :)

@simonwiles You're welcome! In order to get the Squeezeboxes properly working with pa-dlna, it is currently also required to switch off sending of track-metadata in pa-dlna, because pa-dlna re-uses the same media URI from track to track. This is incompatible with the way the Squeezeboxes handle track changes and causes the connection to break on a track change.
I'm still evaluating which solution would be best for this (if there is any at all - I'm not sure...) and I've already started another issue as a starting point for a discussion about this at pa-dlna.

Until then, it is necessary to switch that off, e.g. by using a config file ~/.config/pa-dlna/pa-dlna.conf:

[DEFAULT]
selection = FFMpegMp3Encoder

# required for SqueezeBoxes
[FFMpegMp3Encoder]
track_metadata = no

Comment thread Slim/Plugin/UPnP/MediaRenderer/ProtocolHandler.pm Outdated
…e proxy

Some DLNA servers require the source connection to originate from the
same IP address that was published for the player via UPnP.
So, force the UPnP/DLNA MediaRenderer protocol handler to always use the
server-side proxy path (canDirectStream => 0).

Also change the request header to HTTP/1.1, allowing for the DLNA server
to use chunked transfer-encoding and add support for translating it
back to a contiguous raw data stream in _sysread().

Since canDirectStream is forced off, this handler's requestString(),
response() and _sysread() are only ever exercised by the server's own
outgoing connection to the source, never by player firmware, so they
can safely be overridden per-plugin to add HTTP/1.1 + chunked support
without touching Slim::Player::Protocols::HTTP:

- requestString() rewrites the request line's protocol token to
  HTTP/1.1, leaving every other header untouched.
- response() applies the same rewrite to the request string before
  delegating to the base class, so the HTTP::Request object kept for
  the persistent/reconnect session (if canEnhanceHTTP is set) also
  reports HTTP/1.1, and it arms a small dechunking state machine when
  the response header shows "Transfer-Encoding: chunked".
- _sysread() transparently strips the chunk framing from the raw byte
  stream before it reaches the audio decoder, so DLNA sources that only
  offer chunked responses (no Content-Length) can be streamed correctly.

The player-firmware-facing direct-stream request builder in
Slim::Player::Protocols::HTTP is untouched and still defaults to
HTTP/1.0, so no firmware changes are required.

*note: this commit and message is created with the help of AI*

Signed-off-by: Stefan Sichler <stsichler@web.de>
@stsichler
stsichler force-pushed the feature/http1.1-dlna-streaming branch from 5cf54e3 to fb070df Compare July 30, 2026 08:01

@michaelherger michaelherger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now this looks "local" enough. Let's give it a try. Thanks!

@michaelherger
michaelherger merged commit c7fd46b into LMS-Community:public/9.2 Jul 30, 2026
1 check passed
@stsichler

Copy link
Copy Markdown
Contributor Author

Nice!

@stsichler
stsichler deleted the feature/http1.1-dlna-streaming branch July 30, 2026 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants