Debian: Building a Media Centre With Kodi


This article explains how to compile and install an unreleased version of Kodi (version 18.0b1, codename "Leia") on the current version of Debian GNU/Linux (version 9.5, codename "stretch") and deploy the software on an Intel NUC NUC5i3RYH.

The current 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.

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.

Work in Progress

I would like to emphasize that this version of the article describes a beta version of Kodi. You are encouraged to stop reading now and follow instead the instructions for the current version unless you wish to experience a preview of the future release of Kodi.

While preparing this article, I encountered the following issues:

Leia is the first series of Kodi that supports several windowing systems: in addition to the tried-and-true X Window, Kodi has introduced support for Wayland. I have yet to decide whether Wayland offers any advantage over X Window in the setup that I describe, therefore I plan to provide instructions for building for both, as long as I have not made a decision in favour of one of them.

Kodi Leia has also introduced support for GBM, a rendering API of Mesa which I have not a chance to try for it failed to identify my graphics hardware.

The performance of this version of Kodi is far from perfect, the major problem that I faced with both X11 and Wayland builds was choppy sound during video (but not audio) playback, which I should investigate further. Also, I percieved no difference in performance of the X11 build versus the one for Wayland. I admit however, that I did not bother to compare utilisation of system resources in both cases.

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.

The Kodi's build system pulls source code of some of its dependencies from the Internet during the build. Please make sure that you have a functioning Internet connection when building.

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 337MiB while the size of the repository may be 507MiB 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.5, install development tools and libraries (you may have some of these packages already installed, apt-get(8) will safely skip those):

sudo apt-get install git curl nasm g++ make cmake ccache automake autopoint \
    libtool uuid-dev xz-utils pkg-config doxygen libwayland-bin \
    libwayland-dev libegl1-mesa-dev libwayland-egl1-mesa \
    liblzo2-dev zlib1g-dev libpng-dev libasound-dev libavahi-client-dev \
    libbluetooth-dev libbluray-dev libcap-dev libcec-dev liblcms2-dev \
    liblirc-dev libmicrohttpd-dev libpulse-dev python-dev libsmbclient-dev \
    libsndio-dev libudev-dev libxml2-dev libxslt-dev libass-dev libva-dev \
    libvdpau-dev libnfs-dev libplist-dev libcdio-dev libiso9660-dev \
    libcurl4-openssl-dev libcurl4-openssl-dev libfstrcmp-dev libssl-dev \
    libsqlite3-dev libtag1-dev libtinyxml-dev libxkbcommon-dev libglu-dev \
    libmariadbclient-dev default-libmysqlclient-dev default-jre swig \
    libgif-dev libjpeg-dev libpciaccess-dev libxrandr-dev \
    libgbm-dev libinput-dev libgles2-mesa-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.0b1-Leia https://github.com/xbmc/xbmc.git
curl -o - 'https://dri.freedesktop.org/libdrm/libdrm-2.4.93.tar.gz' \
    | tar -xzf -

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="\${KODI_PFX}/include"
export CPLUS_INCLUDE_PATH="\${KODI_PFX}/include"
export LIBRARY_PATH="\${KODI_PFX}/lib"
export LD_LIBRARY_PATH="\${KODI_PFX}/lib"
export PKG_CONFIG_PATH="\${KODI_PFX}/lib/pkgconfig:\${KODI_PFX}/share/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 libdrm

cd "${HOME}/src/libdrm-2.4.93"
./configure "--prefix=${KODI_PFX}"
make
sudo make install

Compiling and Installing RapidJSON

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

Compiling and Installing crossguid

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

Compiling and Installing flatbuffers

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

Compiling and Installing libfmt

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

Compiling and Installing wayland-protocols

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

Compiling and Installing waylandpp

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

Configuration of the Kodi Build System

Please note that there are three options of configuring Kodi with regard to the rendering system: X11, Wayland, or Mesa GBM. You must select one of the three options given below.

Create the Kodi Build Directory

mkdir "${HOME}/src/xbmc-build"

Update the Cache of ld.so(8)

sudo ldconfig "${KODI_PFX}/lib"

Override the FindLibDRM.cmake Script

Note: this step is necessary for preventing the Kodi's build system from noticing the Debian's version of libdrm. The following is an awful hack which is required because cmake(1), whithout any shame, ignores (Yes, it does—at least the version that is distributed with Debian 9.5) the environment variable PKG_CONFIG_PATH that I have set above to point to "${KODI_PFX}/lib/pkgconfig" where libdrm*.pc files are installed. I override FindLibDRM.cmake inside the empty build directory, without modifying Kodi's source or any of the system files:

