DLNA/UPnP Servers on Ubuntu

DLNA is great. It allows smart TVs, blu-ray players, phones, laptops etc. to access your Photos, Videos and Music across your network. Once you’ve set it up… it “just works”. The first step in setting it up though, is choosing a DLNA server to run. Ubuntu has a myriad of options in its repositories and there are even some non-free third party options with support for Ubuntu.

dlna-diagram

My setup is relatively simple, I have one LG smart TV and one Ubuntu powered file server housing all my media. Occasionally I use VLC on a laptop to access DLNA shares, but I usually use sFTP instead. Which brings us on to the first issue… Every one of the DLNA servers I’ve tried (MediaTomb, Rygel, MiniDLNA/ReadyMedia, et. al.) relies on inotify to be informed of changes to your media library. If, like me, you usually manage this library over sFTP… then inotify events aren’t triggered and you have to manually reload the DLNA server to pick up file changes.

MediaTomb, however, also offers a “timed” setting. This tells MediaTomb to check for changes to the media library at a defined interval. It’s also not at all resource intensive… in fact, in my example config below, MediaTomb checks for changes every 30 seconds and places an almost immeasurable load on my atom powered server when doing so.

Rygel

An excellent choice if you want to run the DLNA server on your laptop/desktop. Perhaps you don’t have a dedicated server, but you do have a smart TV and would occasionally like to watch media stored on your computer across your network. Rygel has a simple UI and is easily configured by even the most novice of computer users. Whilst it is possible to run it on a headless server, the default packages in the Ubuntu repositories do not provide the scripts required to manage it as a service. It is possible to write your own… but I didn’t find that Rygel offered anything above the other contenders to make this worthwhile.

MiniDLNA/ReadyMedia

An up and coming entry… ReadyMedia (or MiniDLNA as it was previously known and is still called in the repositories) is written by Netgear for their ReadyNAS productline, like the other offerings here, it is completely free and open source (GPLv2).

ReadyMedia was my preferred choice for a while. It’s configuration is far simpler than MediaTomb and it’s not only rock solid in daily use, but is also still being actively developed with both new features and fixes. However, it currently lacks anything other than inotify support for detecting changes to media. Furthermore, simply restarting the service with “sudo service minidlna restart” doesn’t check for new media either. Instead, “sudo service minidlna force-reload” is required, which rebuilds the entire database from scratch every time and is a somewhat lengthy process. If you manage your media files using NFS, or indeed directly on the server, then this shouldn’t be a problem… but if you find you’re usually connected to your server of sFTP for file management, then ReadyMedia probably isn’t for you.

MediaTomb

MediaTomb is fairly old… and it’s fair to say that work on it appears to have slowed over the years. However, there were fresh commits at the end of 2013 and the latest release is still less than a year old. I’d say it’s far from being dead and that actually, the longer release cycles are more to do with the projects maturity than it being dead.

It has more features than most of the other servers out there combined! But better yet… they work! In my testing it has been by far the most stable and reliable software in its field and with this sort of service, that’s what you want. If you’re sitting down to watch a film, or the latest episode of some US series you’ve obtained perfectly legally… the last thing you want to have to do is ssh into your server and restart services, edit configs etc.

My full config is below. It shares media from /home/dan/Videos (which MediaTomb has read-only access to) and it rescans this folder every 30 seconds in case something is changed over sFTP. Simple. You can of course get MediaTomb to do much more, including re-encoding media on the fly if your device isn’t capable of playing it. The configuration can be a little complicated… but then you’d expect that with such a myriad of options. For more detailed config consult the official docs.

