Debian: Building a Media Centre With Kodi


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

The previous version of this document that describes building Kodi version 17.6 (codename "Krypton") on Debian GNU/Linux 9.5 (codename "stretch") 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 6GB.

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 360MiB while the size of the repository may be 850MiB 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 10, 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 cmake clang ccache curl pkg-config python-dev \
     autoconf libtool autopoint default-jre swig doxygen graphviz \
     mesa-common-dev libao-dev liblzo2-dev zlib1g-dev libpng-dev libgif-dev \
     libjpeg-dev libasound-dev libavahi-client-dev \
     libavahi-compat-libdnssd-dev libbluetooth-dev libbluray-dev \
     libcap-dev libcec-dev libdbus-1-dev liblcms2-dev liblirc-dev \
     libmicrohttpd-dev libnfs-dev libpulse-dev libsmbclient-dev \
     libsndio-dev libudev-dev libxslt-dev libva-dev libvdpau-dev \
     libplist-dev libass-dev libcdio-dev libiso9660-dev \
     libcurl4-openssl-dev libavcodec-dev libavformat-dev libavdevice-dev \
     libavfilter-dev libavresample-dev libavutil-dev \
     libfmt-dev libfstrcmp-dev libssl-dev rapidjson-dev libsqlite3-dev \
     libtag1-dev libtinyxml-dev libglu1-mesa-dev libegl1-mesa-dev \
     libxrandr-dev libmariadbclient-dev default-libmysqlclient-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 18.3-Leia https://github.com/xbmc/xbmc.git
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 CC=clang
export CXX=clang++
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\$(getconf _NPROCESSORS_ONLN)"
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 shairplay

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

Compiling and Installing flatbuffers

sudo make -C "${HOME}/src/xbmc/tools/depends/target/flatbuffers" PREFIX="${KODI_PFX}"

Compiling and Installing Kodi

sudo ldconfig "${KODI_PFX}/lib"
mkdir "${HOME}/src/xbmc-build"
cd "${HOME}/src/xbmc-build"
cmake ../xbmc -DCMAKE_INSTALL_PREFIX="${KODI_PFX}"
cmake --build . -- -j$(getconf _NPROCESSORS_ONLN)
sudo make install

Package Kodi

sudo tar -C / -cJf "kodi-18.3-$(uname -m).tar.xz" \
	--exclude "${KODI_PFX:1}/share/doc" \
	"${KODI_PFX:1}/"{bin,lib,share}
Upon a successful build, the file kodi-18.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 policykit-1 samba-common-bin sudo x11-xserver-utils xinit zlib1g unzip \
    xz-utils upower pulseaudio libao4 libasound2 libass9 libavahi-client3 \
    libavahi-common3 libavcodec58 libavfilter7 libavformat58 libavutil56 \
    libbluetooth3 libbluray2 libbsd0 libcap2 libcdio18 libcec4 libcurl4 \
    libdbus-1-3 libdrm2 libegl1 libexpat1 libfreetype6 libfribidi0 libfstrcmp0 \
    libgcrypt20 libgif7 libgl1 libglu1-mesa libgpg-error0 libicu63 \
    libiso9660-11 libjpeg62-turbo liblcms2-2 liblirc-client0 liblz4-1 liblzma5 \
    liblzo2-2 libmariadb3 libmicrohttpd12 libnfs12 libpcre3 libpcrecpp0v5 \
    libpng16-16 libpostproc55 libpulse0 libpulse-mainloop-glib0 \
    libpython2.7 libsmbclient libsndio7.0 libsqlite3-0 libssl1.1 \
    libswresample3 libswscale5 libsystemd0 libtag1v5-vanilla \
    libtinyxml2.6.2v5 libudev1 libuuid1 libva2 libva-drm2 libva-x11-2 \
    libvdpau1 libx11-6 libxau6 libxcb1 libxdmcp6 libxext6 libxml2 \
    libxrandr2 libxslt1.1

Enable sudo(8) by adding kodi as a member of the group sudo:

usermod -G sudo -a kodi

Logout and login as kodi.

Installation of Kodi on the Target

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

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

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

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

Create the X server configuration file:

sudo tee /etc/X11/xorg.conf <<EOF
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):

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

chvt 7
exec setsid /sbin/agetty --autologin kodi tty7 &
exit 0
EOF
sudo 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.

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 :-)

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:

sudo tee /etc/network/interfaces <<EOF
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:

sudo tee /etc/hostapd.conf <<EOF
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, July 30th, 2019


I hereby place this article along with the accompanying source code into the public 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.