Debian: Building a Media Centre With Kodi


This article explains how to compile and install a fairly recent version of Kodi (version 17.3, codename "Krypton") on the current version of Debian GNU/Linux (version 9.0, codename "stretch") and deploy the software on an Intel NUC NUC5i3RYH.

The previous version of this document that describes building Kodi version 17.1, codename "Krypton" on Debian GNU/Linux 8.8 (codename "jessie") can be found here.

A version of this document that describes building Kodi version 17.1, codename "Krypton" on Devuan 1.0 (codename "jessie") can be found here.

The reader may like to try the instructions given below because the official instructions for building Kodi are, unfortunately, given for Debian or Ubuntu, which are not quite the same operating system: the official instructions, when followed literally, do not work on Debian, which may confuse inexperienced users to the point of abandoning the idea. In addition, the official instructions do not specify the intended versions of those systems, which complicates matters even further. To amend that, I attempt to describe a recipe that is actually reproducible. Besides that, I offer a way of configuring a dedicated media appliance that should be as secure as Debian: Kodi runs using a non-privileged user account on a minimal, unmodified system which remains upgradeable. I do not claim building a system that has the best performance though: you may need to tinker with the setup further if you are not satisfied with the result. I do promise however, that this setup will work if the hardware is supported by Debian.

I selected the Intel NUC NUC5i3RYH for the price/performance ratio that the platform offers. In addition, I like the form factor of the system: it is small—finding a place for such a device should not be a problem even in a very much cluttered living room. Another useful datum about the machine is its temperature operating range: I witnessed it decoding network video streams for hours without a glitch in a hot environment (there was above 38°C outside for several days in a row and no air conditioning inside), without additional ventilation. I also found that there is no need for a hard drive: the system works well while running off a cheap 8GB SanDisk CruzerFit USB 2.0 Flash drive, having a plenty of free storage (only about 1.5GB are occupied by the complete system). A CruzerFit drive is a perfect companion to a NUC: due to the form factor of the drive, it is not very noticeable when inserted into a USB socket on the back panel; certainly, it does not contribute to the overall dimensions of the setup.

Compilation

Please note that you must compile Kodi on a machine having the same architecture as the target, i.e. if your target is amd64 you must compile on an amd64 system. Cross-compilation is more complex and requires additional software and operations; it is out of the scope of this article.

The build process requires a considerable amount of free disk space. If you compile Kodi on a virtual machine, please allocate a virtual disk of at least 9GB.

The instructions given below are valid for the software versions mentioned above, on the amd64 architecture. I did not attempt reproducing instructions given below on another architecture.

I assume that sudo(1) is installed and configured.

If you install software packages from a network mirror, please take into account that it may make perfect sense to install them in parallel with fetching the source code from the Kodi's git repository (the size of packages may be as large as 280MiB while the size of the repository may be 530MiB or larger). In that case, if you do not have git already installed, install git first, separately from the rest of the packages listed below, and then proceed to performing these two tasks in parallel.

Installing Development Tools and Libraries

On a (virtual) machine running Debian 9.0, install development tools and libraries (you may have some of these packages already installed, apt-get will safely skip those):

sudo apt-get install git \
        automake autopoint bison build-essential ccache cmake curl cvs \
        default-jre fp-compiler gawk gdc gettext gperf libasound2-dev \
        libass-dev libavcodec-dev libavfilter-dev libavformat-dev \
        libavutil-dev libbluetooth-dev libboost-dev libboost-thread-dev \
        libbz2-dev libcap-dev libcdio-dev libcrystalhd-dev libcrystalhd3 \
        libcurl3 libcurl4-gnutls-dev libcwiid-dev libcwiid1 libdbus-1-dev \
        libenca-dev libflac-dev libfontconfig1-dev libfreetype6-dev \
        libfribidi-dev libglew-dev libiso9660-dev \
        libjpeg-dev libltdl-dev liblzo2-dev libmad0-dev libmicrohttpd-dev \
        libmodplug-dev libmp3lame-dev libmpeg2-4-dev libmpeg3-dev \
        libnfs-dev libogg-dev libpcre3-dev libplist-dev \
        libpng-dev libpostproc-dev libpulse-dev libsamplerate0-dev \
        libsdl1.2-dev libsdl-gfx1.2-dev libsdl-image1.2-dev \
        libsdl-mixer1.2-dev libsmbclient-dev libsqlite3-dev libssh-dev \
        libswscale-dev libtiff5-dev libtinyxml-dev libtool \
        libudev-dev libusb-dev libva-dev libva-egl1 libva-tpi1 libvdpau-dev \
        libvorbisenc2 libxml2-dev libxmu-dev libxrandr-dev libxrender-dev \
        libxslt1-dev libxt-dev libyajl-dev mesa-utils nasm pmount \
        python-dev python-imaging python-sqlite swig unzip yasm zip \
        zlib1g-dev libtag-extras-dev libgnutls28-dev \
        uuid-dev libgif-dev libsdl2-dev liblcms2-dev xz-utils \
        libssl1.0-dev default-libmysqlclient-dev libcrossguid-dev \
        libavahi-client-dev libbluray-dev libp8-platform-dev libcec-dev