cat <<EOF > "${HOME}/src/xbmc-build/FindLibDRM.cmake"
set(LIBDRM_FOUND true)
set(LIBDRM_INCLUDE_DIR ${KODI_PFX}/include/libdrm)
set(LIBDRM_VERSION $(pkg-config --modversion libdrm))
set(LIBDRM_LIBRARY ${KODI_PFX}/lib/libdrm.so)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibDRM
    REQUIRED_VARS LIBDRM_LIBRARY LIBDRM_INCLUDE_DIR
    VERSION_VAR LIBDRM_VERSION)

set(LIBDRM_LIBRARIES \${LIBDRM_LIBRARY})
set(LIBDRM_INCLUDE_DIRS \${LIBDRM_INCLUDE_DIR})

if(NOT TARGET LIBDRM::LIBDRM)
    add_library(LIBDRM::LIBDRM UNKNOWN IMPORTED)
    set_target_properties(LIBDRM::LIBDRM PROPERTIES
        IMPORTED_LOCATION "\${LIBDRM_LIBRARY}"
        INTERFACE_INCLUDE_DIRECTORIES "\${LIBDRM_INCLUDE_DIR}")
endif()

mark_as_advanced(LIBDRM_INCLUDE_DIR LIBDRM_LIBRARY)
EOF

Option 1: Configure Kodi's Build System for X11

cd "${HOME}/src/xbmc-build"
cmake ../xbmc -DCMAKE_INSTALL_PREFIX="${KODI_PFX}" -DCMAKE_MODULE_PATH="$(pwd)"

Option 2: Configure Kodi's Build System for Wayland

cd "${HOME}/src/xbmc-build"
cmake ../xbmc -DCMAKE_INSTALL_PREFIX="${KODI_PFX}" -DCMAKE_MODULE_PATH="$(pwd)" \
    -DCORE_PLATFORM_NAME=wayland \
    -DWAYLAND_RENDER_SYSTEM=gl

Option 3: Configure Kodi's Build System for GBM

cd "${HOME}/src/xbmc-build"
cmake ../xbmc -DCMAKE_INSTALL_PREFIX="${KODI_PFX}" -DCMAKE_MODULE_PATH="$(pwd)" \
    -DCORE_PLATFORM_NAME=gbm \
    -DGBM_RENDER_SYSTEM=gles

Compiling and Installing Kodi

cd "${HOME}/src/xbmc-build"
cmake --build . -- -j$(getconf _NPROCESSORS_ONLN)
sudo make install

Package Kodi

sudo tar -C / -cJf "kodi-18.0b1-$(uname -m).tar.xz" "${KODI_PFX:1}/"{bin,lib,share} \
    --exclude "${KODI_PFX:1}/share/doc"
Upon a successful build, the file kodi-18.0b1-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. This particular collection of packages will allow running Kodi with any rendering system—X11, Wayland, or GBM:

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

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

sed -i -e 's/^sudo:\(.*\)$/sudo:\1kodi/' /etc/group

Logout and login as kodi.

Installation of Kodi on the Target

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

sudo tar -C / -xJf kodi-17.6-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

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
sudo chmod 500 /etc/rc.local
The above will instruct system startup scripts to login the user kodi automatically on the seventh virtual terminal.

Option 1: Configure Kodi for X Window

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

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.

Option 2: Configure Kodi for Wayland

Create the weston(1) configuration file:

mkdir "${HOME}/.config"
cat <<EOF > "${HOME}/.config/weston.ini"
[core]
xwayland=false

[keyboard]
keymap_layout=us

[shell]
background-image=
panel-location=none

[output]
name=LVDS1
mode=1920x1080
transform=90

Modify the shell profile of the user kodi:

cat <<EOF > "${HOME}/.profile"
if [ "\${XDG_VTNR}" = "7" ]; then
    weston --tty=7 &
    while true; do
        /opt/kodi/bin/kodi-standalone
    done
fi
EOF
When the user kodi logs into the system on the seventh virtual terminal, the script above will start weston(1) once and then will keep re-launching the Kodi binary ad infinitum. This approach allows for restarting Kodi by selecting the option Exit from its main menu.

Permit the user kodi to launch weston(1):

sed -i -e 's/^weston-launch:\(.*\)$/weston-launch:\1kodi/' /etc/group

Finish the Installation

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, August 26th, 2018


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.