<?xml version="1.0" encoding="UTF-8"?>
<config version="2" xmlns="http://mediatomb.cc/config/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mediatomb.cc/config/2 http://mediatomb.cc/config/2.xsd"><!--
     Read /usr/share/doc/mediatomb-common/README.gz section 6 for more
     information on creating and using config.xml configration files.
    -->
  <server>
    <ui enabled="no" show-tooltips="yes">
      <accounts enabled="no" session-timeout="30">
        <account user="mediatomb" password="mediatomb"/>
      </accounts>
    </ui>
    <name>MediaTomb</name>
    <udn>uuid:2da8a510-66e2-4eb2-8aa6-4a9bdf5350e1</udn>
    <home>/var/lib/mediatomb</home>
    <webroot>/usr/share/mediatomb/web</webroot>
    <storage caching="yes">
      <sqlite3 enabled="yes">
        <database-file>mediatomb.db</database-file>
      </sqlite3>
      <mysql enabled="no">
        <host>localhost</host>
        <username>mediatomb</username>
        <database>mediatomb</database>
      </mysql>
    </storage>
    <protocolInfo extend="yes"/><!-- For PS3 support change to "yes" --><!--
       Uncomment the lines below to get rid of jerky avi playback on the
       DSM320 or to enable subtitles support on the DSM units
    --><!--
    <custom-http-headers>
      <add header="X-User-Agent: redsonic"/>
    </custom-http-headers>

    <manufacturerURL>redsonic.com</manufacturerURL>
    <modelNumber>105</modelNumber>
    --><!-- Uncomment the line below if you have a Telegent TG100 --><!--
       <upnp-string-limit>101</upnp-string-limit>
    -->
    <extended-runtime-options>
      <ffmpegthumbnailer enabled="no">
        <thumbnail-size>128</thumbnail-size>
        <seek-percentage>5</seek-percentage>
        <filmstrip-overlay>yes</filmstrip-overlay>
        <workaround-bugs>no</workaround-bugs>
      </ffmpegthumbnailer>
      <mark-played-items enabled="no" suppress-cds-updates="yes">
        <string mode="prepend">*</string>
      </mark-played-items>
    </extended-runtime-options>
  </server>
  <import hidden-files="no">
    <autoscan use-inotify="auto">
      <directory location="/home/dan/Videos" mode="timed" interval="30" level="full" recursive="yes" hidden-files="no"/>
    </autoscan>
    <scripting script-charset="UTF-8">
      <common-script>/usr/share/mediatomb/js/common.js</common-script>
      <playlist-script>/usr/share/mediatomb/js/playlists.js</playlist-script>
      <virtual-layout type="builtin">
        <import-script>/usr/share/mediatomb/js/import.js</import-script>
        <dvd-script>/usr/share/mediatomb/js/import-dvd.js</dvd-script>
      </virtual-layout>
    </scripting>
    <mappings>
      <extension-mimetype ignore-unknown="no">
        <map from="mp3" to="audio/mpeg"/>
        <map from="ogg" to="application/ogg"/>
        <map from="asf" to="video/x-ms-asf"/>
        <map from="asx" to="video/x-ms-asf"/>
        <map from="wma" to="audio/x-ms-wma"/>
        <map from="wax" to="audio/x-ms-wax"/>
        <map from="wmv" to="video/x-ms-wmv"/>
        <map from="wvx" to="video/x-ms-wvx"/>
        <map from="wm" to="video/x-ms-wm"/>
        <map from="wmx" to="video/x-ms-wmx"/>
        <map from="m3u" to="audio/x-mpegurl"/>
        <map from="pls" to="audio/x-scpls"/>
        <map from="flv" to="video/x-flv"/>
        <map from="mkv" to="video/x-matroska"/>
        <map from="mka" to="audio/x-matroska"/><!-- Uncomment the line below for PS3 divx support --><!-- <map from="avi" to="video/divx"/> --><!-- Uncomment the line below for D-Link DSM / ZyXEL DMA-1000 --><!-- <map from="avi" to="video/avi"/> -->
      </extension-mimetype>
      <mimetype-upnpclass>
        <map from="audio/*" to="object.item.audioItem.musicTrack"/>
        <map from="video/*" to="object.item.videoItem"/>
        <map from="image/*" to="object.item.imageItem"/>
        <map from="application/ogg" to="object.item.audioItem.musicTrack"/>
      </mimetype-upnpclass>
      <mimetype-contenttype>
        <treat mimetype="audio/mpeg" as="mp3"/>
        <treat mimetype="application/ogg" as="ogg"/>
        <treat mimetype="audio/x-flac" as="flac"/>
        <treat mimetype="image/jpeg" as="jpg"/>
        <treat mimetype="audio/x-mpegurl" as="playlist"/>
        <treat mimetype="audio/x-scpls" as="playlist"/>
        <treat mimetype="audio/x-wav" as="pcm"/>
        <treat mimetype="audio/L16" as="pcm"/>
        <treat mimetype="video/x-msvideo" as="avi"/>
        <treat mimetype="video/mp4" as="mp4"/>
        <treat mimetype="audio/mp4" as="mp4"/>
        <treat mimetype="application/x-iso9660" as="dvd"/>
        <treat mimetype="application/x-iso9660-image" as="dvd"/>
        <treat mimetype="video/x-matroska" as="mkv"/>
        <treat mimetype="audio/x-matroska" as="mka"/>
      </mimetype-contenttype>
    </mappings>
    <online-content><!-- Make sure to setup a transcoding profile for flv -->
      <YouTube enabled="no" refresh="28800" update-at-start="no" purge-after="604800" racy-content="exclude" format="flv" hd="no">
        <favorites user="mediatomb"/>
        <standardfeed feed="most_viewed" time-range="today"/>
        <playlists user="mediatomb"/>
        <uploads user="mediatomb"/>
        <standardfeed feed="recently_featured" time-range="today"/>
      </YouTube>
      <Weborama enabled="no" refresh="28800" update-at-start="no">
        <playlist name="Active" type="playlist" mood="active"/>
        <playlist name="Metal" type="playlist">
          <filter>
            <genres>metal</genres>
          </filter>
        </playlist>
      </Weborama>
      <AppleTrailers enabled="no" refresh="43200" update-at-start="no" resolution="640"/>
    </online-content>
  </import>
  <transcoding enabled="no">
    <mimetype-profile-mappings>
      <transcode mimetype="video/x-flv" using="vlcmpeg"/>
      <transcode mimetype="application/ogg" using="vlcmpeg"/>
      <transcode mimetype="application/ogg" using="oggflac2raw"/>
      <transcode mimetype="audio/x-flac" using="oggflac2raw"/>
    </mimetype-profile-mappings>
    <profiles>
      <profile name="oggflac2raw" enabled="no" type="external">
        <mimetype>audio/L16</mimetype>
        <accept-url>no</accept-url>
        <first-resource>yes</first-resource>
        <accept-ogg-theora>no</accept-ogg-theora>
        <agent command="ogg123" arguments="-d raw -o byteorder:big -f %out %in"/>
        <buffer size="1048576" chunk-size="131072" fill-size="262144"/>
      </profile>
      <profile name="vlcmpeg" enabled="no" type="external">
        <mimetype>video/mpeg</mimetype>
        <accept-url>yes</accept-url>
        <first-resource>yes</first-resource>
        <accept-ogg-theora>yes</accept-ogg-theora>
        <agent command="vlc" arguments="-I dummy %in --sout #transcode{venc=ffmpeg,vcodec=mp2v,vb=4096,fps=25,aenc=ffmpeg,acodec=mpga,ab=192,samplerate=44100,channels=2}:standard{access=file,mux=ps,dst=%out} vlc:quit"/>
        <buffer size="14400000" chunk-size="512000" fill-size="120000"/>
      </profile>
    </profiles>
  </transcoding>
</config>