Pulling Source Code

There is not much to say, the following commands fetch the required source code into a working directory. The following assumes that you keep all of the source code under ${HOME}/src.

mkdir -p "${HOME}/src"
cd "${HOME}/src"
git clone -b 17.3-Krypton https://github.com/xbmc/xbmc.git
git clone https://gitlab.com/vadimp/kodi-mdnsresponder
git clone https://github.com/juhovh/shairplay.git

Environment Variables

The toolchain requires setting a number of environment variables. To avoid permanent modifications to your build machine that may conflict with other tasks that you may perform, I propose having a separate file that contains required definitions. You can source this file into your shell whenever required.

Create the file is as follows:

cat > "${HOME}/src/kodi-build-vars.sh" <<EOF
export KODI_PFX='/opt/kodi'
export C_INCLUDE_PATH="\${C_INCLUDE_PATH}:\${KODI_PFX}/include"
export CPLUS_INCLUDE_PATH="\${CPLUS_INCLUDE_PATH}:\${KODI_PFX}/include"
export LIBRARY_PATH="\${LIBRARY_PATH}:\${KODI_PFX}/lib"
export LD_LIBRARY_PATH="\${LD_LIBRARY_PATH}:\${KODI_PFX}/lib"
export PKG_CONFIG_PATH="\${PKG_CONFIG_PATH}:\${KODI_PFX}/lib/pkgconfig"
export PATH="\${PATH}:\${KODI_PFX}/bin"
export MAKEFLAGS="-j$((1 + $(/sbin/sysctl -a 2>/dev/null \
    | grep -E 'kernel\.sched_domain\.cpu[[:digit:]]+' \
    | cut -d. -f3 \
    | cut -b4- \
    | sort -n \
    | tail -1)))"
EOF
The above assumes that you intend to install Kodi under /opt/kodi, if that is not the case, please modify the value of KODI_PFX accordingly.

You can source it into your running shell as follows:

source "${HOME}/src/kodi-build-vars.sh"

Compiling and Installing libshairplay

cd "${HOME}/src/shairplay"
./autogen.sh
./configure "--prefix=${KODI_PFX}"
make
sudo make install

Compiling and Installing mDNSResponder

cd "${HOME}/src/kodi-mdnsresponder"
make
sudo sh -c "PREFIX=\"${KODI_PFX}\" make install"

Compiling and Installing Kodi

sudo ldconfig "${KODI_PFX}/lib"
cd "${HOME}/src/xbmc"
./bootstrap
./configure "--prefix=${KODI_PFX}" --enable-mid
make
sudo make install

Package Kodi

sudo tar -C / -cJf "kodi-17.3-$(uname -m).tar.xz" "${KODI_PFX:1}/"{bin,lib,share} \
    --exclude "${KODI_PFX:1}/share/doc"
Upon a successful build, the file kodi-17.3-architecture.tar.xz will contain the binary distribution of Kodi. This is the end product of compilation, keep this file ready for installation on the target machine.

Installation of the Base Debian System for the Target

The easiest way of installing Debian for the target machine is performing network installation directly onto the USB drive. For instance, you may configure a VirtualBox VM without a virtual disk, attach the physical USB drive to the VM and boot the VM from the netinst ISO image inserted into the virtual CD-ROM drive. Assuming that you skipped adding a virtual disk to the VM, the USB drive will appear as /dev/sda inside the VM. Proceed with the regular Debian installation but mark only the "SSH server" option in the software selection dialog and unmark everything else. I assume that you created a regular user account kodi during the installation. The above will yield a minimal system that accepts SSH connections.

Installation of Kodi Dependencies on the Target

