This is only a short and very rough HowTo about connecting an external UPNP-Mediaserver to your local PS3 using squid as a proxy to avoid latency problems on the internet.
Nowadays I was facing the problem that I wanted to utilize a friends Media-Server within my local LAN. Since [http://de.wikipedia.org/wiki/Universal_Plug_and_Play UPnP] only works within a single-network segment I needed some kind of a “proxy”, that advertises the capabilities of the media-server within my network.
All steps that I’ve described here are still work in progress. The code is not very nice yet and most of it is still just a proof-of-concept. Nevertheless it’s working
My first idea was to extend the MediaTomb software that is already running on my local server, but soon I found that I had to less practice with coding in C.
So I was searching for some alternatives in other programming languages that I’m more familiar with. I ended up with “good old” Perl
I also found some help for the first-start at Sourceforge. Also the German Wikipedia explained the mechanism of Upnp-advertisments quite well. Based on this information I was really emphasised and thought this will be an easy to solve problem.
A very handy tool is Cidero. It helps you to find out wether or not you receive your UPnP-advertisments.
In the beginnig everything looked quite easy. My plan was to write a small daemon that should run on my local machine and simply send the SSDP messages for the foreign server.
Therefore I only need to take the default-SSDP and push it periodically to 18.104.22.168 port 1900 of course using UDP
NOTIFY * HTTP/1.1
SERVER: Linux/22.214.171.124 UPnP/1.0 Mediaserver/1.0
Well it turned out, that this did not work. Using tcpdump and wireshark I found that a media-server is sending more than only one advertisment. It advertises all single
services it provides. So I ended up in sending 5 SSDP messages:
the so called "upnp:rootdevice"
the USN it self
I implemented all of this and the foreign media-server showed up in the cidero-controller and I was happy. Immediatly after that I switched on my PS3 and was disappointed. For what-ever reason the device didn’t show up. Anyway my local MediaTomb did, so it couldn’t be a network-problem.
After some tests I found out, that the PS3 is a little bit picky regarding the advertisments. It seems like it is not possible to send an advertisment from a different IP address than the one that is offering the service. It also seems like the PS3 is double-checking the IGMP-memberships and comparing the advertisment records to the IP of the sender.
It was hard to know what to do now. I didn’t want to copy all the content of the foreign server to my local machine and I also didn’t want to dump all advertisments and xml-documents manually to my system.
What I ended up with is the following trick:
- my local attach:myupnp-proxy:upnp-proxy advertises the foreign USN on it’s local IP-address and port (but it does not handle the port)
- I added a rule in IP-tables that redirects all traffic going to my local system to the foreign-IP address
DNAT tcp -- eth0 * 0.0.0.0/0 10.16.1.15 tcp dpt:49152 to:10.0.3.252:49152
This worked quite well. I was able to see the media-server within Cidero and on my PS3. I was also able to choose some songs and play then. But now I was facing a bigger
problem. The music had interruptions from time to time. It’s not very funny to listen to music that stucks within the track. I soon found that the latency within the
network has to be the reason. 40-50 ms round-trip seems to be to high for the buffer that the PS3 uses. A tcp-dump showed a lot of interrupted tracks and partially requested
content. So I had to find a buffering solution. Since all data is transferred via HTTP my decision was to use SQUID for it and install it as a transparent proxy
What I ended up with is the following scenario:
- All messages going to the foreign media-server (correct port) received on my primary interface will be forwarded to the transparent-proxy (on a different local-IP).
- The HTTP-headers are set correctly by the media-player so Squid knows where to get the real data from.
DNAT tcp -- eth0 * 0.0.0.0/0 10.0.3.252 tcp dpt:49152 to:10.16.1.20:49153
The foreign-network is connected via an open-VPN connection that is also terminated on my server. So I need a MASQUERADE rule in the POSTROUTING process.
Hey! This is great I thought. Now SQUID is in between and everything will work. => Nope! I was wrong. The music still stucked. It took a while until I found the prefetch-
parameters for the partial content. Here they are:
cache_mem 32 MB
maximum_object_size_in_memory 8 MB
maximum_object_size 20480 KB
read_ahead_gap 20 MB
range_offset_limit 20 MB
I had to deactivate this line as well:
#refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
Now everything is working quite good, but I’m sure the squid-parameters still can be optimized a little bit. It tooks 1-2 seconds until a track starts, but then it streams
I don’t know if this also works with videos. Maybe the Squid-Settings have to be adjusted. Of course if the video has more bandwidth than you can download you need a
bigger buffer. I don’t know how good this will really work. For MP3 it’s absolutely fine.
I would be happy to get some feedback from you wether or not this article was interesting for you. For your questions or annotations just drop me an email.