Setup Chromecast With Transcoding UPnP Media Server Located On A Different Network

Here are some notes on my configuration that allows the following:

  • Chromecast on wireless subnet to play video
  • Smartphone(s) on wireless subnet using Avia/BubbleUPnP to select video and control Chromecast
  • Mediatomb Linux server, on a different network segment, transcoding any video format to Chromecast format in realtime
  • Linux router at the center with wired and wireless connections

Linux router configuration

eth0 is the interface the transcoding media server is connected to, wlan0 is the wireless interface the Chromecast and controlling smartphone is connected to.

On Linux router, first ensure TTL of all UPnP and mDNS packets is incremented so that packets generated with the default ttl of 1 hop will not be discarded immediately:

iptables -t mangle -A PREROUTING -d 239.255.255.250 -j TTL --ttl-inc 1
iptables -t mangle -A PREROUTING -d 224.0.0.251 -j TTL --ttl-inc 1

Then install smcroute and configure the startup.sh as follows:

# Join all private interfaces to UPnP IGMP group
smcroute -j wlan0 239.255.255.250
smcroute -j eth0 239.255.255.250
# Join all private interfaces to mDNS IGMP group
smcroute -j wlan0 224.0.0.251
smcroute -j eth0 224.0.0.251
# Static route for UPNP traffic from media server to wireless clients
smcroute -a eth0 10.0.1.233 239.255.255.250 wlan0
# Static routes for Traffic from wireless clients to media server.
# Warning: smcroute man page advertises a limitation of 200 static multicast routes.
for (( i = 2 ; i <= 254 ; i++ )); do
  smcroute -a wlan0 172.16.2.$i 239.255.255.250 eth0
done

You can debug missing UPnP traffic with tcpdump -i eth0 -n udp port 1900 for example, while generating a UPnP scan from a wireless client. UPnP Monkey was a useful tool for debugging here by using its ‘refresh’ widget and watching for traffic. Also see here for more information on static multicast routing with Linux.

Mediatomb configuration

You can use the config.xml from here as a starting point. Warning: Customize the account user/password, the folder, and make a direct path to the agent command () so that its availability is not dependent on system PATH.

Replace the contents of the agent command script with the following script (contents were adapted from here):

#!/bin/bash

video=$1
legenda=""
comLegenda=0
#Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding
subtitleStyle="Default,Arial,20,65535,65535,&H0,&H0,0,0,0,1,1,0,2,10,10,10,0,0"

#Levar em conta que as extensões podem estar maiusculas
IFS=$(echo -e "\t\n")
for tmpfile in $(echo $video | sed 's/....$/*/')*; do
    filename=$(basename "$tmpfile")
    extension="${filename##*.}"
    echo $extension
    if [ "$extension" == "ass" ]; then
        echo 'Legenda ASS encontrada'
        legenda=$(echo $video | sed 's/...$/ass/')
        comLegenda=1
    elif [ "$extension" == "srt" ]; then
        echo 'Legenda SRT encontrada'
        legenda=$(echo $video | sed 's/...$/srt/')
        comLegenda=1
    elif [ "$extension" == "ssa" ]; then
        echo 'Legenda SSA encontrada'
        legenda=$(echo $video | sed 's/...$/ssa/')
        comLegenda=1
    elif [ "$extension" == "sub" ]; then
        echo 'Legenda SubRip encontrada'
        legenda=$(echo $video | sed 's/...$/sub/')
        comLegenda=1
    fi

done

if [ $comLegenda == 1 ]; then
    encoding=$(file -bi "$legenda" | sed -e 's/.*[ ]charset=//')
    encoding=`echo "$encoding" | tr [:lower:] [:upper:]`

    ffmpeg -y -sub_charenc "$encoding" -i "$legenda" "/tmp/legenda.ass"
    sed -i '/Style: /c\Style: '$subtitleStyle'' /tmp/legenda.ass
    exec ffmpeg -i "$video" -y -c:v libvpx -b:v 5M -crf 10 -c:a libvorbis -cpu-used 16 -threads 8 -f webm -vf subtitles="/tmp/legenda.ass" -map 0 -map -0:s "$2"

elif [ ${video##*.} == webm ]; then
    exec avconv -i "$video" -y -vcodec copy -acodec copy -f webm "$2"
else
    exec avconv -y -i "$video" -vcodec libvpx -b 4096k -acodec libvorbis -ar 48000 -ac 2 -ab 448000 -threads 2 -deadline realtime -f webm - > "$2"
fi

reset
exit

(Ideally we would use -threads auto, so that the configuration is independent of the number of CPU cores in the server, but due to this bug in libvpx we have to specify a number of encoder threads to spawn.)

After restarting MediaTomb, you should be able to see it in the browse list of the wireless smartphone UPnP client, and you should see your Chromecast as an available renderer. The video should transcode and render in realtime after a short pause at the beginning.

If not, check the above configuration a few times, try watching network traffic with tcpdump while manipulating the client, try running the commandline yourself to transcode the video and see if it succeeds and is fast from the command line.

This is not a simple configuration and there are many pitfalls that may require deeper inspection, but hopefully the above will get you going in the basic case where you have an existing multisegment media network where you want to introduce a Chromecast, and don’t have other complicated requirements for UPnP usage (like dynamic port mapping).

Cross-Subnet Chromecast Usage

This part is for someone who just wants to watch YouTube or cast a browser tab to their Chromecast from a computer that is not on the same wireless subnet as the Chromecast.  Basically, the hard part is getting UPnP and mDNS traffic to the Chromecast.  Say you have a wired subnet connected to interface eth1 and a workstation at IP address 10.10.10.10, and the Chromecast is on subnet wlan0 as before with an IP address of 172.16.10.10. Then your smcroute startup.sh configuration may look something like this (combining some aspects with the above). It’s a little clumsy to have to statically allocate IP addresses to the various actors, but I couldn’t find a better way. Also note the multiple output interfaces for some of the static routes.

# Join all private interfaces to UPnP IGMP group
smcroute -j wlan0 239.255.255.250
smcroute -j eth0 239.255.255.250
smcroute -j eth1 239.255.255.250
# Join all private interfaces to mDNS IGMP group
smcroute -j wlan0 224.0.0.251
smcroute -j eth0 224.0.0.251
smcroute -j eth1 224.0.0.251
# Static route for UPNP traffic from media server to wireless clients
smcroute -a eth0 10.0.1.233 239.255.255.250 wlan0
# Static routes for Traffic from wireless clients to media server.
# Chromecast and phones talk to mediatomb and desktops
smcroute -a wlan0 172.16.10.10 239.255.255.250 eth0 eth1
# Chromecast MDNS traffic
smcroute -a wlan0 172.16.10.10 224.0.0.251 eth0 eth1
# Control wifi chromecast and mediatomb from desktop wired network
smcroute -a eth1 10.10.10.10 239.255.255.250 wlan0 eth0
# Make MDNS requests to chromecast from desktop wired network
smcroute -a eth1 10.10.10.10 224.0.0.251 wlan0

One Response to “Setup Chromecast With Transcoding UPnP Media Server Located On A Different Network”

  1. I have follow all the steps on my Ubuntu server, but its not working for me. is any kernel parameters required for mdns (224.0.0.251) multi-cast routing.

Leave a Reply