Insert the USB drive into the target machine and boot. You can either connect to the target using SSH (I leave figuring out the IP address of the target as an exercise to the reader. Hint: by default, the target's NIC will be configured with DHCP. There must be a sticker with the MAC address of the target, configure your DHCP server to allocate a known address for the target) or connect a monitor and a keyboard directly to the target.

Login as root and install required software packages with all dependencies:

apt-get -y install \
        dbus libasn1-8-heimdal libasound2 libass5 libasyncns0 \
        libattr1 libavahi-client3 libavahi-common3 libbluetooth3 libbsd0 \
        libbz2-1.0 libcap2 libcdio13 libcomerr2 libcrystalhd3 \
        libcurl3-gnutls libdbus-1-3 libdrm2 libexpat1 libffi6 libflac8 \
        libfreetype6 libfribidi0 libgcrypt20 libgl1-mesa-glx \
        libglapi-mesa libglew2.0 libglu1-mesa libgmp10  libgnutls-dane0 \
        libgpg-error0 libgssapi3-heimdal libgssapi-krb5-2 \
        libhcrypto4-heimdal libheimbase1-heimdal \
        libheimntlm0-heimdal libhogweed4 libhx509-5-heimdal libice6 \
        libjbig0 libjpeg62-turbo libjson-c3 libk5crypto3 \
        libkeyutils1 libkrb5-26-heimdal libkrb5-3 libkrb5support0 \
        libldap-2.4-2 libldb1 liblzma5 liblzo2-2 libmad0 \
        libmicrohttpd12 libnettle6 libntdb1 libogg0 libp11-kit0 libpcre3 \
        libpcrecpp0v5 libpng16-16 libpulse0 libpython2.7 \
        libroken18-heimdal libsasl2-2 libsm6 libsmbclient libsndfile1 \
        libsqlite3-0 libssh-4 libssl1.1 libsystemd0 libtag1v5-vanilla \
        libtalloc2 libtasn1-6 libtdb1 libtevent0 libtiff5 libtinyxml2.6.2v5 \
        libudev1 libuuid1 libva1 libva-x11-1 libvorbis0a libvorbisenc2 \
        libwbclient0 libwind0-heimdal libwrap0 libx11-6 libx11-xcb1 libxau6 \
        libxcb1 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0 \
        libxcb-render0 libxcb-shape0 libxcb-sync1 libxcb-xfixes0 \
        libxdamage1 libxdmcp6 libxext6 libxfixes3 libxi6 libxml2 libxmu6 \
        libxrandr2 libxrender1 libxshmfence1 libxslt1.1 libxt6 libxtst6 \
        libxxf86vm1 libyajl2 policykit-1 samba-libs sudo x11-xserver-utils \
        xinit zlib1g unzip libsdl2-2.0-0 liblcms2-2 xz-utils upower \
        libmariadbclient18 libcrossguid0 \
        libavahi-client3 libbluray1 libp8-platform2 libcec4
        libvdpau1 libva-drm1 pulseaudio
The instructions below assume that the user kodi is allowed to use sudo(8). Add kodi as a member of the group sudo by editing /etc/groups.

Logout and login as kodi.

Installation of Kodi on the Target

Transfer the archive kodi-17.3-architecture.tar.xz to the target and extract it to /:

sudo tar -C / -xJf kodi-17.3-architecture.tar.xz

Inform ld.so(8) about Kodi's libraries:

cat <<EOF | sudo tee /etc/ld.so.conf.d/kodi.conf
/opt/kodi/lib
EOF
sudo ldconfig

Create the X server configuration file:

cat <<EOF | sudo tee /etc/X11/xorg.conf
Section "ServerLayout"
    Identifier     "X Server"
    Screen      0  "Screen0" 0 0
EndSection

Section "Files"
    ModulePath   "/usr/lib/xorg/modules"
    FontPath     "/usr/share/fonts/X11/misc"
    FontPath     "built-ins"
EndSection

Section "Module"
    Load  "glx"
EndSection

Section "Monitor"
    Identifier   "Monitor0"
    VendorName   "Monitor Vendor"
    ModelName    "Monitor Model"
EndSection

Section "Device"
    Option      "AccelMethod" "sna"
    Identifier  "Card0"
    Driver      "intel"
    BusID       "PCI:0:2:0"
EndSection

Section "Screen"
    Identifier "Screen0"
    Device     "Card0"
    Monitor    "Monitor0"
    SubSection "Display"
        Viewport   0 0
        Depth     24
    EndSubSection
EndSection
EOF

There are several ways of launching Kodi on startup, I prefer the old-school rc.local(5):

cat <<EOF | sudo tee /etc/rc.local
#!/bin/sh

exec setsid /sbin/agetty --autologin kodi tty7 &
exit 0
EOF
chmod 500 /etc/rc.local
The above will instruct system startup scripts to login the user kodi automatically on the seventh virtual terminal.

Modify the shell profile of the user kodi:

cat <<EOF >> "${HOME}/.profile"

while [ "\${XDG_VTNR}" = "7" ]; do
        startx /opt/kodi/bin/kodi-standalone -- "vt\${XDG_VTNR}"
done
EOF
The script above will keep starting the X server and launching the Kodi binary when the user kodi logs into the system on the seventh virtual terminal. This approach allows for restarting Kodi by selecting the option Exit from its main menu.

Since starting the X server is a privileged operation, you need to permit any user of the target system to start X. On Debian, this is accomplished by reconfiguring Xwrapper.config(5) using the following command:

dpkg-reconfigure xserver-xorg-legacy
and selecting the option anybody in the dialog that appears.

Remove downloaded archives of software packages:

sudo rm /var/cache/apt/archives/*.deb

That is all. Kodi should be up and running after the next reboot.

I admit that I have not tested every feature of this setup. Usually I resolve issues as they come. If you find that something does not work, the first thing to do is to check the file /home/kodi/.kodi/temp/kodi.log for any error messages. Most probably, the issue will be resolved by installing a software package. At very least, this setup is a solid ground for further tinkering with the system :-)

Recommended: Create Samba Cache

If you access SMB/CIFS shares from Kodi, you will eventually notice that it attempts to store information under /var/cache/samba and fails because this directory is missing.

While Kodi does function without that cache, you should like to fix that issue unless you have a specific reason for not doing so:

sudo install -d -m 1770 -g kodi /var/cache/samba

Optional: Turn the Target Into a WiFi Hotspot

I find it convenient to control Kodi from the Android "family tablet" that we have in our drawing-room. We use this tablet for quick Internet browsing, reading e-books to children, and for playing games occasionally. Since, without an external antenna, the signal from the wireless adapter of the NUC basically disappears within three metres outside of the walls of the house, I do not consider using the NUC as a hotspot to be a security risk. The official Kodi remote for Android works quite well, so we use the tablet also for controlling Kodi. Parents have the Kodi remote installed on smartphones, "just in the case". I consider making this hotspot unprotected in the future as a service to our guests.

If you like the idea, the recipe follows.

Caution: the configuration below will enable authorised connecting devices to receive an IP address from the DHCP server and access other machines on the LAN. You ought to prevent unrestricted access to the LAN using the packet filter on the target. Please do not proceed if you are not sure that you know how to do that properly.

As a much more secure alternative, you may consider turning the target into a proper router with network address translation and packet filtering that offers its own DHCP service to connecting WiFi devices.

Again, please be careful—I cannot emphasize that enough.

Install Software Packages

Enable installation of software packages from the non-free collection (this is required for installation of the firmware for the NUC's WiFi adapter):

sudo sed 's/ stretch main$/ stretch main non-free/' -i /etc/apt/sources.list

Update the list of available packages and install the required ones:

sudo apt-get update
sudo apt-get install firmware-iwlwifi bridge-utils hostapd

Configure Network Parameters

Since Debian switched to predictable names of network interfaces, there is no way of knowing these names in advance. Before you continue, take a look at the list of interface names:

ls /sys/class/net
You should see three names: lo (the name of the loopback interface), a name that begins with enp (this is the name of the wired interface), and a name that begins with wlp (this is the name of the wireless interface). For instance, on my machine, I see lo, enp0s25, and wlp2s0. In the instructions given below I use these names, please carefully replace them with the names that you find on your system.

Change the network configuration of the target to bridge the WiFi adapter to the wired one:

cat <<EOF | sudo tee /etc/network/interfaces
auto lo br0
iface lo inet loopback
iface enp0s25 inet manual
iface br0 inet dhcp
    bridge_ports enp0s25
EOF

Create the file /etc/hostapd.conf while replacing kodi-ssid, kodi-channel, and kodi-passphrase below with values of your choice:

cat <<EOF | sudo tee /etc/hostapd.conf
interface=wlp2s0
driver=nl80211
bridge=br0
ssid=kodi-ssid
hw_mode=g
channel=kodi-channel
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=3
wpa_passphrase=kodi-passphrase
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
EOF

Enable hostapd:

sudo sed 's/^#DAEMON_CONF=""$/DAEMON_CONF="\/etc\/hostapd.conf"/' \
    -i /etc/default/hostapd
and reboot.

Vadim Penzin, June 29th, 2017


I hereby place this article along with the accompanying source code into the public domain.
You are welcome to contact me by writing to howto at this domain.
I publish this information in the hope that it will be useful, but without ANY WARRANTY.
You are responsible for any and all consequences that may arise as the result of using this information.