# Introduction

LibreELEC is a minimalist 'Just enough OS' Linux distribution for running [Kodi](https://kodi.tv). Our documentation can help you install and configure LibreELEC to run Kodi, or develop and build installation images using our buildsystem.

Documentation is authored and maintained by LibreELEC users. If you see something is incorrect or missing please click the GitBook link below to join our documentation team. The GitBook online app makes changing documentation simple, with your changes sent directly to our [documentation repo on GitHub](https://github.com/LibreELEC/documentation) as a pull-request that project staff can review and merge.

<https://app.gitbook.com/invite/-MLu6vC60WCTrc5ntH0o/-MLu6xOKP1FP_QoIzYwk>

{% hint style="info" %}
Please do not be concerned about your English language skills when contributing changes to our documentation. It is easier for a native speaker to merge your content and then make corrections than to write everything themselves.
{% endhint %}

All content is licensed under the Creative Commons [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) license.

## Support

User support is managed through our forum: <https://forum.libreelec.tv> and the #libreelec IRC channel on Libera Chat. Start a forum thread to ask a question, and someone will reply. Please be patient and wait for answers, we are all unpaid volunteers with jobs and families!

For support on Kodi itself, please refer to the official [Kodi Wiki](https://kodi.wiki/view/Main_Page) and [Kodi Forums](https://forum.kodi.tv).


# Log Files

If you experience problems and want to investigate yourself or ask others for help in the forum or the IRC channel, a log file (or files) and configuration data provides useful info.

Kodi has `default` and `debug` log modes. As you'd expect, debug logs show more detail and are more useful for staff and forum regulars to work with. If you are asked for a log - assume the request is for a `debug` log and for the entire log file, not just the small snippet you think is useful (often we need to see and understand the configuration too).

Enable 'debug logging' at Settings → System → Logging, then paste or copy/share the logs.

## LibreELEC Settings

The settings add-on has a built-in "paste" function that grabs the current Kodi log file and other useful system configuration details and sends them to the <http://ix.io> pastebin service. It is an easy way for inexperienced (or command-line phobic) users to share logs.

Navigate to LibreELEC → System → scroll down to `Paste system logs` and press enter to submit them. Once the upload completes the GUI will show a short URL that you can copy and use in a forum post or while chatting to developers on IRC.

## SSH/Console

SSH into your LibreELEC machine and run the following command:

```
pastekodi
```

You will get a short <http://ix.io> URL back. That will look like this:

```
LibreELEC:~ # pastekodi 
http://ix.io/2f5
```

Copy and paste the URL link to a forum post or an IRC chat session, or review it yourself.

## Samba/SMB

If Samba (SMB Sharing) is enabled you can collect the log file by accessing the `Logfile` folder over the network. This is a special folder. When you access the folder it triggers a task to collect the current Kodi log and system configuration, and package everything into a single zip file that can be copied back to your local machine or unpacked in the share. The auto-created files are named with date and time to make it easier to find the latest file. Inside the zip are multiple files. The main one project staff will be interested in is `KODI.log`

**!! PLEASE DO NOT UPLOAD LOG/ZIP FILES TO THE FORUM !!**

Instead, open `KODI.log` in a text editor and copy/paste the content to an internet "paste" service like <https://pastebin.com> then share the paste URL. This makes reviewing your log a "one click" exercise so more people are likely to review it, and it saves a ton of disk space on our forum server.

## Kodi Log Uploader

The "Kodi Log Uploader" add-on can be installed from the Kodi add-on repo. It will detect that is being used on LibreELEC to collect the correct log files, and it performs the same task as the paste function in the LibreELEC settings add-on. The main difference is that Kodi Log Uploader displays a QR code on-screen to make the process of copying the pastebin URL for use easier (for some). It also sends the log to the Team Kodi pastebin service, which uses highlighting to make reading the logfile easier for developers and forum staff.


# Updating

Updating LibreELEC is (mostly) simple and can be done automatically, manually from inside the Kodi GUI via the LibreELEC Settings add-on, by [downloading an update file from our website](https://libreelec.tv/downloads_new) and copying the file to a local Samba share, or by running a command from the SSH console. We publish two image file types:

* LibreELEC-Project.arch-11.0.1.**tar** (update) files which are used for updates only.
* LibreELEC-Project.arch-11.0.1.**img.gz** (update + image) files which are used for creating new USB/SD installation media but can also be used for updates.

We can update from both **.tar** and **.img.gz** files.

## Auto-Update

Auto-Update is enabled by default and tracks minor version updates, e.g. LibreELEC 11.0.0 will update to 11.0.1, 11.0.2, etc. as they are released. It will not perform major version updates as these involve Kodi add-on updates (broken add-ons are the main source of update issues) and user-experience changes we do not want to force onto users. If auto-update is enabled the latest update file will download in the background, then Kodi will prompt you to reboot and start the update process. If you prefer to manage system updates manually, auto-update can be disabled in the settings add-on.

## Settings Add-On

Navigate to the Update section of the settings add-on, select the update channel (LibreELEC major version) and then the specific minor version to update to. The update file will start downloading, and once complete the system will reboot to perform the update.

Please see the following video

{% embed url="<https://www.youtube.com/watch?v=CjlHY6syRHw>" %}

## Samba Share

Using a file browser (explorer.exe, not a web browser) copy/paste an update file to the `\\LIBREELEC\UPDATE` Samba share on your LibreELEC device. Once the file transfer has completed, reboot LibreELEC to start the update process.

## SSH Console

SSH into your LibreELEC device and navigate to the (hidden) update folder

```
cd /storage/.update
```

Check to make sure there are no files in the folder

```
ls -la
```

Download the update file (change the URL for the current release, etc.)

```
wget http://releases.libreelec.tv/LibreELEC-RPi4.arm-11.0.1.img.gz
```

Once the download has completed, reboot to start the update process

```
reboot
```

## USB Drive

Download the LibreELEC image or update file and copy it to a USB drive. Connect the USB drive to your HTPC and navigate to the `/storage/.update/` update folder using Kodi File Manager (you will need to enable viewing of hidden files and folders in Kodi settings). Copy the update file from the USB drive to `/storage/.update` then reboot to start the update process.

## Downgrade

Kodi does not support downgrading. If "updating" within the same LibreELEC/Kodi major release, e.g. LibreELEC 11.0.1 to 11.0.0, the downgrade will normally work. If downgrading to an older LibreELEC/Kodi major version e.g. LibreELEC 11.0.1 to 10.0.4, the downgrade process will complete but Kodi may not gracefully handle being restarted with configuration files and add-ons from the (newer) previous release. Always make a backup before upgrading so that you can clean install then restore the backup to effect a downgrade without problems.

## Migrate OpenELEC

In 2016 when we forked from OpenELEC the differences between projects were small and it was simple to migrate by using our update .tar file. Today there are some challenges:

* LibreELEC images for Generic x86\_64 hardware have grown to 240MB+ in size and most older OpenELEC installs have a small 230MB boot partition so LibreELEC files will not fit and the manual .tar update process will fail (gracefully). Raspberry Pi and similar images are smaller and will still fit, but read on:
* Older Kodi add-ons are frequently incompatible with newer Kodi versions, causing crashes when the system restarts, and the bigger the version jump the more likely add-ons will cause problems. LibreELEC will detect when Kodi repeatedly fails to start and defaults to a "safe mode" configuration, but this normally requires you to access the SSH console to get back to a working setup.
* Kodi does not self-manage media and add-on package caches so over-time filesystem litter accumulates. Starting over from a clean install removes all the not-needed junk resulting in a faster/lighter installation with an improved Kodi user experience.

To migrate essential Kodi data from the old installation before migrating (which is likely to fail) or making a clean installation, enable the SSH service in the Settings add-on, then log-in over SSH to stop Kodi and back-up the userdata folder:

```
cd /storage/backup
systemctl stop kodi
tar -czf kodi_userdata.tar.gz /storage/.kodi/userdata
```

Backup files are normally 1-2GB in size so move them off-box by copying to USB or moving them to `/storage/backup` which is accessible over the network via the `\\LIBREELEC\BACKUP` Samba share. After clean installing LibreELEC you can restore the backup:

```
systemctl stop kodi
rm -rf /storage/.kodi
tar -xzf /storage/kodi_userdata.tar.gz
systemctl start kodi
```

The following video shows the migration process from OpenELEC v7.0 to LibreELEC v7.0 as it looked in 2016. The Kodi GUI now looks different (the skin changed) but the process remains the same: <https://youtu.be/Tkoxg-Q0Fe8>


# Create Media

The “LibreELEC USB-SD Creator” app helps you select and download the latest LibreELEC image for your HTPC device and create bootable USB or SD Card media. The tool is available for current 64-bit Windows 10/11 versions, and macOS v14.x and newer.

Download Links:

* [LibreELEC.USB-SD.Creator.x64.exe](https://releases.libreelec.tv/LibreELEC.USB-SD.Creator.x64.exe) ([sha256](https://releases.libreelec.tv/LibreELEC.USB-SD.Creator.x64.exe?mirrorlist))
* [LibreELEC.USB-SD.Creator.macOS.dmg](https://releases.libreelec.tv/LibreELEC.USB-SD.Creator.macOS.dmg) ([sha256](https://releases.libreelec.tv/LibreELEC.USB-SD.Creator.macOS.dmg?mirrorlist))

Note: The Linux version of the app for Ubuntu and Debian derivatives is not currently available. Please see the note on [#alternatives](#alternatives "mention") below.

## Step 1

Choose the LibreELEC image and the app will show the latest stable release, e.g.

* Generic x86\_64 - LibreELEC-Generic.x86\_64-12.0.1.img.gz
* RaspberryPi 2/3 - LibreELEC-RPi2.arm-12.0.1.img.gz
* RaspberryPi 4 - LibreELEC-RPi4.arm-12.0.1.img.gz
* RaspberryPi 5 - LibreELEC-RPi5.arm-12.0.1.img.gz

If you select the 'Show all' check-box the drop list includes older stable releases too.

## Step 2

After selecting the LibreELEC image and version click the `Download` button. This will prompt you to select a folder to download to. You can also select a previously downloaded image file on your machine for installation. Hit the `Select file` button and browse your computer for the .img.gz file, or drag/drop the file on the app GUI.

## Step 3

Select the USB stick or SD card to write the image onto. Click the refresh button if the removable device is not listed. Note: **ALL DATA ON THE TARGET DEVICE WILL BE OVERWRITTEN** so please ensure there is no important data on it!

## Step 4

After selecting an image and target device the `Write` button is available. Click it to write the image. Once the progress bar reaches 100% and shows `Writing done!` you can exit the app, eject the USB or SD media, and boot your device to install LibreELEC.

## Support

If you have problems with the app, please post in the [USB-SD Creator Support forum](https://forum.libreelec.tv/forum-41.html).

## Alternatives

Here are some alternative tools that can be used for creating LibreELEC boot media:

* [Raspberry Pi Imager](https://www.raspberrypi.com/software/) can create Raspberry Pi images using files from our servers
* [Balena Etcher](https://etcher.balena.io/) is popular but huge (almost the same size as our distro images!)
* [Win32DiskImager](https://win32diskimager.org/) is a reliable tool for Windows OS devices
* [dd](https://linux.die.net/man/1/dd) is available from most Linux OS command lines


# Add-Ons

LibreELEC builds and hosts a number of Kodi binary add-ons to extend functionality, e.g.

* Audio Encoders
* Audio Decoders
* Image Decoders
* Inputstream parsers
* PVR clients
* Screensavers
* Virtual Filesystems
* Visualisations

We also provide a range of program/service add-ons, including:

* .net Core Runtime
* Adafruit Libraries
* BTRFS Tools
* DVB Tools
* FFmpeg Tools
* Game Tools
* JRE for BD-J menus
* Multimedia Tools
* Network Tools
* Raspberry Pi Tools
* System Tools
* VDR Configuration

"Tools" add-ons bundle multiple binaries into a single add-on with a themed purpose to reduce repo maintenance. Look in the Kodi GUI and the info panel will tell you the list of binaries in each bundle.


# Containers

The awesome folks at [LinuxServer.io](https://linuxserver.io) maintain a range of popular Docker containers installable as Kodi add-ons. After installing the Docker add-on (from the LibreELEC add-on repo) you can install the LinuxServer repo add-on (from the LibreELEC add-on repo) and then install container add-ons from within the Kodi GUI. To make maintenance easier LinuxServer add-ons are designed to pull the latest Docker image automatically on Kodi startup to keep the containers fresh.

It is also possible to install Docker containers manually from the SSH console using `docker pull` commands. This allows you to install a container from any public container repository. This is also how you can access the full [fleet of LinuxServer containers](https://fleet.linuxserver.io).

## Container Architecture

Docker containers often ship in multiple CPU "architecture" or "arch" variants. To run, the container architecture must match the "userspace" CPU arch of the LibreELEC image which can be different from "kernel" CPU architecture. The userspace arch is noted in the image filename, e.g.

* LibreELEC-Generic.**x86\_64**-11.0.1.img.gz has `x86_64` userspace
* LibreELEC-RPi4.**arm**-11.0.1.img.gz has `arm` userspace
* LibreELEC-RPi4.**aarch64**-12.0-nightly-20230310.img.gz has `aarch64` userspace

Userspace CPU arch can also be read from the `/etc/os-release` file in the filesystem, e.g.

```
RPi4:~ # cat /etc/os-release 
NAME="LibreELEC"
VERSION="11.0.3"
ID="libreelec"
VERSION_ID="11.0"
PRETTY_NAME="LibreELEC (official): 11.0.3"
HOME_URL="https://libreelec.tv"
BUG_REPORT_URL="https://github.com/LibreELEC/LibreELEC.tv"
BUILD_ID="1189cdb0f43e6f4208f747d54fefb70478ebee9d"
LIBREELEC_ARCH="RPi4.arm"  <= This contains the userspace CPU arch
LIBREELEC_BUILD="official"
LIBREELEC_PROJECT="RPi"
LIBREELEC_DEVICE="RPi4"
```

Docker containers may also use different arch naming, e.g.

* The `arm` arch may be referred to as `linux/arm` and `linux/arm/v7`
* The `aarch64` arch may be referred to as `linux/arm64` and `linux/arm64/v8`
* The `x86_64` arch may be referred to as `amd64`

{% hint style="warning" %}
LibreELEC 12 will switch most ARM SoC devices capable of running a 64-bit kernel from `arm` to `aarch64` userspace. This will require affected users to remove `arm` containers before they update and redeploy `arm64` versions post-update.
{% endhint %}


# Security

This article documents LibreELEC's insecurities: the services we run by default and the security design choices and compromises the OS makes. Where options exist, it also provides guidance or warnings to help you better-secure your LibreELEC installation.

{% hint style="danger" %}
LibreELEC is designed for home networks and the out-of-box configuration is a compromise of security, supportability, and usability. It should not be used in security-sensitive networks.
{% endhint %}

## Avahi

Avahi (Zeroconf) runs in the background to announce services like Kodi, Samba, SSH over mDNS to the local network to make connecting from mDNS-aware OS and client applications easier. The service list is updated automatically when individual services are enabled or disabled. Avahi can be disabled in the LibreELEC settings add-on.

## Bluetooth

Bluetooth is enabled by default if hardware is detected to facilitate connections from remote controls and keyboards, and the OS listens for connections and pairing requests. Devices like speakers normally pair automatically while keyboards, remote controls, and compute devices with input capabilities normally prompt for a PIN code (shown on the screen). Bluetooth services including OBEX file transfer can be disabled in the LibreELEC settings add-on.

## Credentials

In a conventional Linux distro users access the OS with a non-privileged user account and use `sudo`to elevate privileges to perform tasks as the `root`user. This provides security isolation between user and system processes, with the side benefit of preventing easy end-user access to disruptive configuration options that are easily changed or misconfigured resulting in complex support activity.

In LibreELEC there is a single`root`user and most internal services run as the root user. This reduces distro maintenance and eliminates the need for `sudo` to provide a simple console experience for users with typically low or no Linux CLI experience. Although users have `root`privileges, most of the filesystem exists in a read-only state so there is limited scope for unskilled users to misconfigure the OS from its default known-good state.

As the default `root/libreelec`credential is a well-known secret the first-run wizard prompts for it to be changed. It can also be changed from the console using `passwd`. It is *not* possible to add users, groups, or change the `user:group` context applications run under without creating a custom OS image with baked-in changes.

{% hint style="danger" %}
Users are strongly advised to change default credentials. The default `root/libreelec` and `libreelec/libreelec` have long been observed in common password dictionary lists that are available to anyone.
{% endhint %}

## Firewall

The OS is intended for use inside a home network behind a NAT router/firewall device. It embeds the `iptables` firewall but this is disabled by default. It can be enabled via the LibreELEC settings add-on, and we provide simple `Home/Public` options for inexperienced users to enable for essential protection. The "Home" option allows traffic from 192.168.x.x, 172.16.x.x, 10.x.x.x IP ranges (RFC1918) while the "Public" option blocks all traffic from all networks. The firewall automatically enables when custom iptables configuration is provided by the `/storage/.config/iptables` file.

## Samba

Samba is enabled by default to facilitate end-user access to the `\Logfiles` share when installation completes but the system does not boot to the Kodi home screen. Accessing the`\Logfiles`share auto-generates a zip archive containing logs and config info that can be downloaded and shared with project staff and end-users providing support assistance in the forum.

On successful boot the first-run wizard is shown and users can disable Samba. After the wizard has completed Samba services can be enabled/disabled or reconfigured via the LibreELEC settings add-on. Here you can enable authentication and change the default credential used to access the Samba server. You can also downgrade SMB protocol support to min/max SMBv1 to support legacy devices that cannot connect to an SMBv2/v3 capable server.

{% hint style="info" %}
Samba **server** configuration located in the LibreELEC settings add-on, has nothing to do with Kodi SMB **client** configuration located in Kodi settings. These are separate functions with separate configuration.
{% endhint %}

## SSH

SSH services are disabled by default but can be enabled on successful boot in the first-run wizard. If you enable services you are prompted to change the default `root/libreelec`credential. After the wizard has completed SSH services can be enabled/disabled or reconfigured via the LibreELEC settings add-on. Here you can reset the root password. The password can also be changed from the local console or SSH console using the standard Linux `passwd`tool.

For better security and convenience, add a public key to `/storage/.ssh/authorized_keys` and then disable password authentication in the LibreELEC settings add-on. You can replace the default 2048-bit RSA keys generated on first-boot and stored in the `/storage/.ssh` directory. New SSH keys must be secured with 600 permissions else the SSH daemon will not start.

{% hint style="info" %}
Enabling the "Disable SSH Password" feature does not disable the password login prompt. It simply ensures no password provided will be accepted.
{% endhint %}

## VPN

Connecting to any commercial or private VPN server that provides a public IP address to the VPN tunnel network interface requires the server to block inbound connections or the [#firewall](#firewall "mention") to be enabled with either `Home` or `Public` profiles. Services like Samba and SSH listen on all available interfaces so the VPN connection exposes services to the public internet.

## WSDD2

The WSDD2 service broadcasts information on Samba share to Windows OS devices to support auto-discovery in Explorer. It is started and stopped alongside the Samba service.


# Allwinner

## Disclaimer

* **Only nightly releases are available right now. Use at your own risk!**
* **Boards/STBs with less than 1GiB of RAM are not supported**

## Boards Supported

### **A64 based boards**

* OrangePi Win
* Pine64
* Pine64 LTS
* Pine64 Plus

### **H3 based boards**

* BananaPi M2+
* Beelink X2
* Libretech ALL-H3-CC (Tritium)
* NanoPi M1
* OrangePi 2
* OrangePi PC
* OrangePi PC plus
* OrangePi Plus/Plus 2
* OrangePi Plus 2E

### H5 based boards

* OrangePi PC 2

### **H6 based boards**

* Beelink GS1
* OrangePi 3
* OrangePi 3 LTS
* OrangePi Lite 2
* OrangePi One Plus
* Pine H64
* Tanix TX6

### **R40 based boards**

* BananaPi M2 Ultra


# Amlogic

LibreELEC images for Amlogic with modern Linux kernels use boot processes and device-tree files that are not compatible with older LibreELEC images (LE 9.x and earlier) that use Amlogic Linux 3.14 or 4.9 kernels. The change to boot processes means you cannot update from older releases and must make a new/clean installation.

There are two images supporting Amlogic Gen10+ (64-bit) SoCs and older Gen8 (32-bit) SoCs used in a range of Linux SBC and Android STB devices:

`AMLGX` supports the following 64-bit SoCs:

* GXBB (S905)
* GXL (S805X/S905X/D/W/L)
* GXM (S912)
* G12A (S905X2/D2/Y2)
* G12B (S922X/A311D)
* SM1 (S905X3/D3)

`AMLMX` supports the following 32-bit SoCs:

* Meson 8 (S805)
* Meson 8b (S802)
* Meson 8m2 (S812)

> WeTek Play(1) aka WeTek OpenELEC uses Meson 6 (8726MX) hardware. There is little support for Meson 6 hardware in the upstream kernel and low probability of support evolving to the point where modern-kernel LibreELEC images are viable. Support ends with LibreELEC 9.0.

`AMLGX` and `AMLMX` provide a "box" image for use with devices that run Amlogic (aka Vendor or Legacy) boot firmware (U-Boot 2015.01 with Amlogic and manufacturer customisations) and "board" images using modern boot firmware (mainline U-Boot) specific to a single SBC board or STB device. The image type can be identified by the filename `-suffix`:

* `LibreELEC-AMLGX.arm-11.0.0-box.img.gz` is the `AMLGX` "box" image
* `LibreELEC-AMLGX.arm-11.0.0-khadas-vim3.img.gz` is a "board" image for VIM3
* `LibreELEC-AMLMX.arm-11.0.0-box.img.gz` is a "box" image for Meson 8 devices

## Box Images

Box images support SBC and STB devices with Android or "vendor" boot firmware running on the internal eMMC storage. LibreELEC is installed by triggering "recovery" mode boot in the Amlogic U-Boot firmware. Recovery mode searches for some standard files on SD and USB media. LibreELEC provides files tweaked to boot and run LibreELEC instead of recovering the device. Once recovery mode is activated the device will search and find LibreELEC on each boot; until Android recovery completes (which never happens).

As `box` images can be used on many devices you must configure the device-tree file to use first. This is done by editing `uEnv.ini` in the root folder of the SD card. Change `@@DTB_NAME@@` to the name of the .dtb file to use. Current supported device-tree files are in the `dtb` folder.

For example, here is the default `uEnv.ini` file:

```
dtb_name=/amlogic/@@DTB_NAME@@
bootargs=boot=UUID=2306-0801 disk=UUID=8268da37-3a8d-4f6d-aba0-08918faded56 quiet systemd.debug_shell=ttyAML0 console=ttyAML0,115200n8 console=tty0
```

To boot a Beelink GT-King box change `@@DTB_NAME@@` to `meson-g12b-gtking.dtb`

```
dtb_name=/amlogic/meson-g12b-gtking.dtb
bootargs=boot=UUID=2306-0801 disk=UUID=8268da37-3a8d-4f6d-aba0-08918faded56 quiet systemd.debug_shell=ttyAML0 console=ttyAML0,115200n8 console=tty0
```

Once the device-tree name is set you can insert the SD card in the box and power on. Some box devices detect the presence of the SD card automatically. Others may need recovery mode to be triggered using a reset button on the device. Common locations for the button are:

* Visible button marked "reset" or "recovery" or "power" button
* Visible pin-hole on the underside of the case
* Hidden button visible through ventilation holes in the case
* Hidden at the end of the 3.5mm audio jack

In most cases you will need a small pin, unfolded paper-clip, or toothpick to press the reset button with - hence the install process is often referred to as the "toothpick method" in forum posts. Press and hold the button, then power-on the box. After 5-7 seconds release the button to interrupt boot and start the recovery process. Due to differences in box speeds and vendor U-Boot the exact timing for button release varies and you will need to experiment to find the timing that works for your box. It is possible to see U-Boot output and remove the guesswork by attaching a UART serial cable to the board, although most set-top box devices will need connector pins soldering to the board as manufacturers omit them to save manufacturing costs.

## Board Images

These images are built for Single Board Computer (SBC) devices which boot modern U-Boot via an SD card or removable eMMC module. Installation is normally simple requiring you to write the image to the SD card or eMMC module and boot the device. If the board has eMMC storage soldered (not on a removable module) it may be necessary to boot from the "box" image first. Once booted to a box image on SD card (so eMMC is not in use) you can write the correct `board` image to eMMC (overwriting Android or other factory-installed images) using `dd` to write the image. You can use the `emmctool` command to help that process (see below).

## Android Images

If you are searching for an Android firmware image to recover/restore a set-top box please be advised that the project cannot help you. We have no interest in Android and Android images and do not have a secret stash of vendor firmware files. Please contact the original manufacturer of your box, or use their support forum, or (often best) search Android focussed community forums like 4pda.

> The sole exceptions are the WeTek Hub and Play2 devices: we have the original Android firmware update files and raw 'dd' images of the internal storage of the boxes.

## installtointernal

Community images using Amlogic Linux 3.14/4.9 kernels often include the `installtointernal` script to reconfigure the factory boot process and run LibreELEC from internal eMMC storage. We do not provide or support this script. There are two main reasons:

1. Amlogic uses a proprietary partitioning scheme that relocates partition data structures to non-standard locations. This is supported in Amlogic Linux kernels and Amlogic-modified versions of tools like parted, fdisk and fsck used to create and manage filesystems. It is not supported in modern upstream Linux kernels or modern versions of filesystem tools. This means the Linux kernel used in AMLGX images cannot read the offset partition data to mount (and repurpose) Android partitions as a persistent /storage area.
2. The script causes a high volume of support issues. When the script fails to modify the boot process or create partitions correctly the user ends up with a "bricked" box. Amlogic builds several factory-restore mechanisms into their software that mean it is always possible to recover the box, but this normally requires the user to find the correct Android image for the device and reflash it with a Windows OS tool that often has issues. Our forum staff are all volunteers who give time to the project for fun. Helping a never-ending stream of pissed-off inexperienced users recover bricked boxes is not fun, nor do we have a collection of Android images to use, so we actively discourage the existence and use of this script.

In short: It was technically possible (but heavily discouraged) to use `installtointernal` with older LibreELEC images. It is NOT POSSIBLE to use `installtointernal` with AMLGX and running the script will either fail, or fail *and* break boot. To run LibreELEC from eMMC storage please purchase a supported "board" device.

## emmctool

In the `AMLGX` image there is an eMMC helper script called `emmctool` that supports a range of useful functions for backup/write/erase (and more) for eMMC storage. See:

```
LibreELEC:~ # emmctool 

info: boot device is /dev/mmcblk0, U-Boot version is 2021.04
info: emmc device is /dev/mmcblk1

Model: MMC 8WPD3R (sd/mmc)
Disk /dev/mmcblk1: 7818MB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name          Flags
 1      17.4kB  7818MB  7818MB  ext4         EMMC_STORAGE

usage: emmctool (w)rite <filename>   : write <filename>.img/.img.gz to the eMMC module
                (b)backup <filename> : dump the emmc partition to an .img.gz file
                (d)etect             : detect an eMMC module attached after boot
                (i)nfo               : show info about the eMMC module
                (l)abels             : change eMMC disk labels to /
                (r)esize             : resize the storage partition to 100%
                (s)storage           : convert emmc for use as /storage (boot from sdcard)
                (z)ero               : zero (erase/wipe) the eMMC module
                (h)elp               : displays this help message
```

The `emmctool` helper supports a limited range of SBC boards with eMMC modules. On a generic Android device it will output the (i) info only.


# BananaPi M5 / M2S

## Enabling WiFi and Bluetooth

BananaPi M5 and M2S have an optional WiFi mezzanine board with an RTL8822CS chip providing 802.11 b/g/n/ac on 2.4GHz/5GHz channels and Bluetooth 5.0 connectivity. The board is not active unless enabled through a device tree modification.

On BPI-M5 create `/storage/.config/autostart.sh` with the following content:

```shell
mount -o remount,rw /flash
fdtput -t s /flash/meson-sm1-bananapi-m5.dtb /soc/sd@ffe03000 status okay
fdtput -t s /flash/meson-sm1-bananapi-m5.dtb /soc/bus@ffd00000/serial@24000 status okay
mount -o remount,ro /flash
```

On BPI-M2S create `/storage/.config/autostart.sh` with the following content:

```sh
mount -o remount,rw /flash
fdtput -t s /flash/meson-sm1-bananapi-m2s.dtb /soc/sd@ffe03000 status okay
fdtput -t s /flash/meson-sm1-bananapi-m2s.dtb /soc/bus@ffd00000/serial@24000 status okay
mount -o remount,ro /flash
```

After rebooting the board, the WiFi and BT devices should be detected:

```bash
LibreELEC:/ # dmesg | grep rtw
[ 8.547372] rtw_8822cs mmc2:0001:1: WOW Firmware version 9.9.4, H2C version 15
[ 8.548447] rtw_8822cs mmc2:0001:1: Firmware version 9.9.14, H2C version 15

LibreELEC:/ # dmesg | grep -i Blue
[    8.099139] Bluetooth: Core ver 2.22
[    8.099306] NET: Registered PF_BLUETOOTH protocol family
[    8.099317] Bluetooth: HCI device and connection manager initialized
[    8.099538] Bluetooth: HCI socket layer initialized
[    8.099557] Bluetooth: L2CAP socket layer initialized
[    8.099797] Bluetooth: SCO socket layer initialized
[    8.272210] Bluetooth: HCI UART driver ver 2.3
[    8.272242] Bluetooth: HCI UART protocol H4 registered
[    8.272930] Bluetooth: HCI UART protocol Three-wire (H5) registered
[    8.307537] Bluetooth: HCI UART protocol Broadcom registered
[    8.316217] Bluetooth: HCI UART protocol QCA registered
[    9.038966] Bluetooth: hci0: RTL: examining hci_ver=0a hci_rev=000c lmp_ver=0a lmp_subver=8822
[    9.042736] Bluetooth: hci0: RTL: rom_version status=0 version=3
[    9.042767] Bluetooth: hci0: RTL: loading rtl_bt/rtl8822cs_fw.bin
[    9.053947] Bluetooth: hci0: RTL: loading rtl_bt/rtl8822cs_config.bin
[    9.094258] Bluetooth: hci0: RTL: cfg_sz 33, total sz 36529
[    9.518223] Bluetooth: hci0: RTL: fw version 0xffb8abd6
[    9.574916] Bluetooth: MGMT ver 1.22
```


# LaFrite

LibreComputer LaFrite (AML-S805X-AC) is an S805X (GXL) board with 512MB or 1GB of RAM and 16MB SPI boot flash. The board runs upstream U-Boot from SPI, and has no SD card slot, so you can boot the AMLGX `box` or `lafrite` images written to a USB stick or eMMC module. Default boot order is:

* SPI (built-in)
* EMMC (optional module)
* USB (socket furthest from the GPIO header)

### Run LibreELEC from eMMC

LibreComputer preinstalls their eMMC modules with Android, so if you power on the board with the module attached it will always boot into Android. To erase Android or overwrite with LibreELEC the board must first boot from USB without the module attached. Once in LibreELEC booted from USB, the module can be attached, detected, and erased or imaged with the `lafrite` image:

1. Power on the Board, and boot the AMLGX `box` image from USB
2. Attach the eMMC module, and from the SSH console:
3. Run `emmctool d` to detect the module
4. Run `emmctool z` to erase (zero) the module
5. Copy the `lafrite` image to `/storage/` on the USB stick
6. Run `emmctool w /storage/LibreELEC-AMLGX.arm-11.0.0-lafrite.img.gz` to write the `lafrite` image to the eMMC module.
7. Power off the board, remove the USB stick
8. Power on the board, and LibreELEC will boot to eMMC and resize /storage

### Updating U-Boot in SPI

LibreComputer provides [U-Boot firmware](https://boot.libre.computer/release/aml-s805x-ac/) files for updating the SPI flash. LibreELEC does not need a minimum version to boot, but newer U-Boot firmware fixes some graphical on-screen glitches seen in the early boot stages. To update:

1. Download the latest `aml-s805x-ac-spiflash.img` and flash it to a USB stick
2. Connect the USB drive to the socket furthest from the GPIO header
3. Power on the board
4. Current U-Boot checks if the new image matches existing firmware, and when it does not (as it is newer) the firmware will be updated. When complete:
5. Power off the board and remove the USB stick

### UART

The debugging UART is accessible on the 40pin GPIO header:

* TX (Green) on Pin 3
* RX (Grey) on Pin 5
* GND (Black) on Pin 6


# WeTek Hub/Play2

Installing LibreELEC to internal eMMC storage

Create a bootable SD card using the `AMLGX` "box" image, then edit the `uEnv.ini` file in the root folder of the SD card and change `@@DTB_NAME@@` to `meson-gxbb-wetek-hub.dtb` or `meson-gxbb-wetek-play2.dtb` then save/eject and boot the box using the SD card. If you have been booting from SD card before it should automatically detect the card and boot into LibreELEC. If you have been booting from eMMC you may need to select "boot from SD Card" during boot.

Once the box has booted into the "box" image you can download the latest WeTek "board" image and install LibreELEC to internal eMMC storage using `emmctool`. <mark style="color:red;">**This permanently overwrites the Android vendor OS with LibreELEC.**</mark>

Find the URL for the relevant board image on the [download page](https://libreelec.tv/downloads/amlogic/). For example, the LibreELEC 11.0 image for the WeTek Play2 will be:

```
https://releases.libreelec.tv/LibreELEC-AMLGX.arm-11.0.0-wetek-play2.img.gz
```

Enable SSH and login, then run the following commands to download the board image to /storage and run `emmctool` to write (`w`) the `LibreELEC-AMLGX.arm-11.0.0-wetek-play2.img.gz` image to eMMC:

```
cd /storage
wget https://releases.libreelec.tv/LibreELEC-AMLGX.arm-11.0.0-wetek-play2.img.gz
emmctool w LibreELEC-AMLGX.arm-11.0.0-wetek-play2.img.gz
```

The `emmctool` utility will write the board image to eMMC, expand the /storage partition to 100% size and change the partition labels to `BOOT` and `DISK` to avoid name-clashing with the default labels used in the SD card image (so you can boot from SD card if needed).

Once `emmctool` has finished, run `shutdown` and remove the SD card. Then cycle power to boot into LibreELEC running from the internal storage.


# NXP - iMX6/iMX8

Current iMX6 images support the ARMv7-A dual-lite and quad versions (ARM Cortex-A9) of the following boards:

* Cubox-i
* Wandboard
* Udoo

Current iMX8 images are experimental and do not support a specific board.

Installation is done by writing the LibreELEC \*.img file to an SD card. The boards have internal hardware identifiers so there is no need to edit `extlinux.conf` on the card. Selection of the correct device dtb is handled internally within U-Boot.

**NOTE** - \*\*\*\* It is not possible to update from older LibreELEC or OpenELEC imx6.arm images to LE 11.0 as the boot configuration for LE 11.0 is different and older kernels do not support zstd compression. If you attempt an upgrade, the boot configuration of the old installation will be broken. You are advised to clean install LE 11.0 and manually restore sources and library DB files. Backups can be taken and restored, but as there is now a long time gap since LE 8.2.5 (and OE 8.0.x) it is best to start over with a clean system.


# Intel x86-64 (Generic)

The LibreELEC "Generic" image supports a (very) broad range of x86\_64 compatible hardware using AMD, Intel, and nVidia GPU hardware. The GPU in a device determines what media can be played using hardware decoding and modern features like HDR, and the CPU determines if any unsupported codecs can be software decoded for playback by ffmpeg.

## HDR

HDR support in the Linux kernel, in Kodi, and in LibreELEC is ongoing "work in progress" that continues to evolve. HDR depends on a combination of the media format and colourspace properties, GPU hardware, HDMI output, and TV panel capabilities. Most users wrongly view HDR support like codec support, but it is significantly more complicated. Few people outside the broadcast media industry truly understand how it works (in theory and in practice) but we are fortunate to have users with that professional background providing testing and insightful feedback to the team as progress is made.

As GPU hardware is one of the major variables, please read the AMD, Intel, and nVidia GPU sections below for further information relevant to HDR support on that GPU type:

## Intel GPUs

Intel NUC and similar-sized Intel GPU devices are popular for building an HTPC device around since they combine well supported upstream GPU drivers with entry level Celeron and Core i3 chips to intermediate Core i5 and high-end Core i7 CPUs.

Modern Intel GPUs have been shipping since "Nehalem" in 2010, and over time the number of different CPU and GPU generations and codenames have multiplied, making it confusing to figure out what media features a device can support. The following table is based on public sources like Wikipedia, and it indicates hardware features, which do not always translate into what Linux and Kodi currently support in software:

<table><thead><tr><th>CPU</th><th>Codename</th><th width="206">Driver</th><th>H264</th><th>HEVC</th><th>AV1</th><th>4K</th><th>HDR</th></tr></thead><tbody><tr><td>Gen1</td><td>Nehalem</td><td>i965</td><td>Yes</td><td>No</td><td>No</td><td>No</td><td>No</td></tr><tr><td>Gen2</td><td>Sandy-bridge</td><td>i965</td><td>Yes</td><td>No</td><td>No</td><td>No</td><td>No</td></tr><tr><td>Gen3</td><td>Ivy-Bridge</td><td>i965</td><td>Yes</td><td>No</td><td>No</td><td>No</td><td>No</td></tr><tr><td>Gen4</td><td>Haswell</td><td>i965</td><td>Yes</td><td>No</td><td>No</td><td>No</td><td>No</td></tr><tr><td>Gen5</td><td>Broadwell, Braswell</td><td>i915</td><td>Yes</td><td>No</td><td>No</td><td>No</td><td>No</td></tr><tr><td>Gen6</td><td>Skylake</td><td>i915</td><td>Yes</td><td>Yes</td><td>No</td><td>DP</td><td>No</td></tr><tr><td>Gen7</td><td>Kaby-lake, Apollo-lake</td><td>i915</td><td>Yes</td><td>Yes</td><td>No</td><td>Yes</td><td>HDMI</td></tr><tr><td>Gen8</td><td>Coffee-lake, Kaby-lake refresh, Whiskey-lake</td><td>i915</td><td>Yes</td><td>Yes</td><td>No</td><td>Yes</td><td>HDMI</td></tr><tr><td>Gen9</td><td>Coffee-lake refresh</td><td>i915</td><td>Yes</td><td>Yes</td><td>No</td><td>Yes</td><td>HDMI</td></tr><tr><td>Gen10</td><td>Comet-lake, Ice-lake, Amber-lake</td><td>i915</td><td>Yes</td><td>Yes</td><td>No</td><td>Yes</td><td>Yes</td></tr><tr><td>Gen11</td><td>Rocket-lake, Tiger-lake</td><td>i915</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td></tr><tr><td>Gen12</td><td>Alder-lake</td><td>i915</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td></tr><tr><td>Gen13</td><td>Raptor-lake</td><td>i915</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td></tr></tbody></table>

* Gen6 CPUs (Skylake) have HDMI 1.4b and DisplayPort 1.2 connectors. HDMI can run at max 1920x1200\@60 resolution, while DP can run at max 3840x2160\@60 resolution.
* Gen7 and Gen8 CPUs use an LSPCON chip for HDMI 2.0 output. HDR is supported only when the HDMI output is connected to an HDMI 2.0 port on the TV. Users with Intel NUC devices are recommended to run the latest Intel firmware for their device. Lots of bugs in original/factory LSPCON firmwares have been fixed.
* Linux supports LSPCON chips for HDR from Linux 5.12 onwards
* Linux has full support for Tiger-Lake CPUs from Linux 5.12 onwards
* Intel GPUs are known as *Integrated graphics processors (IGPs)* and are embedded within the CPU core. Each CPU generation uses a single GPU generation but the generation ID's do not match, e.g. Gen10 CPUs have Gen11 GPUs.

**LibreELEC 10.0 shipped with Linux 5.10 kernel support and Xorg graphics, so it does not have support for HDR or Gen11 hardware**. Community created LibreELEC 10.0 images with newer Linux kernels supporting Gen11 hardware and`GBM` graphics with experimental HDR patches can be downloaded from the LibreELEC forums. LibreELEC 11.0 use GBM graphics, include Kodi 20.0 support for HDR, and an updated kernel supporting Gen11, Gen12 hardware.

## AMD GPUs

AMD GPUs are a popular option for users building custom HTPCs from motherboards without onboard Intel graphics. LibreELEC embeds two AMD drivers: `radeon` is used with older cards, and `amdgpu` is used with newer cards (starting from the 'Southern Islands' family).

Determining media features (H264, HEVC, AV1, 4K, 4K60, HDR, etc.) is complicated due to the sheer number of different AMD cards available. Each new GPU generation ships with low-end cards limited in capabilities, and high-end cards with multiple connectors. Media features like 4K and HDR also have a dependency on connectors (HDMI or DisplayPort) and the standards the connectors support. For example, some cards support HDMI 1.4b and a max resolution of up to 3840x2160\@30 with 8-bit HDR output, while cards with DisplayPort 1.4 or HDMI 2.0 may support up to 3840x2160\@60 with 10-bit output.

The most accurate source of information is [https://www.x.org/wiki/RadeonFeature](https://www.x.org/wiki/RadeonFeature/)

## nVidia GPUs

LibreELEC v7.x - v10.x include two different nVidia GPU drivers; a "legacy" driver (340.xx) and the latest stable driver. The drivers provide `OpenGL` support via `Xorg` so Kodi can display a GUI on-screen, and Kodi supports`VDPAU` hardware decoding of H264 and some older SD era media codecs for efficient playback. Newer nVidia cards support 4K resolutions and `NVDEC` hardware decoding, but Kodi does not support `NVDEC`, and while Kodi can output 4K, nVidia VDPAU drivers have no support for HEVC or VP9 (the formats used with most 4K media) and there is no support for HDR. It is no surprise that project active-install stats show most nVidia installs are using the legacy nVidia driver, and the number of installs continues to decline over time: which means LibreELEC users are replacing older nVidia devices with something that does not use an nVidia GPU. This trend is not new and influences our technical decisions:

LibreELEC v11.x has switched "Generic" from Xorg OpenGL graphics to the Mesa OpenGL and the same DRM PRIME video stack used with ARM SoC devices.&#x20;

A "Generic\_Legacy" image using Xorg is available, but if "GBM" image development continues to progress well our intention is to drop the legacy image in the future (and with it, nVidia support). In lieu of this:

***The team does not recommend users purchase nVidia hardware for use with Kodi***

LibreELEC v11.x "GBM" images are built with Mesa `nouveau` OpenGL support so nVidia users who upgrade will see Kodi on-screen. However `nouveau` has no ability to "reclock" modern nVidia GPUs so the card runs at its lowest clock frequency and performance is bad (too bad to be useful). This issue is caused by nVidia requiring the use of signed (closed-source) firmware to interact with newer card generations, and it is a problem with all modern nVidia cards and all Linux distributions. It means the `nouveau` driver only works with very old nVidia cards, and is not a long-term solution for nVidia support in LibreELEC.

Update (Oct 2021): [nVidia has announced the latest drivers support GBM and Mesa](https://www.phoronix.com/scan.php?page=news_item\&px=NVIDIA-495.29.05-Linux). This will allow Kodi to render the GUI via Mesa OpenGL. It removes one technical blocker to LibreELEC supporting newer nVidia devices in future releases. However, it is not the only blocker. The latest driver uses `NVDEC` for hardware decoding so either Kodi would need to add support for `NVDEC` or nVidia would need to support `VAAPI` which is used by Intel and AMD. In theory `NVDEC` is not a big technical challenge to implement, but Team Kodi has an established policy of refusing to include more/new proprietary hardware-decoding APIs that complicate code maintenance. So far nobody on the current Kodi staff has volunteered to implement `NVDEC` support and run the gauntlet of getting it accepted and merged. Even if an attempt was successful (which is unlikely) it would not benefit the majority of LibreELEC users with older nVidia cards which still depend upon the legacy driver and `VDPAU` decoding. So the latest drivers and `NVDEC` support are not the long-term solution for nVidia support in LibreELEC either.

NB: If (when) LibreELEC drops support for Xorg and nVidia users, it does not mean Kodi has dropped support. nVidia users can continue to use their nVidia card with Xorg and any desktop Linux distro that supports Kodi (Arch, Debian, Ubuntu, etc.) - although the long-term trend with desktop distros is to move away from Xorg to Wayland (which depends on Mesa) so the trend there is against nVidia too. In lieu of this, we say again:

***The team does not recommend users purchase nVidia hardware for use with Kodi***

## Legacy Hardware

Despite the range of devices that Generic x86\_64 images can run on, team development and testing has always been focused on current and recent hardware packaged for use as HTPC devices. Users frequently mistake the minimalist nature of LibreELEC as perfect for recycling an older device (laptops with a broken screen are a recurring theme) into a media player. You might be able to boot LibreELEC, but we are often missing hardware drivers for old hardware and the overall playback performance (and power consumption) of first generation Raspberry Pi boards is often way (way) better. As a general rule, project staff view any hardware over 7-8 years old as legacy hardware. If you do need to use legacy hardware; use an era-appropriate LibreELEC (or OpenELEC) image.

## i386 Support

Support for i386 hardware was dropped between OpenELEC v5.x and v6.x in 2015 due to low numbers of users, and LibreELEC has no interest in resurrecting support. It is still technically possible to hack/restore i386 support into our buildsystem and self-build an i386 image since we support 32-bit ARM SoC devices and use 32-bit userspace with 64-bit ARM SoCs so most packages in are still 32-bit compilable with little or no tweaking. However, there are still a few packages that do need tweaking to restore i386 support, and there is no HOWTO guide that you can follow. Some users enjoy the intellectual challenge of figuring out how to restore i386 support, but i386 hardware is super low-spec for modern Kodi use and our recommendation is to invest in a Raspberry Pi board instead of spending tens or hundreds of hours on codebase archaeology. An inexpensive Pi board will give a better overall result, costs less to run, and be zero hassle to maintain over time.


# Laptops

How to disable the internal screen and force external HDMI/DP/VGA output

LibreELEC images are targeted at common HTPC device hardware: typically small form-factor and single-board computer devices that are static/attached to a TV or AVR device. One characteristic of common target hardware is a single active display connection even if the hardware has several output connector options. Laptops are not target hardware devices for the project, but the "Generic" x86\_64 image(s) boot and run on a wide range of x86\_64 devices and some users recycle old laptops as their HTPC. Laptops normally support multiple active display outputs: the internal LCD screen plus one of the following:

* HDMI
* DisplayPort
* VGA

Some laptops can disable the internal screen and force display to an external output using BIOS configuration. Some detect whether the laptop lid is open or closed, and when closed output is automatically directed to an active external connector. Others require run-time switching using keyboard function keys, e.g. Fn+F7 but this needs software support in the OS, and since we are intentionally minimalist LibreELEC does not have that support.

In most cases with multiple display outputs the internal display probes first and display output is directed there. In this scenario users need to manually edit kernel boot parameters to disable the internal display connector, allowing the external connector to be found and used instead.

Enable SSH services and SSH into the laptop, then identify output devices:

```shell
LibreELEC:~ # tail /sys/class/drm/*/status
==> /sys/class/drm/card1-eDP-1/status <==
connected

==> /sys/class/drm/card1-HDMI-A-1/status <==
connected
```

The above output shows two display "connectors" are active and connected:

* eDP-1 = the internal screen
* HDMI-A-1 = the external HDMI connector

NB: Some laptops may use "LVDS-1" for the internal screen, and "VGA-1" for the external connector.

Next we make the boot partition writeable so boot parameters can be edited:

```shell
mount -o remount,rw /flash
```

Now we edit them in the nano text editor:

```shell
nano /flash/syslinux.cfg
```

Connectors are disabled by adding `video=` options, e.g. `video=eDP-1:d` will disable the eDP-1 connector allowing HDMI-A-1 to be used instead. In the example below the APPEND line has been modified to disable the eDP-1 connector:

```sh
APPEND boot=UUID=10B4-4A77 disk=UUID=93786be3-5652-e2f498d33733 quiet video=eDP-1:d
```

After adding the details for the connector, you need to disable, save (ctr+o) and exit (ctrl+x) then `reboot` to test the change. On restart, the external connector should be the only active connector and Kodi should appear on the external display device. As the output capabilities of the external connector will be different to the internal screen, you may need to adjust the Kodi desktop resolution in Kodi display settings to match e.g. 720p or 1080p output.


# Qualcomm

Dragonboard 410c support exists in LibreELEC as open-source `freedreno` drivers provided a stable Linux reference implementation of stateful V4L2m2m uAPI usage, allowing Team Kodi developers to evolve support for GBM and EGL/DRMPRIME rendering with zero-copy hardware decoding, which is now the foundation for future support of Kodi on Linux.

Kodi runs well on the Dragonboard 410c due to mature support in the Linux kernel and ffmpeg, but it is a expensive board to purchase and rather fiddly to flash with a LibreELEC image, so is not hardware the project staff recommends. Device support remains in the buildsystem for occasional reference testing of changes and we do not provide release images.


# Raspberry Pi

## HEVC on LibreELEC 9.2.x and 10.x or newer

The following table summarises LibreELEC support for HEVC media on different Raspberry Pi hardware generations:

| Device               | 9.2.8                       | 10.x and newer            |
| -------------------- | --------------------------- | ------------------------- |
| Raspberry Pi 0/1     | Not supported               | Not supported             |
| Raspberry Pi 2/3     | Up to 1080p in Software     | Up to SD in Software      |
| Raspberry Pi 4 / 400 | Up to 4K, basic HDR (8-bit) | Up to 4K, 8/10/12-bit HDR |
| Raspberry Pi 5       | Not supported               | Up to 4K, 8/10/12-bit HDR |

Raspberry Pi 4, 400, and 5 are the ONLY devices with native hardware decoding of HEVC content, and in LE10 and newer releases (LE11 for RPi5) we support 8/10/12-bit output for great results with 4K HDR material. Note that the original LE 9.2.9 release for RPi4/400 devices only supports 8-bit output for basic playback.

Older Raspberry Pi devices support only software decoded HEVC. In practice Raspberry Pi 3 devices running LE 9.2.x with mild overclocking can play lower-bitrate 1080p content without issues, but if media has higher bitrates and larger filesizes you should expect poor results. Raspberry Pi 2/1/0 models can normally manage 720p media but will struggle with 1080p.

LibreELEC 9.2.x runs best on older Raspberry Pi hardware because the video pipeline in Kodi v18 supports vendor proprietary hardware decoding methods (MMAL and OMXplayer) and custom optimisations for software-based HEVC decoding on Pi hardware. The optimisations for HEVC are very clever, but also require a large and invasive patch (more than 50,000 lines of additional code for FFMpeg). The complexity and Raspberry Pi specific nature of the optimisations has prevented them from being accepted upstream into FFMpeg, and few Linux distributions have allowed such a large patch into their codebase.

Kodi v19 (LibreELEC 10.x) also removed support for vendor proprietary hardware decoding methods (on Raspberry Pi, the MMAL and OMX decoders) to focus on a standards-based approach (V4L2, named for the Linux kernel 'Video for Linux v2' API used). LibreELEC 10.x also dropped support for Raspberry Pi Zero and other 512MB RAM devices as 1GB is now considered as the minimum RAM needed for a good Kodi experience. The Raspberry Pi Foundation have rewritten their video drivers and FFMpeg support to follow the common V4L2 frameworks. As their goal is to upstream all driver and player-app changes, allowing them to be included and used with all Linux distros, the rewrites do not include the custom HEVC optimisations that would never be accepted. This means HEVC support on Raspberry Pi 4, 400, and 5 hardware is excellent as these devices support native HEVC hardware decoding, and the newer drivers support 8/10/12-bit output for better 4K HDR, but playback on older Pi 0/1/2/3 devices will be challenging as FFMpeg software decoding is no longer as-optimised for Pi hardware, and users can expect SD media support only, not HD (720p and 1080p) support as seen with older LibreELEC releases.

In summary:

<mark style="color:red;">**If you need HEVC support on older Raspberry Pi 0/1/2/3 hardware use LibreELEC 9.2.x and do not update to LibreELEC 10.x or newer releases.**</mark>

**If you have Raspberry Pi 4 or 400 hardware, use LibreELEC 10.x or newer to benefit from better HEVC and 4K HDR support. Raspberry Pi 5 devices require LE11.x or newer.**

## Composite Output

LibreELEC images for all Raspberry Pi boards ship pre-configured for HDMI output. Two simple changes are required to switch the image into Composite mode:

First, edit `config.txt` in the root folder of the SD card to comment out `include distroconfig.txt` and uncomment `include distroconfig-composite.txt` , e.g. the comments should look like this:

```
#include distroconfig.txt
include distroconfig-composite.txt
```

Second, edit `cmdline.txt` in the root folder of the SD card to configure PAL or NTSC output. This is done by appending a `video=Composite-1` option to the line of boot params in the file. Append to the existing single line; do not add them on a new/separate line. The two options are:

* `video=Composite-1:720x576@50ie` for PAL output
* `video=Composite-1:720x480@60ie` for NTSC output

Boot after saving the changes and HDMI will be disabled and Composite enabled. You may also need to adjust audio output preferences in Kodi as the pre-configured default is for HDMI.


# Rockchip


# Samsung (Exynos)

Odroid XU4 and XU3 boards can run the `Exynos` image which uses a current upstream Linux kernel with a mesa/panfrost open-source graphics pipeline and the latest Kodi version.&#x20;

H264, H263, VP8 and other older codecs are supported. XU4/XU3 do not have HEVC or VP9 support and cannot handle software decoding those formats.

Note: The Samsung S5-MFP decoding drivers regressed after Linux 5.4 when a cleanup was done on the driver that removed functionality. The original plan was to restore function in later changes, but this never happened. Due to the age of the boards now, is unlikely to happen. You may find the Linux 5.4 kernel images in the HardKernel forums are more functional.

`Exynos` images are designed to boot and run from SD card, but can also boot from an eMMC module if upstream u-boot is installed to the `/dev/mmcblk1boot0` or `/dev/mmcblk1boot1` partitions. The boot process requires `extlinux` support so will not work with the older vendor u-boot versions that sometime ship pre-installed on XU4 eMMC modules.


# Virtual Image

The project builds an OVA version of the Generic (x86\_64) imported which can be imported into current versions of vmware Workstation, Fusion (on Intel macOS hardware), and vSphere (ESXi). The OVA exists to support project team-member development activities, e.g. functional testing of userspace changes and the LibreELEC settings add-on without needing to use HTPC hardware.

We have never formally supported running LibreELEC in a hypervisor. This is mainly because none of the active project maintainers do this, so when software breakage to the OVA occurs the break often goes undiscovered and unfixed for many months (until the next time some development needing it takes place).

As we do not support the current VMware oriented OVA image, there are no plans to extend virtual image non-support to include Hyper-V, KVM, QEMU or any other hypervisors.&#x20;


# 4K / HDR

This page explains the configuration points:

* Desktop Resolution
* Modeline Whitelist
* Adjust Refresh
* Deinterlacing
* 4K60 Support
* HDR Questions

### Desktop Resolution

The primary impact of the Kodi desktop resolution is GUI performance, or how Kodi feels when you navigate around menus and libraries. Kodi leverages GPU hardware to accelerate rendering of GUI elements, but fanart and thumbnails are frequently adapted from original artwork on-the-fly as you scroll around, and even when all images have been pre-processed, they must still be read from disk caches before being displayed. Higher levels of CPU and I/O activity from larger artwork and media also mean higher power consumption from the HTPC device.

The second impact of the Kodi desktop resolution is how media is scaled. If "Adjust Refresh" is not enabled, Kodi will scale all media played up or down to the desktop resolution and refresh rate, which by default is 1080p @ 60 fps. Scaling SD and 720p media up to 1080p while adding extra frames to match 60fps is handled well, as Kodi simply needs to duplicate frames to reach the higher fps rate, and the simple scaling algorithms Kodi uses to reduce artefacts in the upscaled image move smaller amounts of data in/out of memory. Hardware as low-spec as the first generation Raspberry Pi can normally manage this well.

Scaling SD and 1080p media to 4K is a literally bigger challenge. Frame sizes for 4K media are 4x the size of 1080p so the amount of data being processed in/out of memory increases and the CPU resources needed also increase. Scaling 4K to 1080p is a larger challenge again. Source 4K media has huge frame sizes and sophisticated (down)scaling algorithms are required to create a lossy image without massive visual artefacts.

Higher-spec Intel CPU devices with recent Core i7 chips and SSD storage can normally run the Kodi GUI at 4K with 60fps refresh rates and scale media with reasonable quality, but older and lower-spec Intel CPU devices and anything running from a spinning HDD or removable USB/SD media will struggle with a 4K desktop. This also includes ARM SoC devices. They might be capable of displaying the Kodi desktop in 4K but the experience is poor since they don't have the memory bandwidth or CPU speeds to process the data volumes needed.

However, all 4K resolution TV's have dedicated scaling hardware with sophisticated algorithms to upscale 1080p images to the native 4K resolution of the screen. TVs do this better and much more efficiently than Kodi can scale images itself.

<mark style="color:red;">**Recommendation: Keep the Desktop resolution at 1080p, with 60fps refresh rate. Allow Kodi to upscale SD media to HD, and let the TV handle 1080p upscaling to 4K**</mark>

### Mode Whitelist

Most 4K televisions support a broad range of resolutions and refresh rates to support different media standards. In Linux each output format is known as a "modeline" and Kodi allows you to configure a list of allowed modes to use in combination with the "Adjust Refresh" option.

Some hardware supports 4096x2160 modes. Kodi evaluates the whitelist using the height (2160) and refresh rate, so if you include these in your whitelist selection Kodi will switch to them instead of 3840x2160 modes which are an exact or more accurate match with 4K streaming media. If you see black bars on the sides of 4K media while playing, remove 4096 modes from the whitelist.

<mark style="color:red;">**Recommendation: Configure Kodi to allow the following modes, if available:**</mark>

* <mark style="color:red;">**3840x2160 @ 60/59.94/50/30/29.97/25/24/23.976**</mark>
* <mark style="color:red;">**1920x1080 @ 60/59.94/50/24/23.976**</mark>

### Adjust Refresh

Kodi can either upscale media to match the desktop resolution and refresh rate, or switch to a resolution and rate that exactly or better matches the media. Switching to match the rate can eliminate or minimise the need for Kodi to make corrections (to keep things in-sync) by adding or dropping frames. Adding frames to the stream is generally harmless and rarely causes noticeable artefacts, but dropping frames causes skips, glitches and audio pops.

Kodi has three "Adjust Refresh" settings:

* Off (scale media to the desktop resolution/rate)
* On start/stop (change resolution/rate when playback starts and stops)
* Always (change on start/stop and during playback if the media changes resolution/rate)

<mark style="color:red;">**Recommendation: Set the Adjust Refresh setting to "On Start/Stop"**</mark>

### Deinterlacing

4K media is progressive so this is not a requirement for 4K or HDR playback, but many Kodi users have DVB setups where interlaced streams are common so we need to set the mode whitelist to support them. The challenge with interlaced media is:

* Kodi cannot output interlaced frames, it always outputs progressive frames
* Kodi cannot detect media is interlaced until you start playing it

Kodi converts interlaced media for progressive output by doubling the original refresh rate and rendering each half-frame in its own full frame, e.g. PAL 1080i @ 25fps media becomes 1080p @ 50fps, and NTSC 1080i @ 29.97 becomes 1080p @ 59.94fps. For this rate doubling to work, we need to ensure the whitelisted 1080p modes do not contain 1080p @ 25/29.97/30Hz rates, else Kodi will see an exact match against resolution and refresh rate and you will see high CPU loads and 50% of frames being dropped. If the modes are removed, Kodi will use 50Hz/59.94Hz rates, and if the media is interlaced, Kodi can still render 100% of the frames.

<mark style="color:red;">**Recommendation: Remove 1080 @ 30, 29.97 and 25 fps rates from the Modelist**</mark>

### 4K @ 60Hz

Successful 4K output at 60Hz depends on HDMI output capabilities from the HTPC device, certified cables that can provide the higher bandwidth required for higher bit-depth video and higher bit-rate audio, HDMI input ports on the TV or AVR that match the outputs from the HTPC, and media that aligns to the hardware capabilities. Common problems that we see include:

* Some TV's and AVR's support different HDMI capabilities on different ports. Some support 4K60 4:2:2 (12-bit) input on specific ports, while other ports support 4K60 4:2:0 (8/10-bit) input.
* Some TV's and AVR's require 4K60 4:2:2 capabilities to be enabled in TV settings else the port defaults to 4K60 4:2:0 input. There is no standardised naming among vendors so we have seen "Deep Colour" and "Enhanced HDMI" used to describe 4K60 4:2:2 support.
* Raspberry Pi 4/5 boards notably do not support 4K60 4:2:0 output. If the TV or connected port only supports 4K60 4:2:0 input the 4K60 modes will (correctly) not be available.
* Raspberry Pi 4 boards need configuration in `/flash/config.txt` to enable 4K @ 60/59.94/50 mode output. This is not enabled by default because it increases power consumption, and as most media uses 4K\@30/23.976 most users do not need to enable 4K60 modes.
* Raspberry Pi 5 devices support 4K60 output by default and do not require `/flash/config.txt` configuration. This is one reason why Raspberry Pi 5 boards require a higher rated PSU. If you do not need 4K60 output most 5V/3A PSU's used with RPi4 work fine with an RPi5 too.
* 4K @ 60/59.94/50 modes require an HDMI 2.0 cable that supports the much higher bandwidth needed. Suitable cables are normally sold as 4K\@60 "certified" cables. Cheaper and lower-spec cables that support HDMI 1.4 modes (up to 4K\@30) are a frequent cause of "I've enabled 4K\@60 but have a blank screen" issue reports in the forums.

<mark style="color:red;">**If you are unable to use 4K60 modes: please check cables, check port capabilities, and if using SBC boards; check the PSU can handle the needed current draw before reporting issues in the forums!**</mark>

### HDR

Broadcast and Internet media follow a multitude of formal standards for resolution, refresh-rate, bit-depth, video format and colour-space. HDR formats add static or dynamic metadata to the stream or even individual video frames to enhance how colours are displayed. Kodi on Linux can support static HDR formats like HLG and HDR10, but not dynamic (proprietary) formats like HDR10+ and Dolby Vision which do not have open-source implementations. Users should understand HDR is not a simple "My TV can do 4K" type standard. HDR is a collection of competing technical standards (format wars are in progress) and the number of variables that must be determined and processed to render something nice looking on screen is huge.

Kodi aims to hide the mind-bending complexity of choosing how HDR media will be displayed on screen by detecting what your HTPC device and TV support and what the media to be played requires, allowing the display pipeline to automatically configure itself for the best result; whether that is an exact match or the best compromise. Kodi and LibreELEC support for HDR formats is still in early stages.

<mark style="color:red;">**Recommendation: There is nothing specific to configure for HDR itself (only 4K things) so sit back and enjoy that Kodi and LibreELEC developers are working to bring HDR support to your living room, for free. Please be patient, because it's a long and complicated task!**</mark>

Here are some answers to common HDR questions:

* Kodi does not support HDR to SDR conversion (tonemapping) on Linux. If you play HDR media on a TV that does not support HDR, it will often play but colours will be muted and washed out. In the future Kodi may support conversion, but it is not currently implemented.
* Kodi has no way to present OSD menus in SDR when playing HDR media, so menus will have bright saturated colours. In the future, plane based tonemapping may be able to correct this, but it is not currently implemented and not all hardware supports multiple planes.
* Kodi will attempt to output in the highest bit-depth supported by the display pipeline, e.g. on a Raspberry Pi 4 it will attempt 12-bit before falling back to 10-bit, then 8-bit. Not all 4K HDR capable hardware supports higher 12-bit and 10-bit depths.
* Kodi supports Dolby Vision under Android (if the device is licensed for it) but not Linux. Dolby requires manufacturers to license their Intellectual Property and use integration libraries to decode the HDR metadata. Until FFMpeg comes up with a "clean room" reverse engineered open-source implementation, Kodi will not support it.


# Blu-ray Playback

No official Blu-ray player software exists for Linux, but open-source libraries allow Kodi (on LibreELEC) to play most Blu-ray discs once `/storage/.config/aacs/KEYDB.cfg` has been populated with a flat-file database of known encryption keys and certificates. To avoid legal issues with DMCA laws in the USA we cannot pre-configure a key database, so you must install this yourself.

Connect to your LibreELEC device via SSH, then run the following commands:

```
mkdir -p /storage/.config/aacs
curl -k -L http://fvonline-db.bplaced.net/fv_download.php?reduced -o /storage/.config/aacs/keydb.zip
unzip /storage/.config/aacs/keydb.zip -d /storage/.config/aacs/
mv /storage/.config/aacs/keydb.cfg /storage/.config/aacs/KEYDB.cfg
rm /storage/.config/aacs/keydb.zip
```

The current file contains PK, HC, VUK and UK data required for attempting disc decryption with more than 170,000 titles. Periodically running the commands will refresh the `KEYDB.cfg` file and add support for new Blu-ray discs.

{% hint style="info" %}
For a more detailed description on how Blu-ray DRM works on Linux, please refer to this article on the Arch Linux wiki: <https://wiki.archlinux.org/index.php/Blu-ray>
{% endhint %}


# Config.txt

On Raspberry Pi hardware, the `config.txt` file is used to configure boot and hardware configuration, similar to how the BIOS or UEFI are used on an PC.

## Editing config.txt

There are two options for editing `config.txt`: over the network using SSH or removing the storage medium (SD card, USB drive) and editing the file directly on your computer.

### Editing via SSH

`config.txt` is usually on the `/boot` partition in Raspberry Pi OS. In LibreELEC, the `/flash` boot partition is read-only by default, so we need to remount it in read-write mode:

```
mount -o remount,rw /flash
```

We will use the `nano` text editor to modify the file. Save changes with `ctrl+o` and exit using `ctrl+x`:

```
nano /flash/config.txt
```

After editing, set the `/flash` partition back to read-only mode:

```
mount -o remount,ro /flash
```

Finally, reboot for the changes in `config.txt` to be applied:

```
reboot
```

## Editing on your computer

Turn off the Raspberry Pi, remove the SD card or USB drive on which LibreELEC is installed, and use a card reader connected to your Windows, Linux, or macOS computer.

If using Windows, use a text editor capable of saving text files in Unix format, e.g. [Notepad++](https://notepad-plus-plus.org/downloads) or Wordpad.exe (not Notepad.exe).

## Adding codec licenses or specific hardware HATs

### MPEG2 and VC-1 Licenses

* Raspberry Pi 0/1/2 cannot hardware-decode MPEG2/VC-1 media files without a license key that can be purchased from the [Raspberry Pi Foundation](https://codecs.raspberrypi.com/license-keys/). The hardware is too slow to software decode these formats without the keys.
* Raspberry Pi 3 hardware has higher spec CPUs and is capable of software-decoding without the licenses, although purchasing them allows hardware-decoding and your device will run cooler.
* Raspberry Pi 4 is capable of software decoding these formats and license keys are not available.

To purchase license keys you need the serial number of your Raspberry Pi. This can be read with the following command:

```
cat /proc/cpuinfo
```

Edit `config.txt` as described above, uncommenting the license key lines by removing the `#` marks, and replacing `00000000` with the keys you received after purchasing:

```
decode_MPG2=0x00000000
decode_WVC1=0x00000000
```

Reboot and confirm the license keys are installed correctly by running these commands:

```
vcgencmd codec_enabled MPG2
vcgencmd codec_enabled WVC1
```

If the licenses are enabled you should see this:

```
MPG2=enabled
WVC1=enabled
```

If any key that you purchased shows `disabled` check that:

* You entered the correct serial number
* You added the licence key to `config.txt` correctly
* You uncommented the lines in `config.txt` by removing the `\#` mark (and space)
* You rebooted before testing

### Overlays for HATs and extra hardware

Raspberry Pi kernels use a board-specific device-tree file to describe the board's hardware and how things are connected. As the Raspberry Pi is designed to be extended with extra hardware via HATs and peripheral connectors the kernel also supports device-tree "overlay" files. When configured, these overlay "fragments" of device-tree content that describe the extra hardware on the board device-tree, and the kernel reads them as a single combined file.

Overlays can be found in `/flash/overlays` and they are configured in `config.txt` in the root folder of the SD card that you boot the Raspberry Pi from. The following are examples of common overlay changes.

#### Audio Interfaces

```
dtoverlay=hifiberry-dac
dtoverlay=hifiberry-dacplus
dtoverlay=hifiberry-digi
dtoverlay=hifiberry-amp
dtoverlay=iqaudio-dac
dtoverlay=iqaudio-dacplus
```

On RPi 5, using Libreelec 12 and upwards, different audio interfaces are needed:

```
dtoverlay=hifiberry-dacplus
dtoverlay=hifiberry-dacplus-std
dtoverlay=hifiberry-dacplus-pro
```

With kernels older than 6.1.77 on RPi 5, "slave" mode must be forced:

```
dtoverlay=hifiberry-dacplus,slave
```

#### Infra-Red Receivers

```
dtoverlay=gpio-ir
```

Override defaults for the gpio-ir module:

```
dtoverlay=gpio-ir,gpio_pin=25,gpio_pull=up,rc-map-name=rc-technisat-usb2
```

#### Optional hardware interfaces

```
dtparam=i2c1=on  # for later RPi's
dtparam=i2c0=on  # for early RPi's
dtparam=spi=on
```

## Overclocking

Please see [the Raspberry Pi documentation](https://www.raspberrypi.com/documentation/computers/config_txt.html#overclocking-options) for more details on overclocking.


# Cron

cron can be used to schedule timed event execution of binaries and scripts, e.g. download of EPG guides on a repeating time interval (hourly, every 12 hours, etc.) or running a nightly backup script in the background at 2am.&#x20;

Running `crontab -e` will open the root user crontab in `nano` allowing you to paste content your cron commands. Use `ctrl+o` to save the file and `ctrl-x` to exit nano.&#x20;

For more info on cron commands, see: <https://help.ubuntu.com/community/CronHowto>


# Dual Boot

It is technically possible to dual-boot LibreELEC alongside an existing Windows or Linux installation, but the installation process is complex and less experienced users are prone to mistakes that result in their main Desktop OS and personal data being wiped from the hard drive. LibreELEC installers assume a dedicated disk target and cannot install into a spare partition or free space on the same drive that boots the Desktop OS. For this reason the project staff do not encourage or support dual-boot configurations. If you choose to attempt one and things go wrong, you were warned!


# EDID

## Custom EDID

To change the order of turning on your devices (normally your HTPC has to be powered on last) or to use your LibreELEC device without the TV turned on, you need to dump/save the EDID information from your TV (or AVR).

In the steps below we will explain how this can be done:

**Note:** Your devices should all be turned on and you should have a screen and audio working. Otherwise the EDID information isn't provided properly and this How-To won't work.

In the sections below we explain different ways to dump and use the EDID information. We also provide a script which performs the specific steps for the various devices automatically.

On x86\_64 the steps for Intel and nVidia based GPUs differ significantly from each other.

## Generic x86\_64

**Note:** This script will also only work for Intel or nVidia based GPUs. AMD/ATI GPU's are not supported.

To use the getedid script you need to have SSH access to your LibreELEC machine.

Once you are in, just type in

```
getedid
```

to see which options are available. It will look like this.

![](/files/-MMfAHRSCXupi7KY6YTG)

The available options are `create`, `gpu`, `delete` and `help`. These are explained below.

#### getedid help

This will show a help message and a little explanation for the specific options.

#### getedid gpu

This will check which GPU you are using and you will either get "Intel", "NVidia" or "GPU is not supported" after running that command.

#### getedid create

This will do all needed steps which are needed to dump the EDID for the GPU you are using. It first checks if the GPU is supported, then it checks if you already have done changes to the files which the script needs to change, too. If you already have done some changes to those files, the script will stop and you should dump the EDID manually. Those steps are explained in the other tabs. The reason for that is, that we can't know what you already have changed and therefore the script might do something horrible wrong and we don't want to break your system. As you already know how to edit those files it should not be that hard to do that again.

If the files are like they should be from a vanilla installation, the script does its thing and will do everything which is necessary and reboot your machine after everything is done as expected.

After that you shouldn't take care about the ordering how to turn on your devices, anymore. Your HTPC should also be turned on as the first device in the chain now.

#### getedid delete

This will delete all the created files from `getedid create` if you have used it before. After using `getedid delete` the default configuration is restored. No unneeded files on it, everything is like a vanilla installation and you have to take care about the ordering how to turn on your devices again.

For the source of that script please look at: <https://github.com/LibreELEC/LibreELEC.tv/blob/master/packages/sysutils/busybox/scripts/getedid>

### Intel

#### Get the needed information about your system

First, you have to SSH in your LibreELEC machine. Then enter the following command.

```
tail /sys/class/drm/*/status
```

Look for the connected device:

![how it looks like at the shell](/files/-MMfAOuZssX4hIDQ2uoj)

```
==> /sys/class/drm/card0-HDMI-A-2/status <==
connected
```

The information we need **HDMI-A-2** is connected.

#### Create the EDID file

Now we will create a copy of the EDID binary data and put it where it needs to go. Change the cat command to match the active HDMI/DP port. For the possibility to copy and paste the correct commands, change the tabs below to the matching port.

```
mkdir -p /storage/.config/firmware/edid
```

HDMI-A-1

```
cat /sys/class/drm/card0-HDMI-A-1/edid > /storage/.config/firmware/edid/edid.bin
```

HDMI-A-2

```
cat /sys/class/drm/card0-HDMI-A-2/edid > /storage/.config/firmware/edid/edid.bin
```

Next a cpio archive file will be created which will be loaded at boot.

```
cd ~
mkdir -p cpio/lib/firmware/edid
cp .config/firmware/edid/edid.bin cpio/lib/firmware/edid/
cd cpio/
find . -print | cpio -ov -H newc > ../edid.cpio
```

#### Editing the extlinux.conf or syslinux.cfg

Now mount the boot partition as "RW" and move the file to it

```
mount -o remount,rw /flash
mv ../edid.cpio /flash/
```

After the file is moved to the correct place, we have to add some boot parameters. For this we have edit either the "extlinux.conf" or the "syslinux.cfg" file in your /flash/ directory. Use this command to check which one is available.

```
ls /flash/
```

Search for "extlinux.conf" or "syslinux.cfg" and edit it. Only one of them is available.

**syslinux.cfg**

```
nano /flash/syslinux.cfg
```

**extlinux.conf**

```
nano /flash/extlinux.conf
```

Note: If you are not using LibreELEC 9.0 or newer please use nano -w instead of nano

Add to the APPEND line the following things.

HDMI-A-1

```
initrd=/edid.cpio drm.edid_firmware=edid/edid.bin video=HDMI-A-1:D
```

The APPEND line should look this like this after (everything in a single line):

```
APPEND boot=LABEL=System disk=LABEL=Storage ssh quiet initrd=/edid.cpio drm.edid_firmware=edid/edid.bin video=HDMI-A-1:D
```

HDMI-A-2

```
initrd=/edid.cpio drm.edid_firmware=edid/edid.bin video=HDMI-A-2:D
```

The APPEND line should look this like this after (everything in a single line).

```
APPEND boot=LABEL=System disk=LABEL=Storage ssh quiet drm.edid_firmware=edid/edid.bin video=HDMI-A-2:D
```

Last step is to reboot the device.

```
reboot
```

### nVidia

If you boot your nVidia GPU based LibreELEC box before the TV/AVR and you see a black screen on boot - follow this guide to create an edid.bin file that tricks Xorg into thinking the TV/AVR are powered on at boot time.

**Note:** This example will NOT work on Intel or AMD GPU's.

#### Get the needed information about your system

Open an SSH session to your LibreELEC machine. Once logged into the console we need to work out the DFP number.

```
grep ": connected" /var/log/Xorg.0.log | head -n 1
```

You should see message like the following:

```
  [3241512.110] (--) NVIDIA(0): SAMSUNG (DFP-0): connected
```

Note the DFP number - in this example it is "DFP-0" but yours may be different.

#### Set Xorg to Debug Mode

To extract EDID data we need we need to place Xorg into debug mode. First we stop Xorg.

```
systemctl stop xorg.service
```

Next we clone the xorg.conf to the config override location in `/storage/.config`.

```
cp /etc/X11/xorg-nvidia.conf /storage/.config/xorg.conf
```

Then we edit the file with `sed` to enable debug mode.

```
sed -i 's/"ModeDebug" "false"/"ModeDebug" "true"/g' /storage/.config/xorg.conf
```

The device section in the modified file should look something like this.

```
Section "Device"
    Identifier     "nvidia"
    Driver         "nvidia"
    Option         "DynamicTwinView" "False"
    Option         "NoFlip" "false"
    Option         "NoLogo" "true"
    Option         "ConnectToAcpid" "0"
    Option         "FlatPanelProperties" "Scaling = Native"
    Option         "ModeValidation" "NoVesaModes, NoXServerModes"
    Option         "HWCursor" "false"
    Option         "ModeDebug" "true"
EndSection
```

Now restart Xorg.

```
systemctl start xorg.service
```

#### Create the EDID file

Extract the RAW binary EDID information from the debug /var/log/Xog.0.log to a file.

```
nvidia-xconfig --extract-edids-from-file=/var/log/Xorg.0.log --extract-edids-output-file=/storage/.config/edid.bin
```

The command should output something like.

```
Found 1 EDID in "/var/log/Xorg.0.log".
Wrote EDID for "ONK TX-NR616 (DFP-0)" to "/storage/.config/edid.bin" (256 bytes).
```

#### Edit xorg.conf

Now we edit /storage/.config/xorg.conf - set ModeDebug back to False (edit the word true to false) and uncomment the following lines.

```
Option         "ConnectedMonitor" "DFP-0"
Option         "CustomEDID" "DFP-0:/storage/.config/edid.bin"
Option         "IgnoreEDID" "false"
Option         "UseEDID" "true"
```

Make sure you change the DFP number to match the one we found earlier. In the end your config will look something like.

```
Section "Device"
  Identifier     "nvidia"
  Driver         "nvidia"
  Option         "DynamicTwinView" "False"
  Option         "NoFlip" "false"
  Option         "NoLogo" "true"
  Option         "ConnectToAcpid" "0"
  Option         "FlatPanelProperties" "Scaling = Native"
  Option         "ModeValidation" "NoVesaModes, NoXServerModes"
  Option         "HWCursor" "false"
  Option         "ModeDebug" "false"
  Option         "ConnectedMonitor" "DFP-0"
  Option         "CustomEDID" "DFP-0:/storage/.config/edid.bin"
  Option         "IgnoreEDID" "false"
  Option         "UseEDID" "true"
EndSection
Section "Screen"
  Identifier     "screen"
  Device         "nvidia"
  DefaultDepth    24
  Option         "ColorRange" "Full"
 #    Option         "ColorRange" "Limited"
 #    Option         "ColorSpace" "RGB"
  SubSection     "Display"
   Depth       24
  EndSubSection
EndSection
Section "Extensions"
  Option         "Composite" "false"
EndSection
```

Finally we stop/restart xorg.service to disable debug mode and use the new edid.bin file.

```
systemctl restart xorg.service
```

If all has gone to plan Xorg now detects the EDID file and the order of powering on equipment no longer matters!

## Amlogic (Legacy)

Amlogic legacy kernel devices (using 3.10, 3.14 kernels) do not capture "edid.bin" files like Intel and nVidia devices, but a similar process can capture, store and force the resolutions of a device. Connect your HTPC device directly to the HDMI source that you want to capture EDID information from, then login over SSH and run the following command.

```
cat /sys/class/amhdmitx/amhdmitx0/disp_cap > /storage/.kodi/userdata/disp_cap
```

This stores a list of the supported resolutions. It looks like

```
480p60hz
480p_rpt
576p50hz
720p60hz
1080i60hz
1080p60hz
720p50hz
1080i50hz
1080p30hz
1080p50hz
1080p25hz
1080p24hz
2160p30hz
2160p25hz
2160p24hz
smpte24hz
smpte25hz
smpte30hz
smpte50hz
smpte60hz
smpte50hz420
smpte60hz420
2160p50hz
2160p60hz
2160p50hz420
2160p60hz420
```

To remove or add specific resolutions, e.g. if 1080p24hz is missing, edit disp\_cap.

```
nano /storage/.kodi/userdata/disp_cap
```

Ctrl+o to save, Ctrl+x to exit the nano editor. Next restart Kodi by rebooting the box or running.

```
systemctl restart kodi
```

## Raspberry Pi

The getedid script can be used as described for [Generic x86\_64](#generic-x86_64).


# Fonts

Kodi includes a default font that supports a large number of languages in a reasonable file size. It does not support all languages as this would require a font file larger than a LibreELEC image!

If you see blank squares for titles and filenames instead of readable text - You need to add a custom Arial True-Type (.ttf) font that supports the missing language characters and glyphs.

In LibreELEC create `/storage/.kodi/userspace/Fonts/` (note the capital F) and place an Arial based font in the folder, e.g. `/storage/.kodi/userspace/Fonts/Arial.ttf` - after rebooting or restarting Kodi the font can be selected in Kodi Settings > Interface > Skin > Fonts.


# Hidden WiFi

WiFi networks with a hidden SSID are not visible to the connection manager (ConnMan) so cannot be selected in the LibreELEC settings add-on, and even if you manually configure a new ConnMan network profile via SSH, ConnMan cannot see the network to use the stored profile to connect.&#x20;

LE10 and older use ConnMan to manage connections and `wpa_supplicant` to create the actual connection. LE11 also use ConnMan to manage connections, but switched from `wpa_supplicant` to `iwd` allowing a simple `systemd` service to be used for connecting to hidden networks.

Create `/storage/.config/system.d/hidden-ssid.service` with the following content:

```sh
[Unit]
Description=Hidden SSID Connect Service
After=network-online.target connman.service iwd.service
Wants=network-online.target connman.service iwd.service
Before=kodi.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/iwctl --passphrase <PWD> station wlan0 connect-hidden <SSID>
ExecStop=/usr/bin/iwctl station wlan0 disconnect

[Install]
WantedBy=multi-user.target
```

Replace `<PWD>` with the WiFi passphrase and `<SSID>` with the name of the network. On most LE devices there will only be a single `wlan0` wireless network interface, but if you have more than one card and `wlan1` or `wlan2` etc. are visible, set the correct NIC/card to use.

Next enable and start the `systemd` service:

```sh
systemctl enable /storage/.config/system.d/hidden-ssid.service
systemctl start hidden-ssid.service
```

Starting the service will initiate the connection and `ifconfig` should show an active NIC with an IP address. Ensure testing is done with Ethernet cables unplugged else the default traffic `route` will be on the `eth0` Ethernet connection.

{% hint style="info" %}
**Users often hide the network SSID to improve privacy and network security, but the SSID is disclosed in client connection requests making a hidden network easily discoverable to anyone sniffing WiFi packets and looking for it. Hiding the SSID provides zero protection.**
{% endhint %}


# Hypercon

## <mark style="color:red;">Not working anymore since LE10</mark>

<mark style="color:red;">Starting with LE10 Hyperion no longer works due to changes in the video pipeline. Consider hardware/external grabbers.</mark>

HyperCon is a graphical application which allows you to configure [Hyperion](https://github.com/LibreELEC/documentation/tree/bb394d22013fdc5f491418b7367a92b73ca7c45a/hyperion.md) (an ambient lighting system) running on a remote LibreELEC device, from a Windows, macOS or Linux desktop. Hypercon is a Java application, and so requires you to have a working Java runtime environment (JRE) installed to run it. Java v1.7 or higher is required.

The latest version is here <http://releases.libreelec.tv/hypercon-LE.jar>

## Linux

On Ubuntu/Debian systems

```
sudo apt-get install openjdk-7-jre
wget http://releases.libreelec.tv/hypercon-LE.jar
```

On Fedora/CentOS systems

```
yum install java-1.7.0-openjdk*.
wget http://releases.libreelec.tv/hypercon-LE.jar
```

To run Hypercon:

```
java -jar ./hypercon-LE.jar
```

## Windows

Download and install the correct 32-bit or 64-bit Java Runtime for your Windows OS version from the official Java download site [https://www.java.com/](https://www.java.com). Open the .jar file as you would a regular .exe file and it should launch using Java (JRE). If not, right click and select “Open with” then “Java” listed in the list.


# Hyperion

<mark style="color:red;">WARNING: Hyperion does not support the GBM/V4L2 video pipeline used in LibreELEC 10.x and 11.x: including all Raspberry Pi and Generic x86\_64 (GBM) releases. Users with x86\_64 hardware can update to the Generic\_Legacy (X11) image. Users with Raspberry Pi hardware must use an external grabber hardware device or remain on older releases. Changes to add GBM support to Hyperion are tracked here:</mark> <https://github.com/hyperion-project/hyperion.ng/pull/1422>

[Hyperion](https://github.com/hyperion-project/hyperion) is an open source project that provides an ambient lighting system, compatible with Kodi. Hyperion requires hardware and software configuration. This page describes the process to add Hyperion to Generic x86\_64 and Raspberry Pi hardware. For software configuration please head over to [Hypercon](/configuration/hypercon).

## Adalight

If you want hardware that will work on any LibreELEC device, an "Adalight" setup is the best choice. It works by sending serial data to an Arduino micro controller which controls the LEDs. You need:

* Arduino (Uno, nano, etc)
* WS2801 LED strand
* 5V power supply
* Wire/Jumpers
* Breadboard/Protoboard (optional)
* Soldering iron (optional)

![Adalight wiring](/files/SDH5ExwaGmtraenl4jNo)

Follow the tutorial here <https://learn.adafruit.com/adalight-diy-ambient-tv-lighting/overview>.

In [Hypercon](/configuration/hypercon) you will need to enable:

![Hypercon configuration Adalight](/files/-MLrOZr42991jQfV9JRd)

## Raspberry Pi

Pi devices can drive an SPI output directly, and hyperion can output to an spidev device. You need:

* Raspberry Pi
* WS2801 LED strand
* 5V power supply
* Wire/Jumpers

![Raspberry Pi wiring](/files/-MLrMcnE8872AlKjX49s)

You can find the pinout here <https://pinout.xyz>. You will need to connect the following pins:

```
19 MOSI -> Data
23 SCLK -> Clock
25 GND  -> Ground
```

You need to enable SPI in the config.txt file:

```
mount -o remount,rw /flash
nano /flash/config.txt
```

Add the following line to the end of the file:

```
dtparam=spi=on
```

Then reboot. In [Hypercon](/configuration/hypercon) you will need to enable:

![Hypercon configuration Raspberry Pi](/files/HWNTugSfeTyrqHeZPX0Z)


# Infra-Red Remotes

## Introduction

Modern Linux kernels (used in LibreELEC) have built-in support for IR remotes. IR signals are decoded by the kernel and programs see button presses from IR remotes in the same way as key presses from a keyboard, as Linux input events. This supersedes the older LIRC approach where a separate program, lircd, decodes IR signals and programs obtain button presses from a socket as LIRC events.

However, Kodi's remote handling was built for LIRC so LibreELEC runs the `eventlircd` service in the background to translate Linux input events into LIRC events. So "under the hood" the kernel scheme is being used, but remote buttons are still handled as LIRC events in Kodi.

Kodi translates the received LIRC events to Kodi button names via `Lircmap.xml` and then buttons are mapped to Kodi actions via `remote.xml` and `keyboard.xml` files. This wiki page describes LibreELEC configuration. Information on Kodi configuration is available in the [Kodi LIRC](http://web.archive.org/web/20201111212253/https://kodi.wiki/view/LIRC) and [Kodi Keyboard.xml](http://web.archive.org/web/20201111212253/https://kodi.wiki/view/Keyboard.xml) wiki pages.

{% hint style="info" %}
LIRC is still shipped in LibreELEC so IR remotes with non-standard protocols that need special setups can still be supported, but it is disabled by default. LIRC is only required in exceptional cases.
{% endhint %}

Note that LIRC requires compatible hardware to decode IR signals. An in-depth discussion of IR decoder hardware is outside the scope of this document. On a Raspberry Pi, LibreELEC can use the GPIO pins to communicate with a hardware IR receiver diode, as long as `config.txt` has been suitably modified to enable GPIO support.

## Configuration

Like most modern Linux distros LibreELEC uses `ir-keytable` to configure Infra-Red remotes. Each IR receiver kernel driver installs a default `keytable` which specifies the IR protocol to use, e.g. RC5, RC6, NEC, and the scancode to Linux keycode mappings.

Most universal receivers work with the rc-rc6-mce table so RC6 MCE remotes can be used without further configuration. Drivers for DVB devices sold with a remote usually install their own keytable, e.g. the Hauppauge remote that came with a Hauppauge DVB stick.

After the kernel driver is loaded `ir-keytable -a` is automatically run to change the kernel default configuration. First `/etc/rc_maps.cfg` determines which keytable to load. Then the corresponding keytable file from `/usr/lib/udev/rc_keymaps` is used to configure the remote control driver.

As most of the LibreELEC filesystem is read-only, we use a system of boot-time file overrides to read user-created configuration from the persistent `/storage` area:

* `/storage/.config/rc_maps.cfg` overrides `/etc/rc_maps.cfg`
* `/storage/.config/rc_maps.cfg.sample` has simple examples
* `/storage/.config/rc_keymaps` overrides `/usr/lib/udev/rc_keymaps`
* `/etc/rc_maps.cfg` uses the `libreelec_multi` keytable instead of `rc6_mce`

The default `libreelec_multi` keytable allows us to support Xbox 360/One remotes "out of box" in addition to MCE/RC6 remotes. This is configured via the following change:

```
# use combined multi-table on MCE receivers
#*      rc-rc6-mce               rc6_mce
*       rc-rc6-mce               libreelec_multi
```

## Can I use any remote?

While most IR receivers can be used with a large variety of remotes the answer to “Can I use remote X with IR receiver Y?” depends on many factors:

* Some IR receivers cannot be configured and you can only use the remote they came with.
* Some receivers only support a subset of protocols, e.g. only RC5, not RC6.
* If a remote uses a protocol not supported by the IR receiver, or a protocol not supported by the Linux kernel, the last option is the RAW (lirc) protocol which allows userspace LIRC to be configured though a custom `lirc.conf` file.

## Configuration (Basic)

LibreELEC ships with 100+ remote keytable files so there is a good chance of finding an existing remote configuration that works, or a partially working keytable that can be used as a starting point for adding the missing buttons (see the "Advanced" section).

1. Look at the keytable files in `/usr/lib/udev/rc_keymaps/`
2. If one of the filenames suggests it could match your remote, try using it
3. If it doesn't work, keep trying..

To test a different keytable file run `ir-keytable -c -w /path/to/keytable-file` e.g.

```
LibreELEC:~ # ir-keytable -c -w /usr/lib/udev/rc_keymaps/samsung
Read samsung table
Old keytable cleared
Wrote 30 keycode(s) to driver
Protocols changed to nec
```

If the output ends with these lines the protocol is not supported by the IR receiver:

```
Invalid protocols selected
Couldn't change the IR protocols
```

If the keytable loaded without errors try pressing the up, down, left, right and OK buttons to see if GUI navigation in Kodi works?

If you find a working keytable make the config persistent by creating `/storage/.config/rc_maps.cfg` with the name of the keytable, e.g. if the `samsung` keytable works, create `rc_maps.cfg` with:

```
* * samsung
```

Then run `ir-keytable -a /storage/.config/rc_maps.cfg` and the output should look like:

```
LibreELEC:~ # ir-keytable -a /storage/.config/rc_maps.cfg
Old keytable cleared
Wrote 30 keycode(s) to driver
Protocols changed to nec
```

Test the buttons work again, and if all is okay, you can reboot.

## Configuration (Advanced)

If you cannot find a working keymap or the current keymap has missing buttons you can create your own. Since LibreELEC 10.x the keytable file is plain text file in `toml` markup format. The first section describes the name of the keymap (free text, but avoid special characters and spaces) and the remote protocol and variant. This is followed by lines that map the remote scancode to a Linux keycode. A typical keytable file in toml format looks like this:

```
[[protocols]]
name = "khadas"
protocol = "nec"
variant = "nec"
[protocols.scancodes]
0x14 = "KEY_POWER"
0x03 = "KEY_UP"
0x02 = "KEY_DOWN"
0x0e = "KEY_LEFT"
0x1a = "KEY_RIGHT"
0x07 = "KEY_OK"
0x01 = "KEY_BACK"
0x5b = "KEY_MUTE"
0x13 = "KEY_MENU"
0x58 = "KEY_VOLUMEDOWN"
0x0b = "KEY_VOLUMEUP"
0x48 = "KEY_HOME"
```

{% hint style="info" %}
Older LibreELEC releases (v7.x to v9.x) use a plain text format not `toml` but the process is essentially the same. Look at existing keymaps in `/usr/lib/udev/rc_keymaps` to crib the format.
{% endhint %}

To capture the keycodes you must stop Kodi and eventlircd first, or these services capture IR input and you will see no output from `ir-keytable`:

```
systemctl stop kodi
systemctl stop eventlircd
```

Next we have to identify the IR protocol. If you found a partially working keytable file (with the protocol listed in the header) you can skip this step. First we run `ir-keytable` to find out which protocols the receiver driver supports. Look at the `Supported protocols:` line, e.g.

```
LibreELEC:~ # ir-keytable
Found /sys/class/rc/rc0/ (/dev/input/event1) with:
        Driver gpio-rc-recv, table rc-rc6-mce
        Supported protocols: lirc rc-5 rc-5-sz jvc sony nec sanyo mce_kbd rc-6 sharp xmp
        Enabled protocols: lirc nec rc-6
        Name: gpio_ir_recv
        bus: 25, vendor/product: 0001:0001, version: 0x0100
        Repeat delay = 500 ms, repeat period = 125 ms
```

Run `ir-keytable -p PROTOCOL -t` and press buttons on the remote. If you discover the correct protocol you will see `EV_MSC` events and the scancode of the button pressed, e.g.

```
LibreELEC:~ # ir-keytable -p rc-5 -t
Protocols changed to rc-5
Testing events. Please, press CTRL-C to abort.
1503592437.660155: event type EV_MSC(0x04): scancode = 0x101a
1503592437.660155: event type EV_SYN(0x00).
1503592437.774129: event type EV_MSC(0x04): scancode = 0x101a
1503592437.774129: event type EV_SYN(0x00).
1503592437.921009: event type EV_MSC(0x04): scancode = 0x101a
```

If you see no events stop ir-keytable with `CTRL-C` and try another protocol from the list. You can ignore `lirc` as this is not a real protocol.

Once you find the correct IR protocol create `/storage/.config/rc_keymaps/custom_remote` and set the header file. In the example above the protocol is `rc-5` so we set:

```
# table custom_remote, type: rc-5
```

If you found a partially working keytable, clone it and then edit the header to say `custom_remote`:

```
cp /usr/lib/udev/rc_keymaps/samsung /storage/.config/rc_keymaps/custom_remote
```

Next we capture the scancodes and document the keycode mapping. Some users find it easiest to open two SSH connections; one to see ir-keytable scancode output in, and one so they can copy/paste scancodes directly into the `custom_remote` keytable file, e.g. in one open the `nano` editor:

```
nano /storage/.config/rc_keymaps/custom_remote
```

And in the second run `ir-keytable -t` to find out the scancode of each button. For each button do the following:

* Press a button and note the scancode (the 0x… value after scancode:)
* Add a new line with the scancode (including 0x).
* Add the Linux keycode in "quoted" format and separated with a blank.

You can get a list of all supported Linux keycodes via `irrecord -l | grep ^KEY` but it is easiest to use keycodes listed in the `<remote device=“devinput”>` section of `/usr/share/kodi/system/Lircmap.xml` else you must also create a Kodi `lircmap.xml` with Linux keycode to action mappings.

The table below has a selection of common keycodes:

| Keycode        | Keycode            | Keycode           | Keycode             |
| -------------- | ------------------ | ----------------- | ------------------- |
| KEY\_LEFT      | KEY\_STOPCD        | KEY\_INFO         | KEY\_TEXT           |
| KEY\_RIGHT     | KEY\_FASTFORWARD   | KEY\_PROPS        | KEY\_1              |
| KEY\_UP        | KEY\_FORWARD       | KEY\_ZOOM         | KEY\_2              |
| KEY\_DOWN      | KEY\_REWIND        | KEY\_ANGLE        | KEY\_3              |
| KEY\_OK        | KEY\_VOLUMEUP      | KEY\_MUTE         | KEY\_4              |
| KEY\_ENTER     | KEY\_VOLUMEDOWN    | KEY\_POWER        | KEY\_5              |
| KEY\_SELECT    | KEY\_CHANNELUP     | KEY\_SLEEP        | KEY\_6              |
| KEY\_DELETE    | KEY\_CHANNELDOWN   | KEY\_WAKEUP       | KEY\_7              |
| KEY\_ESC       | KEY\_PAGEUP        | KEY\_EJECTCD      | KEY\_8              |
| KEY\_MEDIA     | KEY\_PAGEDOWN      | KEY\_EJECTCLOSECD | KEY\_9              |
| KEY\_HOME      | KEY\_NEXT          | KEY\_DVD          | KEY\_0              |
| KEY\_EXIT      | KEY\_NEXTSONG      | KEY\_MENU         | KEY\_NUMERIC\_STAR  |
| KEY\_BACK      | KEY\_PREVIOUS      | KEY\_VIDEO        | KEY\_NUMERIC\_POUND |
| KEY\_BACKSPACE | KEY\_PREVIOUSSONG  | KEY\_AUDIO        | KEY\_RED            |
| KEY\_ESC       | KEY\_EPG           | KEY\_MP3          | KEY\_GREEN          |
| KEY\_RECORD    | KEY\_TITLE         | KEY\_CAMERA       | KEY\_BLUE           |
| KEY\_PLAY      | KEY\_TV2           | KEY\_IMAGES       | KEY PVR             |
| KEY\_PLAYPAUSE | KEY\_CONTEXT\_MENU | KEY\_TUNER        | KEY\_RADIO          |
| KEY\_PAUSE     | KEY\_SUBTITLE      | KEY\_TV           |                     |
| KEY\_STOP      | KEY\_LANGUAGE      | KEY\_PVR          |                     |

Once you are finished with the keytable, save the file, stop ir-keytable -t with `CTRL-C` and then restart it with the keytable file:

```
LibreELEC:~ # ir-keytable -c -w /storage/.config/rc_keymaps/custom_remote
Read justboom table
Old keytable cleared
Wrote 12 keycode(s) to driver
Protocols changed to rc-5
```

Now run `ir-keytable -t` and press buttons. In addition to EV\_MSC scancode events you should now see EV\_KEY events, e.g.

```
LibreELEC:~ # ir-keytable -t
Testing events. Please, press CTRL-C to abort.
1503599395.150849: event type EV_MSC(0x04): scancode = 0x1019
1503599395.150849: event type EV_KEY(0x01) key_down: KEY_VOLUMEUP(0x0073)
1503599395.150849: event type EV_SYN(0x00).
1503599395.264827: event type EV_MSC(0x04): scancode = 0x1019
1503599395.264827: event type EV_SYN(0x00).
1503599395.413668: event type EV_MSC(0x04): scancode = 0x1019
1503599395.413668: event type EV_SYN(0x00).
1503599395.673626: event type EV_KEY(0x01) key_up: KEY_VOLUMEUP(0x0073)
1503599395.673626: event type EV_SYN(0x00).
```

If the test is successful, make the keytable persistent by creating `/storage/.config/rc_maps.cfg` with the following content:

```
* * custom_remote
```

Reboot and you should have a working remote in Kodi.

## Troubleshooting

Check the obvious. Batteries run down and either stop the remote from working or reduce the working range. Try using the remote in-front of the receiver. You can also try pointing the IR transmitter at the sensor of a digital camera or smartphone in a dark room. If the IR transmitter works you should see it light up the camera/smartphone screen.

If the remote is sending signals, there are several steps until a button press on your remote triggers an action in Kodi. Use this guide to check each step and trace the problem:

To check if the IR receiver driver is loaded run `ir-keytable`. If you see the error message `/sys/class/rc/: No such file or directory` no driver is loaded.

To check if the IR receiver is receiving any signals, see if `ir-keytable` shows `lirc` as a supported protocol. If yes, run `ir-ctl -r` to show raw, undecoded signals from the receiver. If IR reception works you will see lots of pulse and space lines when pressing a button. Note: On kernels before 4.3 lirc may be listed in Supported protocols but not in Enabled protocols. In this case run `ir-keytable -p lirc` to enable it first (remembering this will disable other decoders).

To check if `lircd` is running run `ir-keytable`. If only `lirc` shows up in `Enabled protocols:` lircd is running. When it starts it disables all other protocols). You can also run `ps | grep /usr/sbin/lircd` to check for `/usr/sbin/lircd` and `/usr/sbin/lircd-uinput` processes. If you see them LIRC enabled. If LIRC is enabled, disable it in LibreELEC Settings > Services and reboot.

To check if the correct keytable is loaded run `ir-keytable -r` to show the current keytable and protocol. Compare this to the header in `/storage/.config/rc_keymaps/custom_remote` and check `/storage/.config/rc_maps.cfg` references the correct keytable name.

To check if IR decoding works correctly stop Kodi and eventlircd:

```
systemctl stop kodi
systemctl stop eventlircd
```

Then run `ir-keytable -t` and press buttons on the remote. You should see EV\_MSC events with the scancode and EV\_KEY events with the Linux keycode, e.g.

```
LibreELEC:~ # ir-keytable -t
Testing events. Please, press CTRL-C to abort.
1503599395.150849: event type EV_MSC(0x04): scancode = 0x1019
1503599395.150849: event type EV_KEY(0x01) key_down: KEY_VOLUMEUP(0x0073)
```

If you only get EV\_MSC but no EV\_KEY events, verify if the correct keytable is configured.

After this test, restart eventlircd and Kodi (or reboot):

```
systemctl start eventlircd
systemctl start kodi
```

To check if eventlircd translates the input events to LIRC events run `irw` to show the translated LIRC events Kodi sees. When pressing a button you should see messages like this:

```
LibreELEC:~ # irw
72 0 KEY_VOLUMEDOWN devinput
72 1 KEY_VOLUMEDOWN devinput
72 2 KEY_VOLUMEDOWN devinput
```

To check if Kodi receives the translated LIRC events enable debug logging in System Settings > Logging then watch the logfile:

```
tail -f /storage/.kodi/temp/kodi.log
```

When you press a button you should see log entries with `LIRC: Update` like this:

```
21:55:33.891 T:1945866240   DEBUG: LIRC: Update - NEW at 60659:6c 0 KEY_DOWN devinput (KEY_DOWN)
21:55:33.891 T:1945866240   DEBUG: OnKey: 167 (0xa7, obc88) pressed, action is Down
```

The LIRC line indicates Kodi received the LIRC event. The `OnKey:` line shows the action generated after applying `Lircmap.xml` and `remote.xml`. If you see LIRC lines but incorrect actions, check your Kodi `Lircmap.xml` and `remote.xml` config files are correct.

## Known Issues

USB data transfers can interfere with GPIO IR receivers on Raspberry Pi 0/1/2/3 hardware, and since Ethernet is internally connected via USB playing large movies from a NAS can exhibit the problem. This is a known issue: [see this forum post for details](https://github.com/raspberrypi/linux/issues/906) and there is nothing we can do. Common workarounds are to use a USB IR receiver like [Flirc](https://flirc.tv) or CEC.

## LIRC Support

Most remotes are now supported by the Linux kernel but "LIRC" (the userspace lircd daemon and tools) is still useful for handling unusual remotes with odd protocols and no kernel drivers. Since LibreELEC 8.2.0 LIRC is disabled by default, but can be enabled in LibreELEC Settings > Services > Lirc. Configuration is handled in (almost) the same way as most desktop Linux distros:

* The `/etc/lirc/lirc_options.conf` file configures the default LIRC driver and /dev/lirc0.
* The `/etc/lirc/lircd.conf` file includes remote configs for MCE, Xbox 360, Xbox One, and a few others.

The embedded files can be overridden at boot time by creating `/storage/.config/lircd.conf` and `/storage/.config/lirc_options.conf` with needed changes.

In LibreELEC `lircd-uinput` reads decoded LIRC events from `/run/lirc/lircd.socket` and translates these to Linux input events via the Linux uinput driver. The Linux input events from lircd-uinput are then picked up by `eventlircd` and fed to Kodi as LIRC events via the `/run/lirc/lircd` socket.

It might seem odd to translate between LIRC, Linux input and (again) LIRC events, but Kodi can only receive LIRC events on a single LIRC socket, and this allows eventlircd to collect all remote events and feed them to Kodi so we can support LIRC-decoded and kernel-decoded remotes without needing user input or complex scripts to change the configuration.

To use LIRC with an IR receiver that supports in-kernel decoding it's best to disable ir-keytable auto configuration with an empty `rc_maps.cfg` file:

```
touch /storage/.config/rc_maps.cfg
```

Although lircd disables all remote protocols (and thus in-kernel decoding) on startup ir-keytable auto-configuration runs in parallel, and if it happens to run after lircd starts it can re-enable in-kernel decoding. This causes duplicate decoding as both lircd and kernel will receive and process the IR signals. This issue is often intermittent since it depends on the timing of lircd start. Sometimes lircd will run after ir-keytable and in-kernel decoding is disabled as expected.

Note: If you stop or disable LIRC in LibreELEC Settings you will need too reboot or set ir-keytable manually from the SSH console. Disabling LIRC does not automatically re-enable in-kernel decoding.

## Apple IR Remotes

Older LibreELEC releases used `atvclient` to support the Apple IR sensor and send LIRC events to Kodi. Since 9.2.0 we use the native Linux kernel driver for the IR sensor, which sends normal HID events. Create a custom keymap in `/storage/.kodi/userdata/keymaps/keymap.xml` with the following content to map a White or Silver remote:

```markup
<keymap>
    <global>
        <keyboard>
            <browser_back>Left</browser_back>
            <browser_forward>Right</browser_forward>
            <volume_up>Up</volume_up>
            <volume_down>Down</volume_down>
            <key id="61952">Back</key>
        </keyboard>
    </global>
    <Visualisation>
        <keyboard>
            <volume_up>VolumeUp</volume_up>
            <volume_down>VolumeDown</volume_down>
        </keyboard>
    </Visualisation>
    <FullscreenVideo>
        <keyboard>
            <volume_up>VolumeUp</volume_up>
            <volume_down>VolumeDown</volume_down>
        </keyboard>
    </FullscreenVideo>
</keymap>
```


# LCDProc

Since Kodi v17 LCD/VFD displays are supported through the LCDProc add-on which must be installed from the Kodi add-on repo. See [script.xbmc.lcdproc/wiki](https://github.com/herrnst/script.xbmc.lcdproc/wiki) for documentation and [LCD.xml.defaults](https://github.com/herrnst/script.xbmc.lcdproc/blob/master/resources/LCD.xml.defaults) for a sample file, and the [LCDProc add-on support thread in Kodi forums](https://forum.kodi.tv/showthread.php?tid=143912).

## Configuration

The `/storage/.kodi/userdata/LCD.xml` file can be created to customise output to an LCD or VFD display. It contains "content" sections that describe how the display will look:

* `<Navigation>` is used for navigation in menus
* `<Music>` is used when listening to music
* `<Video>` is used when watching videos
* `<Tvshow>` is used when watching videos classified as TV shows
* `<General>` is used when there is no activity

Each section contains `<line>` items representing one physical line on the display. Lines scroll horizontally if display text is longer than display width. The display cannot scroll vertically so if you configure five lines on a four line display the fifth line will not show. If there is no value for an Infolabel the line on the LCD/VFD display will be empty and the next line is displayed to avoid empty lines on the display. The file also contains display properties, e.g.

* `<disableonplay>video</disableonplay>` disables the display during video playback
* `<disableonplay>music</disableonplay>` disables the display during music playback
* `<disableonplay>video,music</disableonplay>` disables the display for video and music

For example, the following configuration:

```
<Music>
  <line>$INFO[[LCD.PlayIcon]] $INFO[[Player.Time]]/$INFO[[Player.Duration]]</line>
  <line>$INFO[[MusicPlayer.Title]]</line>
  <line>$INFO[[MusicPlayer.Artist]]</line>
  <line>$INFO[[MusicPlayer.Album]] ($INFO[[MusicPlayer.Year]])</line>
</Music>
```

Will output on the display like this:

```
> 00:42/3:20
Gold Digger
Kanye West feat. Jamie Foxx
Late Registration (2005)
```

Please see [Infolabels](https://kodi.wiki/view/InfoLabels) and [Line Tags](https://kodi.wiki/view/Label_Parsing) for more info on how Kodi processes the `<line>` items. The `$LOCALIZE[[ID]]` variable does a lookup in the [Language File](https://github.com/xbmc/xbmc/blob/master/language/English/strings.po|strings.po) and displays the text corresponding to the `[[ID]]` on the LCD/VDF display.

## LCD InfoLabels

In addition to normal InfoLabels, LCD InfoLabels display values without additional text. This helps configuration display more information in one line at the same time and to avoid scrolling of the specified line.

| LCD Infolabel                                  | Function                                                                               |
| ---------------------------------------------- | -------------------------------------------------------------------------------------- |
| LCD.PlayIcon                                   | Displays the Play / Stop / Pause / FF / REW Icon                                       |
| LCD.ProgressBar                                | Displays a progress bar of the currently played item                                   |
| LCD.CPUTemperature                             | Displays the CPU temperature value with no extra text                                  |
| LCD.GPUTemperature                             | Displays the GPU temperature value with no extra text                                  |
| LCD.HDDTemperature                             | Displays the HDD temperature value with no extra text                                  |
| LCD.FanSpeed                                   | Displays the Fan Speed value with no extra text                                        |
| LCD.Date                                       | Displays the current Date with no additional text                                      |
| LCD.FreeSpace(Drive)                           | Displays the value for remaining free space on Drive (C/E/F/G) with no additional text |
| LCD.Time21, LCD.Time22                         | Displays the time in 2×1 sized characters                                              |
| LCD.TimeWide21, LCD.TimeWide22                 | Displays the time in 2×2 sized characters                                              |
| LCD.Time41, LCD.Time42, LCD.Time43, LCD.Time44 | Displays the time in 4×3 sized characters                                              |

The `LCD.Time` InfoLabels can be displayed while Kodi is in screensaver mode or if the visualisation is started by the screensaver. In all other cases the play and progress icons are shown, which may give unexpected results.


# Network Boot

PXE booting with `SYSTEM` and `/storage` mounted via NFS is supported on Generic x86\_64 and current Raspberry Pi devices (Pi 4 and newer).  Older Raspberry Pi devices can also be booted over the network, but they require a different procedure. In the following writeup the server is Ubuntu 18.04 LTS.

## Server (Ubuntu)

In Ubuntu we need to install and configure DHCP, TFTP, and NFS services:

```
sudo apt install isc-dhcp-server tftpd-hpa nfs-kernel-server
```

### DHCP

Edit `/etc/dhcp/dhcpd.conf` and change the DHCP `range` if needed. Create entries in the `host` section for your client(s):

```
authoritative;
allow booting;
allow bootp;

ddns-update-style none;

default-lease-time 86400;
max-lease-time 86400;

subnet 192.168.0.0 netmask 255.255.255.0
{
  option subnet-mask 255.255.255.0;
  option broadcast-address 192.168.0.255;
  option domain-name-servers 192.168.0.2, 192.168.0.1;
  option routers 192.168.0.1;

  range 192.168.0.10 192.168.0.200;
  next-server 192.168.0.2;
  filename "/pxelinux.0";

  host <name>
  {
    hardware ethernet 00:0a:0b:0c:0d:0e;
    fixed-address 192.168.0.5;
  }
}
```

Edit `/etc/default/isc-dhcp-server` to set the interface name handling DHCP requests:

```
INTERFACES="eth0"
```

### NFS

Create the directories that will contain your `/storage` userdata and TFTP boot files, e.g.

```
sudo mkdir /mnt/media/storage
sudo mkdir -m777 /mnt/tftpboot
```

Download the LibreELEC image for your device. On x86 systems, copy the `KERNEL` and `SYSTEM` files into the `/mnt/tftpboot` directory:

```
sudo cp KERNEL /mnt/tftpboot
sudo cp SYSTEM /mnt/tftpboot
```

On a Raspberry Pi, just copy all files into the `/mnt/tftpboot` directory:

```
sudo cp * /mnt/tftpboot
```

{% hint style="info" %}
If you want to place the files in a subdirectory it is required to adjust the include directive in `config.txt`.
{% endhint %}

Then add the following lines to the `/etc/exports` file:

```
/mnt/media/storage      192.168.0.2/255.255.255.0(no_root_squash,rw,async,no_subtree_check)
/mnt/tftpboot           192.168.0.2/255.255.255.0(no_root_squash,rw,async,no_subtree_check)
```

### TFTP

Create directories for the TFTP bootfiles. In this example they are served from a different disk:

```
sudo mkdir /mnt/tftpboot/pxelinux.cfg
sudo cp -p /usr/lib/syslinux/pxelinux.0 /mnt/tftpboot
```

You may also want to copy the `KERNEL` and `SYSTEM` files to `/mnt/tftpboot`

Add the following lines to `/etc/default/tftpd-hpa` and save the file:

```
RUN_DAEMON="yes"
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/mnt/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"
```

Create `/mnt/tftpboot/pxelinux.cfg/default` (or instead of default use the MAC-Address of your device in the format `90-91-92-93-94-95`) and insert the following:

```
DEFAULT LibreELEC
PROMPT 0

LABEL LibreELEC
kernel /KERNEL
append ip=dhcp boot=NFS=192.168.0.2:/mnt/tftpboot disk=NFS=192.168.0.2:/mnt/media/storage
```

Replace `192.168.0.1` with the NFS server IP address. The `overlay` parameter is not required if you only intend to boot one system. LibreELEC is now configured to boot using TFTP and NFS!

### NFSv4

Today many server use NFSv4 while the kernel still default to NFSv3. In such a case set the correct NFS dialect via the `vers=` option:

```
  APPEND ip=dhcp boot=NFS=192.168.0.1:/mnt/store/libreelec,vers=4.2 disk=NFS=192.168.0.1:/mnt/store/libreelec/storage,vers=4.2 overlay
```

Valid nfs versions are `2 3 4 4.0 4.1 4.2`.

### Firewall

If using the default Ubuntu firewall (UFW) add the following rules to allow ports for TFTP (69) and ONRPC (111):

```
sudo ufw allow proto udp from 192.168.0.0/24 to any port 69
sudo ufw allow proto tcp from 192.168.0.0/24 to any port 111
```

Clients normally connect to the NFS server on random ports, so it the firewall is active "mountd" needs to be told to use a fixed port allowed through the firewall, or boot will hang.

Edit `/etc/default/nfs-kernel-server` and replace the current `RPCMOUNTDOPTS` line. In the example below `8765` is a randomly chosen port:

```
RPCMOUNTDOPTS="-p 8765"
```

Create a matching firewall rule to allow the port:

```
sudo ufw allow proto tcp from 192.168.0.0/24 to any port 8765
```

### Services

And finally, start services:

```
sudo service isc-dhcp-server start
sudo service nfs-kernel-server start
sudo service tftpd-hpa start
```


# Pulseaudio

Pulseaudio is used for routing audio to a Bluetooth device. With additional configuration it can also be used to receive audio and stream to multi-device (multi-room) configurations.

The tutorials on this page are basically using four commands:

* `pactl load-module <name>` to load a pulseaudio module (not all are loaded by default)
* `pactl set-default-sink` to set the pulseaudio output device
* `pactl set-default-source` to set the pulseaudio input device
* `pactl info` to check the current sink/source configuration

Sample `pactl info` output:

```
LibreELEC:~ # pactl info
Server String: /var/run/pulse/native
Library Protocol Version: 31
Server Protocol Version: 31
Is Local: yes
Client Index: 41
Tile Size: 65472
User Name: root
Host Name: LibreELEC
Server Name: pulseaudio
Default Sample Specification: s16le 2ch 44100Hz
Default Channel Map: front-left,front-right
Default Sink: alsa_output.platform-aml_m8_snd.45.analog-stereo
Default Source: alsa_input.platform-aml_m8_snd.45.analog-stereo
```

## Bluetooth Sending

This is the default configuration. Simply pair a Bluetooth audio device in the LibreELEC settings add-on and change the Kodi output device (in Kodi settings) to Bluetooth Audio.

## Bluetooth Receiving

This allows you to stream Bluetooth audio from a smartphone or other Bluetooth device. Before you start, pair the device in the LibreELEC settings add-on.

Stop Kodi (else it holds onto the audio device):

```
systemctl stop kodi
```

Load the pulseaudio udev module:

```
pactl load-module module-udev-detect
```

List the names of pulseaudio output devices using the `pactl` utility:

```
pactl list short sinks
```

For example:

```
1    alsa_output.platform-aml_m8_snd.45.analog-stereo    module-alsa-card.c    s32le 2ch 44100Hz    SUSPENDED
```

Configure the pulseaudio output device:

```
pactl set-default-sink alsa_output.platform-aml_m8_snd.45.analog-stereo
```

Use `pactl` to find your Bluetooth audio device:

```
pactl list short sources
```

For example:

```
12    bluez_source.B8_53_AC_01_8F_E7    module-bluez5-device.c    s16le 2ch 44100Hz    SUSPENDED
```

Configure the pulseaudio source device:

```
pactl set-default-source bluez_source.B8_53_AC_01_8F_E7
```

Restart Kodi:

```
systemctl start kodi
```

Select the audio output device in Kodi if you want audio from your device, and from playing files in Kodi.

## Network Sending

This requires another computer or device running pulseaudio, e.g. an MPD music player or another LibreELEC device.

On the pulseaudio target device, ensure the `native-protocol-tcp` and `zeroconf-publish` modules are loaded:

```
pactl load-module module-native-protocol-tcp auth-anonymous=1
pactl load-module module-zeroconf-publish
```

On the pulseaudio source (LibreELEC) device, stop Kodi and find the output device:

```
systemctl stop kodi
pactl list short sinks
```

For example:

```
39    module-tunnel-sink    server=[[192.168.1.70]]:4713 sink=alsa_output.pci-0000_00_08.0.analog-stereo format=s16le channels=2 rate=44100 sink_name=tunnel.lukas-macbook-pro.local.alsa_output.pci-0000_00_08.0.analog-stereo channel_map=front-left,front-right
```

On the pulseaudio source, configure the pulseaudio output device:

```
pactl set-default-sink tunnel.lukas-macbook-pro.local.alsa_output.pci-0000_00_08.0.analog-stereo
```

Restart Kodi:

```
systemctl start kodi
```

You can now select the default pulseaudio output device in Kodi settings. Audio will be broadcast on the network and other pulseaudio devices can select it as their audio source.

## Network Receiving

This requires another pulseaudio device in the network, e.g. an MPD player or another LibreELEC device.

Stop Kodi else it will hold onto the audio output device:

```
systemctl stop kodi
```

Load the pulseaudio udev module:

```
pactl load-module module-udev-detect
```

Use `pactl` to list pulseaudio output devices:

```
pactl list short sinks
```

For example:

```
1    alsa_output.platform-aml_m8_snd.45.analog-stereo    module-alsa-card.c    s32le 2ch 44100Hz    SUSPENDED
```

Configure the pulseaudio output device:

```
pactl set-default-sink alsa_output.platform-aml_m8_snd.45.analog-stereo
```

On the source pulseaudio device, load the `native-protocol-tcp` and `zeroconf-discover` modules:

```
pactl load-module module-native-protocol-tcp auth-anonymous=1
pactl load-module module-zeroconf-discover
```

On the target device, use `pactl` to list available input devices:

```
pactl list short sources
```

For example:

```
38    module-tunnel-source    server=[[192.168.1.70]]:4713 source=alsa_input.pci-0000_00_08.0.analog-stereo format=s16le channels=2 rate=44100 source_name=tunnel.lukas-macbook-pro.local.alsa_input.pci-0000_00_08.0.analog-stereo channel_map=front-left,front-right
```

Configure the pulseaudio input device:

```
pactl set-default-source tunnel.lukas-macbook-pro.local.alsa_input.pci-0000_00_08.0.analog-stereo
```

Restart Kodi:

```
systemctl start kodi
```

## Configuration

Custom pulseaudio configuration is stored in `/storage/.config/pulse-daemon.conf.d` as `/etc/pulse` is inside the read-only filesystem. Files must have a `.conf` extension. The file `daemon.conf` is processed first, followed by other files in alphabetical order so if the same option is set in multiple files, the last one to be read will be used. If files have the same name as a default (embedded) file they override (replace) the embedded file.

To make custom configurations persistent, we must override `/etc/pulse/default.pa` which is read on startup. Create `/storage/.config/pulse-daemon.conf.d/custom.conf` and set the following to override the startup script file location:

```
default-script-file = /storage/.config/pulse-daemon.conf.d/custom.pa
```

Now create `/storage/.config/pulse-daemon.conf.d/custom.pa` to extend the default startup script:

```
#!/usr/bin/pulseaudio -nF

.fail
.include /etc/pulse/default.pa

# extend default startup script here e.g.
load-module module-rtp-recv latency_msec=250 sap_address=0.0.0.0
```

## Sample Rates and Resampling

Create `/storage/.config/pulse-daemon.conf.d/custom.conf` with your custom options, e.g.

```
resample-method = soxr-vhq
default-sample-format = s16le
default-sample-rate = 44100
```

To see the available resample methods:

```
pulseaudio --dump-resample-methods
```

For example:

```
trivial
ffmpeg
auto
copy
peaks
soxr-mq
soxr-hq
soxr-vhq
```


# Safe Mode

## Safe Mode

This feature gives users the option to not end up in a Kodi restart loop if something went wrong on the Kodi side and the possibility to fix an existing installation.

### How does it work

If for whatever reason Kodi crashes and therefore created a crashlog more than 5 times in 900 seconds (15 minutes), then we will enter the safe mode. This will avoid that you won't be able to get a running Kodi in any way.

### Behind the scenes

What has happened once you entered the save mode? Pretty simple. Once you end up in safe mode, we did a backup of your existing Kodi installation in a different folder. From a technical point of view we simply renamed the existing (and failing) `/storage/.kodi` folder to `/storage/.kodi.FAILED` and triggered a reboot after that. That will mean your next Kodi start will end up with a vanilla Kodi but with a special red background and a notification screen, that you now have entered the save mode. It will look like this:

![](/files/PFDtlbbpYzBAvnWHjgPN)

### What to do now?

First you should read the infos given from from the notification screen above and also probably make notes if you might think you can't remember them later. Once that is done, you should follow this section which is similar to the "first run wizard" and gives you specific options to either enter a hostname, enable Samba and/or SSH or setting up your network connection like shown in the screenshots below:

![Set up the hostname](/files/ojys0u9FYXlRHSh6xhHW)

![Set up your network](/files/FnKVfya8L7x4PY4k09Ra)

![Enable Samba or SSH](/files/guZW5MERbO5lX5jEX86q)

![Exit the wizard](/files/rEG3qjTyJHa90NF4oYeA)

We recommend to enable both SSH and Samba as this might be necessary to debug why your Kodi ended up in the safe mode at all.

After you ended the wizard all your settings, add-ons, library and what not from the previous (failing) installation are stored inside the `/storage/.kodi.FAILED` folder. This folder can either be accessed by SSH or Samba as we also share this folder by default if it exists. Please read the following if you don't know how to access LibreELEC: Accessing LibreELEC

From now on, if you want to debug why Kodi entered the safe mode, we will completely focus to the `/storage/.kodi.FAILED` folder which contains all the necessary information we might need to see what happened.

So for providing the logfile via SSH use the following command:

`pastebinit /storage/.kodi.FAILED/temp/kodi.log`

or search via Samba for the ''Kodi-Failed'' folder and enter the ''temp''-subfolder to get the ''kodi.log'' logfile.

For the very best option, we recommend to use the log uploader option we built-in in LibreELEC.

### After debugging or fixing

After we might have found out what the problem might have caused and we also might have fixed it, you don't need to do anything else beside rebooting your machine. We will automatically restore the old (and probably fixed) installation and at the next boot you will directly boot into Kodi like you are used to.

Be aware, that if we haven't fixed anything, that you will again enter the safe mode to be able to fix your installation if Kodi crashes multiple times again.

### How to disable safe mode

Safe mode can be completely disabled using a flag file `/storage/.config/safemode.disable` .

Login via SSH and type `touch /storage/.config/safemode.disable`

### How to fix a broken add-on

As Kodi don't provide any help you have to manually remove the addon.

Login via SSH and type `rm -rf /storage/.kodi.FAILED/addons/addon.name`


# Samba

The embedded Samba server in LibreELEC is enabled by default and provides CIFS/SMB shares that can be accessed from all modern OS to [Add content via Samba Shares](/how-to/add-content-via-samba-shares) or collect [Log Files](/support/log-files) for support or access the `/storage/.config` folder to make basic system changes. Samba starts with configuration from `/storage/.config/samba.conf` if it exists, else it starts with a default configuration from `/etc/samba/smb.conf`  which is inside the read-only filesystem.&#x20;

Samba services can be disabled from the LibreELEC settings addon.

{% hint style="warning" %}
Samba **server** configuration files do not configure the SMB **client** within Kodi
{% endhint %}

## Removable Media

The OS automatically creates Samba shares for removable media devices like external USB drives that are connected at boot time. Share names are based on the disk label, e.g. `/var/media/MyBook` will result in the `\\LIBREELEC\MYBOOK` share being auto-created. If your disk does not have a label and has mounted using a hardware identifier, e.g. `/var/media/sda1-ata-KINGSTON_SNV2S20` the best and correct way to change the share name is setting a label:

```
# e2label /dev/sda1 "KINGSTON"
```

This will result in the auto-created SMB share `\\LIBREELEC\KINGSTON`  which will be persistent.

{% hint style="danger" %}
Users often workaround unlabeled disks and resulting weird share names by creating custom shares. This works if you have one disk. If you have more than one disk boot time probe order is not guaranteed so `/var/media/sda1-blah` can change to `/var/media/sdb1-blah` breaking the shares. Using `e2label`is the better solution.
{% endhint %}

## Custom Shares

Rename `/storage/.config/samba.conf.sample`  to `/storage/.config/samba.conf` then edit `samba.conf` to make changes to the `[global]`section or add/remove shares, then reboot to restart the OS with the new Samba configuration. The format is simple to crib from the sample file, e.g. to add a new \[Addons] share, append this to the conf:

```
[Addons]
  path = /storage/.kodi/addons
  available = yes
  browseable = yes
  public = yes
  writeable = yes
```

To remove a share from the default list, comment it out, e.g. to remove `[Emulators]` change the conf file to look like this, then restart:

```
  public = yes
  writeable = yes

#[Emulators]
#  path = /storage/emulators
#  available = yes
#  browseable = yes
#  public = yes
#  writeable = yes

[Configfiles]
  path = /storage/.config
  available = yes
```

{% hint style="info" %}
For more information on Samba server configuration options please refer to the official reference guide here: <https://www.samba.org/samba/docs/4.9/man-html/smb.conf.5.html>
{% endhint %}

## Time Machine&#x20;

Samba can serve SMB shares compatible with Apple's [Time Machine](https://support.apple.com/en-ae/104984) backup snapshot functionality in macOS. Time Machine capabilities are not enabled by default and require a custom `samba.conf` (as explained above) with the following options appended to the `[global]`section:

```
# samba TimeMachine support
  min protocol = SMB2
  ea support = yes
  vfs objects = catia fruit streams_xattr
  delete veto files = true
  fruit:metadata = stream
  fruit:veto_appledouble = no
  fruit:nfs_aces = no
  fruit:posix_rename = yes
  fruit:zero_file_id = yes
  fruit:wipe_intentionally_left_blank_rfork = yes
  fruit:delete_empty_adfiles = yes
```

Note that `fruit:model = Xserve` is already defined in the default configuration. Some users prefer the appearance of the `fruit:model = MacSamba`  icon for their shares.

Next add/append a `TimeMachine` share to the configuration file:

```
[TimeMachine]
  path = /storage/timemachine/
  fruit:time machine = yes
  # fruit:time machine max size = 250GB
  read only = no
  guest ok = yes
```

Time Machine provides a roll-up strategy for snapshots to reduce disk consumption, but you can force a specific space quota/restriction by uncommenting `fruit:time machine max size` and setting the size value. In the example above max size has been set to 250GB.

{% hint style="info" %}
see <https://wiki.samba.org/index.php/Configure_Samba_to_Work_Better_with_Mac_OS_X> for more information about macOS coexistence configuration and features.
{% endhint %}


# SSL/TLS Certificates

## cacert.pem

If you run LibreELEC behind an inline proxy that intercepts TLS communications or access content from an TLS encrypted source that requires a self-signed certificate to be trusted, you need to add the private CA certificate to the OS trust chain.

This is done by creating `/storage/.config/cacert.pem` with the private CA certificate details and rebooting. On restart the `ssl-config` systemd service will append the private certificate to the OS default certificate file to create a combined file `/run/libreelec/cacert.pem` which is the symlink target for `/etc/ssl/cacert.pem` referenced by Kodi, curl, etc.


# Startup & Shutdown

## autostart.sh

The `autostart.sh` script runs at the start of userspace boot. It can be used to run commands before Kodi starts. It does not exist by default, but you can create it using nano.

```
nano /storage/.config/autostart.sh
```

You can place any commands in the script, but note they will block the boot process until they complete, so most uses of `autostart.sh` require you to "background" and delay the commands, e.g. the following script sleeps for 20 seconds and then runs a `kodi-send` command to update the video library.

```
(
 sleep 20
 kodi-send --host=127.0.0.1 -a "UpdateLibrary(video)"
)&
```

The network stack will be up when the script runs.

## autostop.sh

The `autostop.sh` script runs during the shutdown process, but before the network is shutdown. It does not exist by default, but you can create it using nano.

```
nano /storage/.config/autostop.sh
```

Like the `autostart.sh` script you can place any commands in the script, and they will block the shutdown process for up to 5 minutes and then will be terminated automatically.

`autostop.sh` is available as of LibreELEC 10.0.2 or LibreELEC 11 nightlies 2022-02-04.

## shutdown.sh

The `shutdown.sh` script run during the shutdown process. It does not exist by default, but you can create it using nano.

```
nano /storage/.config/shutdown.sh
```

Unlike the `autostart.sh` script the network stack will not be up when the script runs and the `shutdown.sh` script should follow the following template to ensure commands are executed during the correct event, i.e. you can run different commands for a `reboot` event to `halt` event, or put commands outside the `case ... esac` as a catch-all.

```
case "$1" in
  halt)
    # your commands here
    ;;
  poweroff)
    # your commands here
    ;;
  reboot)
    # your commands here
    ;;
esac
# your commands here
```


# Tailscale

Tailscale is a zero-config VPN built on top of the WireGuard protocol. It creates a secure, private mesh network, a.k.a "tailnet" that connects devices directly to each other. You can connect your devices into an existing tailnet by installing the Tailscale Service add-on from the add-on repo.

### Connecting

After installing the Tailscale add-on, SSH into the device and bring tailscale up:

```
tailscale up
```

The output will display a URL that you can use to authenticate to your Tailscale network (known as a tailnet). After you authenticate, check the Machines page of the admin console to confirm the device appears in your tailnet.

### Configuration

Once the node has been added to your tailnet it can be configured. Follow Add-ons > My Add-ons > Services > Tailscale > Configure to open the configuration options.

* **Enable** allows you to manually enable (default) or disable the service.
* **Auto-generate name from OS hostname** is enabled by default and the OS hostname will be used as the node name in the tailnet. Disable this to manually specify another node name.
* **Accept routes** allows the node to accept routes published by other nodes in the tailnet.
* **Use exit node** instructs Tailscale to route all traffic through a tailnet exit node. Enabling this option will disable the option to configure the local node as an exit node.
  * **Select exit node** queries the tailnet for available exit nodes to make population of the exit node address easier.
  * **Exit node address** is the IP of the tailnet exit node to use; configured manually or (easier) by selecting an exit node
* **Advertise exit node** allows the local node to access traffic from other nodes and route that traffic to the internet. This option is hidden when 'Use exit node' is enabled.
  * **Allow LAN access** allows local LAN access when the local node is configured as an exit node. If this is disabled the exit node cannot act as a subnet router for the local subnet and will only route traffic to the internet

### Routing

Tailscale uses its own routing table (normally table `52`) with a `0.0.0.0/0` default route that points at `tailscale0` when you use an exit node, and an `ip rule` (normally `pref 5270: from all lookup 52`) that gets evaluated *before* your main table lookup (`pref 32766`). Routing traffic through exit nodes can cause problems accessing devices in the same subnet, as *all traffic* is routed. To have the node connect to e.g. a local NAS server with media, or an external server/service that should use the local internet connection instead of routing via the exit node, a routing exception must be made.

Check your actual rule setup first:

```
ip rule show
ip route show table 52
```

You'll likely see something like:

```
5210: from all fwmark 0x80000/0xff0000 lookup main
5230: from all fwmark 0x80000/0xff0000 lookup default
5250: from all fwmark 0x80000/0xff0000 unreachable
5270: from all lookup 52
32766: from all lookup main
```

To exempt local traffic from being routed through the tailnet you must add an ip rule *before* table 52, e.g. to route traffic to `95.217.22.250/32` we add *ip rule* `5269` *before* tailscale on `5270` :

```
ip rule add to 95.217.22.250/32 lookup main priority 5269
```

Then we add an *ip route* that sends traffic over the local `eth0` interface:

```
ip route add 95.217.22.250/32 via 172.16.20.1 dev eth0
```

Rule and route changes are not persistent over reboot. To make them persistent you will need to create and enable a simple one-shot systemd service to execute commands *after* the tailscale service is started.

Create the service in `/storage/.config/system.d/tailscale-routes.service` and then enable the service with `systemctl enable /storage/.config/system.d/tailscale-routes.service` . Below is an example of a simple one-shot systemd service:

```
[Unit]
Description=Tailscale Routing Service
After=network-online.target time-sync.target tailscale.service
Wants=network-online.target time-sync.target tailscale.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/sbin/ip rule add to 95.217.22.250/32 lookup main priority 5269
ExecStart=/usr/sbin/ip route add 95.217.22.250/32 via 192.168.0.1 dev eth0

[Install]
WantedBy=multi-user.target
```


# Useful Scripts

## Prevent Idle Shutdown

This script uses the `kodi-send` tool to prevent Kodi from shutting down if there are active SSH, SAMBA, or NFS connections. The script checks every 60 seconds, and if at least one connection exists the command `InhibitIdleShutdown(true)` is sent to Kodi.

Create `/storage/.config/prevent_idle.sh` with the following content:

```bash
#!/bin/sh

IDLE_SHUTDOWN_ALLOWED_LAST_STATE=-1

while true
do
  KODI_RUNNING=`ps -A | grep kodi.bin | grep -v grep | wc -l`
  if [ 1 == $KODI_RUNNING ] ; then
    SSH_ACTIVE=`netstat -tnpa | grep 'tcp.*:22.*ESTABLISHED.*' | wc -l`
    NFS_ACTIVE=`netstat -tnpa | grep 'tcp.*:111.*ESTABLISHED.*' | wc -l`
    SMB_ACTIVE=`netstat -tnpa | grep 'tcp.*:445.*ESTABLISHED.*' | wc -l`  
    [ $SSH_ACTIVE -gt 0 -o $NFS_ACTIVE -gt 0 -o $SMB_ACTIVE -gt 0 ] && IDLE_SHUTDOWN_ALLOWED=1 || IDLE_SHUTDOWN_ALLOWED=0 
      if [ $IDLE_SHUTDOWN_ALLOWED_LAST_STATE != $IDLE_SHUTDOWN_ALLOWED ] ; then
        IDLE_SHUTDOWN_ALLOWED_LAST_STATE=$IDLE_SHUTDOWN_ALLOWED
        kodi-send --action="AllowIdleShutdown"
        if [ 0 == $IDLE_SHUTDOWN_ALLOWED ] ; then
          kodi-send --action="InhibitIdleShutdown(false)"
        else
          kodi-send --action="InhibitIdleShutdown(true)"
        fi
      fi
  fi
  sleep 60
done
```

Call the script from `/storage/.config/autostart.sh` so it runs as a background task. It will continue to monitor the state of connections until the device is halted.

```bash
(
/usr/bin/bash /storage/.config/prevent_idle.sh
)&
```

## DYNU IP Updater

This script identifies your public IP address and updates a <https://dynu.com> Dynamic DNS record.

Create `/storage/.config/dynu_update.sh` with the following content:

```bash
#!/bin/sh

DYNU_USERNAME="username"
DYNU_PASSWORD="password-hash"
DYNU_HOSTNAME="example.dynu.com"
REFRESH_RATE=60

PUBLIC_IP=0.0.0.0

test_ip ()
{
  if [ -n $2 ] ; then
    if [ $1 != $2 ] ; then
      update_ip $2
      echo $2
    else 
      echo $1
    fi
  fi
}

update_ip ()
{
  DYNU_WGET="https://api.dynu.com/nic/update?hostname=$DYNU_HOSTNAME&myip=$1&username=$DYNU_USERNAME&password=$DYNU_PASSWORD"
  DYNU_UPDATE=`wget $DYNU_WGET -O - -q ; echo`
  (>&2 echo "$DYNU_UPDATE")
}

while true; do
  PUBLIC_IP_TEST=`wget http://ipecho.net/plain -O - -q ; echo`
  echo $PUBLIC_IP - $PUBLIC_IP_TEST
  PUBLIC_IP="$(test_ip $PUBLIC_IP $PUBLIC_IP_TEST)"
  sleep $(REFRESH_RATE)
  PUBLIC_IP_TEST=`curl -s checkip.dyndns.org | sed 's#.*Address: \(.*\)</b.*#\1#'`
  echo $PUBLIC_IP - $PUBLIC_IP_TEST
  sleep $(REFRESH_RATE)
  PUBLIC_IP_TEST=`curl -s ifconfig.co`
  echo $PUBLIC_IP - $PUBLIC_IP_TEST
  PUBLIC_IP="$(test_ip $PUBLIC_IP $PUBLIC_IP_TEST)"
  sleep $(REFRESH_RATE)
done
```

Call the script from `/storage/.config/autostart.sh` so it runs as a background task. It will continue to monitor the state of connections until the device is halted.

```bash
(
/usr/bin/bash /storage/.config/dynu_update.sh
)&
```

Note: If you set the refresh rate under 60 seconds the `checkip.dyndns.org` server will probably block your requests causing the script to fail.


# WireGuard

LibreELEC can be configured as a WireGuard VPN client allowing you to accessing media in a remote location or tunnel traffic to avoid local inspection of network activity. This guide assumes configuration of a single WireGuard tunnel that is persistent, i.e. activated on device boot so that Kodi network traffic is routed through the WireGuard VPN tunnel.

WireGuard tunnels are managed by a ConnMan VPN plugin (connman-vpn.service) that acts as a companion to the network connection manager daemon (connman.service). The VPN plugin watches `/storage/.config/wireguard/*.config` and defines ConnMan services from auto-discovered configuration files. Once a valid WireGuard .config has been imported it can be connected manually using `connmanctl` from the SSH console or scripted from a systemd service that runs on boot. Connections can also be managed using the network 'Connections' tab in the LibreELEC settings add-on which controls ConnMan via d-bus.

## Sample Config

ConnMan uses its own configuration file format (see below) so you cannot import/use the files exported from WireGuard server tools and third-party VPN services - the format is different. Those files will contain everything you need, but you must manually transpose the information into the ConnMan format:

```
[provider_wireguard]
Type = WireGuard
Name = WireGuard (Home)
Host = 185.210.30.121
WireGuard.Address = 10.2.0.2/24
WireGuard.ListenPort = 51820
WireGuard.PrivateKey = qKIj010hDdWSjQQyVCnEgthLXusBgm3I6HWrJUaJymc=
WireGuard.PublicKey = zzqUfWGIil6QxrAGz77HE5BGUEdD2PgHYnCg3CDKagE=
WireGuard.PresharedKey = DfEYeVs04HS9XhKGM4/ZXHG3Qc4MFK2AJd8XouYDbRQ=
WireGuard.DNS = 8.8.8.8, 1.1.1.1
WireGuard.AllowedIPs = 0.0.0.0/0
WireGuard.EndpointPort = 51820
WireGuard.PersistentKeepalive = 25
```

Name = AnythingYouLike\
Host = IP of the WireGuard **server** (IP, not FQDN)\
WireGuard.Address = The internal IP of the **client** node, e.g. a /24 address\
WireGuard.ListenPort = The **client** listen port (optional)\
WireGuard.PrivateKey = The **client** private key\
WireGuard.PublicKey = The **server** public key\
WireGuard.PresharedKey = The **server** pre-shared key (optional)\
WireGuard.DNS = Nameserver to be used with the connection (optional)\
WireGuard.AllowedIPs = Subnets accessed via the tunnel, 0.0.0.0/0 is "route all traffic"\
WireGuard.EndpointPort = The **server** ListenPort\
WireGuard.PersistentKeepalive = Periodic keepalive in seconds (optional)

{% hint style="info" %}
Using `WireGuard.PresharedKey` is optional, but if your WireGuard configuration omits this you must remove the line from the config. If you leave it blank it will be seen as active with a null value, causing connections to fail.
{% endhint %}

{% hint style="warning" %}
`Host`must be an IP address not a qualified domain name. If you need to handle a VPN server that has a dynamic not static address, an external script (scheduled via cron or a systemd timer) must be used to detect the IP change, update the .config file used by the ConnMan VPN manager, and restart of the WireGuard connection systemd service.
{% endhint %}

## Creating Keys

If you need to create some, run `wg-keygen` from the SSH console and `/storage/.cache/wireguard` will contain new publickey, privatekey, and preshared files with keys inside. Most users will not need to generate WireGuard keys as they will be in the configuration file provided by a VPN service provider.

## Testing Connections

Once you have saved a configuration file, check it is valid:

```
RPi4:~ # connmanctl services
* R home              vpn_185_210_30_121
*AO Wired             ethernet_dca622135939_cable
```

In the above example `vpn_185_210_30_121` was created (vpn\_host) as the ConnMan service name. Test the service will connect using:

```
RPi4:~ # connmanctl connect vpn_185_210_30_121
```

ConnMan will create a new network interface, so `ifconfig` will show `wg0` or sometimes a higher number like `wg1` or `wg2`:

```
RPi4:~ # ifconfig
eth0      Link encap:Ethernet  HWaddr DC:A6:32:13:26:3b  
          inet addr:192.168.10.25  Bcast:192.168.10.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3136938 errors:0 dropped:40816 overruns:0 frame:0
          TX packets:242506 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:310409413 (296.0 MiB)  TX bytes:22433323 (21.3 MiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:6109 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6109 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:415013 (405.2 KiB)  TX bytes:415013 (405.2 KiB)

wg0       Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
          inet addr:10.2.0.2  P-t-P:10.2.0.2  Mask:255.255.255.0
          UP POINTOPOINT RUNNING NOARP  MTU:1420  Metric:1
          RX packets:13744 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11080 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:13775220 (13.1 MiB)  TX bytes:1232552 (1.1 MiB)
```

You should be able to `ping` the remote (server) side of the WireGuard VPN tunnel. In our example this is 10.2.0.1:

```
RPi4:~ # ping 10.2.0.1
PING 10.2.0.1 (10.2.0.1): 56 data bytes
64 bytes from 10.2.0.1: seq=0 ttl=64 time=147.936 ms
64 bytes from 10.2.0.1: seq=1 ttl=64 time=147.955 ms
```

The routing table will show normal traffic routed to the wg0 interface:

```
RPi4:~ # route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         *               0.0.0.0         U     0      0        0 wg0
1.1.1.1         *               255.255.255.255 UH    0      0        0 wg0
8.8.8.8         *               255.255.255.255 UH    0      0        0 wg0
10.2.0.0        *               255.255.255.0   U     0      0        0 wg0
192.168.10.0    *               255.255.255.0   U     0      0        0 eth0
192.168.10.1    *               255.255.255.255 UH    0      0        0 eth0
185.210.30.121  192.168.10.1    255.255.255.255 UGH   0      0        0 eth0
```

To disconnect the ConnMan service:

```
RPi4:~ # connmanctl disconnect vpn_185_210_30_121
```

Check `ifconfig` again and the WireGuard interface will be gone.

## Configuring Systemd

Create a systemd wireguard.service file to start the connection automatically on boot, after the network starts, and before Kodi is launched. The sample wireguard.service file looks like:

```
[Unit]
Description=WireGuard VPN Service
After=network-online.target nss-lookup.target wait-time-sync.service connman-vpn.service
Before=kodi.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/connmanctl connect vpn_service_name_goes_here
ExecStop=/usr/bin/connmanctl disconnect vpn_service_name_goes_here

[Install]
WantedBy=multi-user.target
```

Copy the sample wireguard.service file to `/storage/.config/system.d/wireguard.service`

```
cp /storage/.config/system.d/wireguard.service.sample /storage/.config/system.d/wireguard.service
```

Replace **vpn\_service\_name\_goes\_here** with your service name, e.g. `vpn_185_210_30_121` using nano. Use `ctrl+o` to save changes and `ctrl+x` to exit nano:

```
nano /storage/.config/system.d/wireguard.service
```

Now we can enable and start the service:

```
RPi4:~ # systemctl enable /storage/.config/system.d/wireguard.service
Created symlink /storage/.config/system.d/multi-user.target.wants/wireguard.service → /storage/.config/system.d/wireguard.service.
RPi4:~ # systemctl start wireguard.service
```

Check the WireGuard tunnel is active using "ifconfig" and "ping" and if all is good, reboot to test the WireGuard tunnel comes up automatically on boot.

## WireGuard Routing

ConnMan configures wg0 to route all traffic over the WireGuard tunnel by default, no matter what `WireGuard.AllowedIPs` configuration is set. To route only specific networks via the tunnel the ConnMan service order (which influences routing order) must be changed.

In the example below note the`sleep` and `connmanctl move-after` and `route add` commands used in the following tweaked systemd service file:

```
[Unit]
Description=WireGuard VPN Service
After=network-online.target nss-lookup.target wait-time-sync.service connman-vpn.service
Before=kodi.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/sleep 5
ExecStart=/usr/bin/connmanctl connect vpn_service_name
ExecStartPost=/usr/bin/connmanctl move-after vpn_service_name ethernet_b827eb10c45a_cable
ExecStartPost=/usr/bin/connmanctl move-after vpn_service_name ethernet_b827eb10c45a_cable
ExecStartPost=/usr/sbin/route add -net 192.168.2.0 netmask 255.255.255.0 gw 10.0.0.2
ExecStartPost=/usr/sbin/route add 64.109.130.11/32 via 192.168.0.1 dev eth0
ExecStop=/usr/bin/connmanctl disconnect vpn_service_name

[Install]
WantedBy=multi-user.target
```

The following forum thread has tips and examples: <https://forum.libreelec.tv/thread/21906-wireguard-changes-the-default-route-although-not-configured/>

## Thanks

Big thanks! to ConnMan maintainer Daniel Wagner (wagi) who worked with LibreELEC staff to implement WireGuard support in ConnMan (he wrote the code, we ~~abused~~ tested it).


# Add Firmware

Linux kernel firmware files are normally installed in `/usr/lib/firmware` but in LibreELEC this directory is inside the read-only `SYSTEM` file preventing you from adding files. To allow user changes we support overlays. Copy firmware files and subfolders to `/storage/.config/firmware` and reboot. On boot the folders/files will be overlaid onto `/usr/lib/firmware` where kernel drivers expect to see them.

### Example

The following text from `dmesg` shows the kernel failing to load `rtl8761a_config.bin`which is needed for a Bluetooth device to work:

```
[    8.641489] Bluetooth: hci0: RTL: rtl: loading rtl_bt/rtl8761a_fw.bin
[    9.241371] bluetooth hci0: Direct firmware load for rtl_bt/rtl8761a_fw.bin failed with error -2
```

This can be fixed by creating the overlay directories and downloading the missing firmware file from the linux-firmware repository, then rebooting.

```
mkdir -p /storage/.config/firmware/rtl_bt
cd /storage/.config/firmware/rtl_bt
wget https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/rtl_bt/rtl8761a_fw.bin
Connecting to git.kernel.org (136.144.49.103:443)
saving to 'rtl8761a_fw.bin'
rtl8761a_fw.bin      100% |**********************************| 74488  0:00:00 ETA
'rtl8761a_fw.bin' saved
reboot
```

Firmware files can also be copied via the local Samba/SMB shares, as shown below:

![](/files/-MMbVrEyVMocH21wjYB6)


# Blacklist Kernel Module

In most Linux distros modules are blacklisted by creating `/etc/modprobe.d/blacklist.conf` which contains the name of the module. In LibreELEC `/etc` is inside the read-only `SYSTEM` file so we provide an alternate location `/storage/.config/modprobe.d` which is overlaid onto the normal `/etc` location during boot.

### Example&#x20;

To blacklist the `rc-pinnacle-pctv-hd` module. Login to your LibreELEC box using SSH and confirm the module is loaded:

```
lsmod
```

If the module is loaded, append the module name to `blacklist.conf`:

```
echo "blacklist rc-pinnacle-pctv-hd" >> /storage/.config/modprobe.d/blacklist.conf
```

Now reboot to effect the change.

### Module vs Driver

This approach to blacklisting only works with modules that are compiled with `=m` to create an independent module; meaning they are loaded via modprobe. If the module has been compiled directly into the kernel with `=y` modprobe is not used and this method has no effect. Drivers that are compiled-in are normally controlled via kernel boot params.


# Change Bootsplash

LibreELEC displays the project logo as a background "splash" screen during boot. This can be changed to your own image by placing `oemsplash.png` in the boot partition.

Copy your splash image to the Downloads folder, then SSH into your LibreELEC box. Next we must remount the boot partition in read-write mode so we can make changes:

```
mount -o remount,rw /flash
```

Copy your splash image to the boot partition, renaming it to `oemsplash.png`

```
cp /storage/downloads/yoursplash.png /flash/oemsplash.png
```

Remount the boot partition in read-only mode:

```
mount -o remount,ro /flash
```

On reboot you should see the new bootsplash.

### Splash Image Requirements

Splash images must be a 32-bit png files with 1920 x 1080, 1280 x 720, or 1024 x 768 pixel dimensions. Images will be upscaled to the active display resolution, so it is best to use the largest resolution (but not 4k, as most boot firmware does not support 4k output). Most OS image editors do not support 32-bit png export, so we recommend the excellent and open-source [GIMP](https://www.gimp.org) editor for making boot splashes.


# Force Add-on Update

To force-update an add-on repository:

1. Kodi&#x20;
2. Add-ons
3. Box icon
4. left arrow for the side menu
5. Check for updates
6. the date at the bottom should change to the current time

![](/files/-MMbgexOeDFv71-uygWq)


# Add content via Samba Shares

LibreELEC configures a set of default Samba (SMB) shares, which you can use to copy content to and from your system.

The default shares are listed in the `/storage/.config/samba.conf.sample` file, and if you want to modify the default shares, you can do that too!

### Accessing the Shares

On a Mac, while you're in Finder, select Go > Connect to Server..., the click 'Browse' and find the LIBREELEC server (the name of the server corresponds to the name you set in Kodi's settings). Alternatively, don't click 'Browse', just type in `smb://LIBREELEC/` and press Enter.

On Windows, in Explorer, type in `\\LIBREELEC` and press Enter, and you should see a list of all the shares.

If you are prompted for a password, you should be able to log in as a 'Guest' instead, and have full access to the files on any of the shares.

Copy files into the shares as needed, and in Kodi's UI, you can [Add Video Sources](https://kodi.wiki/view/Adding_video_sources) that include the media you've copied across.

### Modifying the Default Shares

You can either create a fresh Samba config file, or copy the sample file and modify it to your liking:

```
cp /storage/.config/samba.conf.sample /storage/.config/samba.conf
```

After modifying the shares, restart Samba:

```
systemctl restart smbd
```

...or just reboot, and the new settings should take effect after a restart.

The sample configuration file is recreated on every reboot, so you should not modify that file. Because that file changes over time, you can also create your own `samba.conf` file, and [`include` the sample file inline](https://www.samba.org/samba/docs/current/man-html/smb.conf.5.html#idm4527).


# Mount Network Share

Kodi can natively mount SMB, NFS, SFTP, WebDAV (and more) remote filesystems (shares) to read media for playback, but many applications that write content, e.g. TVHeadend storing TV recordings, must write to "local" storage. Remote SMB and NFS shares can be "mounted" to the local filesystem using kernel mounts configured through systemd .mount files.

The following NAS configuration is used in the examples below:

* NAS IP: `192.168.1.222`
* Username: `nasuser1`
* Password: `123nas`
* Share name: `recordings`
* Full address to share: `\\192.168.1.222\recordings`

## SMB Shares

#### 1. Create the folder where the share should be mounted

Connect to your LibreELEC HTPC with SSH.

`mkdir /storage/recordings`

#### 2. Create the systemd .mount file

**IMPORTANT:** The filename uses hyphens to separate elements of the filesystem path to the share mount-point, e.g. `/storage/recordings` will be `storage-recordings.mount` and sub folders, e.g. `/storage/recordings/tv` would be `storage-recordings-tv.mount`

Create the .mount file:

`nano /storage/.config/system.d/storage-recordings.mount`

Below is an example of the mount definition file for a Samba share:

```
[Unit]
Description=cifs mount script
Requires=network-online.service
After=network-online.service
Before=kodi.service

[Mount]
What=//192.168.1.222/recordings
Where=/storage/recordings
Options=username=nasuser1,password=123nas,rw,vers=2.1
Type=cifs

[Install]
WantedBy=multi-user.target
```

#### 3. Things to edit

Address of your share. Remember to always use / slashes:

`What=//192.168.1.222/recordings`

Path where the Share should be mounted:

`Where=/storage/recordings`

Options:

`Options=username=nasuser1,password=123nas,rw,vers=2.1`

`username=` Username of your network share\
`password` Password of your network share\
`rw` Read/write access\
`vers=2.1` Version of the Samba protocol, `2.1` is supported since Windows 7 several [other versions](https://wiki.samba.org/index.php/Samba3/SMB2#Introduction) are supported too

#### 4. Enable the mount

Finally we need to enable the mountpoint.

`systemctl enable storage-recordings.mount`

#### 5. Reboot

Reboot your system to check if the mount works.

#### 6. Helpful command for troubleshooting

Get status and error messages from the mount point:

`systemctl status storage-recordings.mount`

Remove mount point and disable it:

`systemctl disable storage-recordings.mount`

## NFS Shares

#### 1. Create the folder where the share should be mounted

Connect to your LibreELEC HTPC [with SSH](https://app.gitbook.com/accessing_libreelec).

`mkdir /storage/recordings`

#### 2. Create the systemd definition file

**Important:** you need to set the filename for the definition file according to the folder where you want to mount your share . In our case: `storage-recordings.mount` represents the path -> `/storage/recordings`. If you add a subfolder: `storage-recordings-tv.mount` represents the path -> `/storage/recordings/tv`.

`nano /storage/.config/system.d/storage-recordings.mount`

Contents of the definition file for a NFS share:

```
[Unit]
Description=test nfs mount script
Requires=network-online.service
After=network-online.service
Before=kodi.service

[Mount]
What=192.168.1.222:/usr/data2/video
Where=/storage/recordings
Options=
Type=nfs

[Install]
WantedBy=multi-user.target
```

#### 3. Things to edit

Address of your share;

`What=192.168.1.222:/usr/data2/video`

Path where the share should be mounted:

`Where=/storage/recordings`

Options: At this section you are able to define specific NFS options, such as the NFS version. In the example below we set Type for an NFSv3 share.

`Type=nfs`

To use an NFSv4 share:

`Type=nfs4`

#### 4. Start it for a test

`systemctl start storage-recordings.mount`

Note: That's only a test and the mount won't be available after a reboot. To make it available after boot you have to "enable" the service first.

#### 5. Enable the mount

If the previous test worked, enable the service via:

`systemctl enable storage-recordings.mount`

#### 6. Reboot

Reboot your system to see if the mount is available after boot.

#### 7. Helpful commands for troubleshooting

Get status and error messages from the mount point:

`systemctl status storage-recordings.mount`

Remove mount point and disable it:

`systemctl disable storage-recordings.mount`

## **Apple TimeCapsule**

TimeCapsule devices share files using an Apple dialect of SMB that is not compatible with the Samba `smbclient` Kodi uses to connect to SMB shares. To access media on a TimeCapsule you can follow the steps described above for connecting to Samba shares with a systemd storage mount, but with one difference: the `Options` configuration must force SMB v1.0 and legacy NTLM authentication or the mount will fail. See below:

```
Options=username=MyUser,password=MyPass,sec=ntlm,vers=1.0
```

SMB v1.0 is widely considered to be insecure, but TimeCapsules no longer receive software updates and there is no alternative; SMB v2/v3 are not supported.

## Auto Mounting

In some edge cases where the remote filesystem may be unavailable when LibreElec boots or the remote filesystem has a chance of disconnecting, an automount is an easy way to mount without the risk of failure and with the option to attempt to connect/reconnect with no extra effort.

It is basically a safe way to retry mounting the remote filesystem.

### How it works

Because we enable the automount service, we can disable the mount service. Which in turn allows the system to boot without errors, even if the network share is not available (it will still show the files as missing until the share is available, but this is expected). What the automount does is try to connect to the network share when the local mount path is accessed by the filesystem. So when trying to play media from the mount path, or trying to update the library (assuming the mount path is in your media library).

#### 1. Create the folder and systemd `.mount` definition file

Follow the relevant instructions above to create a systemd `.mount` definition file for your network share.

**IMPORTANT:** It is recommended to follow the instructions above completely and add the mounted path to your library in Kodi before proceeding with the instructions below.

#### 2. Disable the mount service in systemd

If you've already enabled the mount service in systemd, disable it to prevent errors on boot when the network share is unavailable.

`systemctl disable storage-recordings.mount`

#### 3. Create a systemd `.automount` definition file

Filename restrictions are the same as for the `.mount` definition file. Meaning that if your `.mount` file is named `storage-recordings.mount` your automount file should be named `storage-recordings.automount`.

`nano /storage/.config/system.d/storage-recordings.automount`

Contents of the automount definition file:

```
[Unit]
Description=test automount for recordings

[Automount]
Where=/storage/recordings
TimeoutIdleSec=0

[Install]
WantedBy=multi-user.target
```

#### 4. Things to edit

Path of the mount in question:

`Where=/storage/recordings`

Idle timeout (time before systemd should unmount the network share, 0 means disabled):

`TimeoutIdleSec=0`

#### 5. Enable the automount service

`systemctl enable storage-recordings.automount`

#### 6. Reload systemd to apply changes

`systemctl daemon-reload`

#### 7. Test the automount

If you have already added the mount path to your library in Kodi, you can test the automount by trying to access the folder inside Kodi. If all went well, the network share will mount as soon as you attempt to access it's mount path.

If the network share is available when LibreElec is starting up, it will be mounted during the boot process.

#### 8. Helpful commands for troubleshooting

Get status and error messages from the automount (great for seeing when a mount was attempted):

`systemctl status storage-recordings.automount`

**IMPORTANT:** Running the above command will NOT show mount errors, to see mount errors you will still need to run `systemctl status` on the `.mount` service (`systemctl status storage-recordings.mount`).

Disable the automount:

`systemctl disable storage-recordings.automount`


# Building (Basics)

The LibreELEC “build-system” is a collection of scripts that simplify the complex task of cross-compiling hundreds of inter-dependent source packages into a working LibreELEC image with a few simple commands. It is the "secret sauce" of the project, as it allows users of all experience levels to tinker and experiment with the distro. Forking our codebase and experimenting is encouraged!

## Environment

The team currently builds official releases, and nightly images in Ubuntu LTS 22.04 Docker containers at the teams <https://github.com/LibreELEC/actions> CI/CD. It is possible to use other Linux distributions (Arch, Debian, Fedora, Gentoo, Manjaro, etc.) but Ubuntu is the most-used and proven. If you plan to build on an existing Linux desktop we recommend building in a Docker container to isolate the build folders from the rest of the OS (Dockerfiles can be found in the tools folder of the main LibreELEC git repo, see [Build (Docker)](/development/build-docker) for more info). Another option is building in a Virtual Machine, e.g. Oracle Virtualbox ($free) or vmware Workstation.

Note: If you want to compile older LibreELEC releases you will need to use an era-appropriate Ubuntu LTS release, e.g. LibreELEC 7.0 will need Ubuntu 14.04 or 16.04.

## Hardware

Image build times depend on CPU and I/O performance so the more CPU cores you have or can allocate, the faster your build times will be. For example:

Approx. 3 hours build time:

* 2x Core i3 CPU
* 4GB RAM (with swap enabled)
* 50GB HDD

Approx. 1.5 hours build time:

* 4x Core i7 CPU
* 8GB RAM
* 100GB SSD

Approx. 30 mins build time:

* 32x Core AMD Threadripper2
* 64GB RAM
* 1TB NVME SSD

Testing with large CPU counts shows build times continue to decrease as CPU count increases (as you'd expect) although over \~16x CPUs the gains per-CPU reduce, and overall build times are limited by the inherently sequential nature of the initial stages of building (creating the cross-compile toolchain). The current build record is \~22 mins (64x CPUs, build folders on a ramdisk).

## Dependencies

Before you can build, it is important to update the OS and install build dependencies:

```
sudo apt update
sudo apt upgrade
sudo apt install bc curl g++ gcc git gperf make openjdk-11-jre-headless rsync unzip xfonts-utils xsltproc xz-utils zip
```

Note: The first time the build-system runs it will validate and prompt you to install any missing package dependencies.

## Cloning

Use `git` to clone the LibreELEC sources to your user folder:

```
cd ~
git clone https://github.com/LibreELEC/LibreELEC.tv.git
cd LibreELEC.tv
```

## Versions

After cloning you are now at the current `HEAD` position of the `master` development branch. To compile a specific LibreELEC release we need to `checkout` the specific version `tag` or `githash` associated with the release, e.g. to build the LibreELEC 11.0.1 release we checkout the `11.0.1` tag:

```
git checkout 12.0.2
```

You can also build at a specific point in the git revision history identified by a commit githash:

```
git checkout f3fdd11916f8a47dc5a11c3a4c99cb7c7ffac78b
```

You are now in the root folder of the build-system and ready to build!

## Sources

The first time the build-system runs it will download and cache package sources, but there are \~260-380 packages to cache (depending on the build `PROJECT`) and some sources are large, and others are download from super-slow servers. To download sources in advance of building, use `download-tool`, e.g.

```
PROJECT=Generic ARCH=x86_64 tools/download-tool
```

## Building

As a normal user (not as root, and not using sudo) run a build command, e.g.

```
PROJECT=Generic ARCH=x86_64 make image
```

This will compile the `Generic` build `PROJECT` for the `x86_64` arch, and `make image` will generate an .img.gz file that can be written to USB/SD media for installation, and a .tar file that can update an existing installation (.img.gz files can also be used for updates, but .tar files are faster).

It is not uncommon for first-time builds to take 6-8 hours due to the number of sources that must be downloaded. Once the build completes the finished image files will be in the `~/LibreELEC.tv/target/` directory.

## Rebuilding

After completing your first build, you probably want to make some nip-tuck changes and then rebuild the image to include them. If you re-run the same build command the build-system will detect most changes and will clean and rebuild only the packages that have been changed. This means a "respin" with minor changes often takes only 1-2 minutes. As a general rule you can keep rebuilding (respinning) unless there are changes to the "toolchain" packages. If these are changed, you will need to clean or remove the build folders and make a "clean build" again.

## Cleaning

If you see strange or transient compilation errors, start by cleaning the sources for the failing package and clear the compiler cache (ccache), e.g. to clean the linux package:

```
PROJECT=Generic ARCH=x86_64 scripts/clean linux
```

You can also remove all build directories (keeping ccache):

```
make clean
```

Or just for one project:

```
PROJECT=Generic ARCH=x86_64 make clean
```

To remove everything and ccache:

```
make distclean
```

Or just for one project:

```
PROJECT=Generic ARCH=x86_64 make distclean
```


# Building (Docker)

Docker is used to build official releases, and nightly images in Ubuntu LTS 22.04 Docker containers at the teams https\://github.com/LibreELEC/actions CI/CD.

## Useful links

The following links will help you get started with using docker to build LibreELEC.

* <https://github.com/LibreELEC/LibreELEC.tv/tree/master/tools/docker>
* <https://github.com/LibreELEC/actions>

## Build Container

```bash
# apply patches to make the image like in CI
sed -i -e "/^USER docker/i RUN ln -s /usr/bin/gcc-10 /usr/bin/cc" tools/docker/focal/Dockerfile

# per tools/docker/README.md
docker build --pull -t libreelec tools/docker/focal
```

## Run Commands

For a list of commands, see [Build (Basics)](/development/build-basics).

### Basic

```bash
docker run \
  -it --rm \
  --log-driver none \
  -v `pwd`:/build -w /build \
  -e PROJECT=Generic \
  -e ARCH=x86_64 \
  -e MTPROGRESS=yes \
  libreelec CMD
```

### Advanced

Limit CPU and RAM so your system remains responsive.

```bash
docker run \
  -it --rm \
  --log-driver none \
  -v `pwd`:/build -w /build \
  `# setting these the same disables swapping` \
  --memory "6g" --memory-swap "6g" \
  `# uses all cpus, but will reserve cycles on each` \
  `#--cpus "4"` \
  `# limit to certain processors` \
  --cpuset-cpus "0-3" \
  -e PROJECT=Generic \
  -e ARCH=x86_64 \
  -e MTPROGRESS=yes \
  libreelec CMD
```


# Building (Advanced)

## Build-System Options

The following options can be used in LE 10.x+ to customise the build experience:

| Name             | Values                  | Default  | Description                                                                                                                                                                                                                                                                      |
| ---------------- | ----------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `THREADCOUNT`    | `#`,`#%`                | `100%`   | Maximum number of packages to build concurrently. On an 8-core system, `50%` would build up to 4 packages at a time.                                                                                                                                                             |
| `ONELOG`         | `yes`,`no`              | `no`     | If `yes`, packages will not create individual logs in `${THREAD_CONTROL}/logs`. If `THREADCOUNT` is 1 the default becomes `ONELOG=yes` in which case use `ONELOG=no` to ensure individual logs are created for each package.                                                     |
| `LOGCOMBINE`     | `always`,`never`,`fail` | `always` | Determine under what circumstances package logs are written to `stdout`. Using `never` and `fail` can slightly reduce IO.                                                                                                                                                        |
| `MTBOOKENDS`     | `yes`,`no`              | `yes`    | Adds `<<<` and `>>>` tags to the combined log output (to facilitate searching).                                                                                                                                                                                                  |
| `DISABLE_COLORS` | `yes`,`no`              | `no`     | Control whether build system output is colored or not.                                                                                                                                                                                                                           |
| `MTCOLORS`       | `always`,`never`,`auto` | `auto`   | If `DISABLE_COLORS=yes` this option controls how `scripts/pkgbuilder.py` progress and status information is colored. `auto` will disable colors when output is being redirected to a file (ie. not a terminal).                                                                  |
| `MTVERBOSE`      | `yes`,`no`              | `no`     | Output additional job state information to `stderr` during the build.                                                                                                                                                                                                            |
| `MTPROGRESS`     | `yes`,`no`              | `no`     | Output real-time load, memory and in-progress job information to `stderr` at 1-second intervals                                                                                                                                                                                  |
| `MTDEBUG`        | `yes`,`no`              | `no`     | Output detailed debug information to `${THREAD_CONTROL}/debug.log`                                                                                                                                                                                                               |
| `MTADDONBUILD`   | `yes`,`no`              | `no`     | If `no`, the build will end after the first failure. When building add-ons, we typically ignore individual package failures and continue building until all packages have been built (or failed).                                                                                |
| `MTIMMEDIATE`    | `yes`,`no`              | `no`     | When `MTADDONBUILD=no` and a package fails, the build can finish after all currently building packages have completed, or it can terminate those packages immediately. Allowing packages that are currently building to finish building can save time when restarting the build. |
| `MTINTERVAL`     | `#`                     | `60`     | System load information is captured at regular intervals in `${THREAD_CONTROL}/loadstats`.                                                                                                                                                                                       |
| `AUTOREMOVE`     | `yes`,`no`              | `no`     | Remove source code directories during the build once the source code directory is not required.                                                                                                                                                                                  |

## Persistent Options

Options can be specified on the command line, or added to persistent "options" files located under the root folder of the buildsystem, e.g. `~/LibreELEC.tv/.libreelec/options` or the users home folder, e.g. `~/.libreelec/options` - if both files exist, home folder options trump root folder options. The following gives a fairly clean and comprehensive output while still allowing command-line overrides:

```
LOGCOMBINE=${LOGCOMBINE:-never}
MTPROGRESS=${MTPROGRESS:-yes}
MTIMMEDIATE=${MTIMMEDIATE:-no}
```

## Builder Name and Version

If you are building and sharing images via the LibreELEC forums it is good to include a custom "builder" name with your images. This allows the team to count the number of active installs using your images (we can share this info on request). Builder name also populates into `/etc/os-release` and logfiles, which helps forum staff supporting users differentiate between official releases and community created images. It is also possible to set custom versioning. e.g.

```
PROJECT=Generic ARCH=x86_64 BUILDER_NAME=yourname BUILDER_VERSION=123 make image
```

It is also possible to set persistent `BUILDER_NAME` and `BUILDER_VERSION` in "options" files.

## Debug Images

The build-system automatically strips debug symbols from most packages. To disable this and include debug symbols and common debugging packages in the image, enable `DEBUG`, e.g.

```
PROJECT=Generic ARCH=x86_64 DEBUG=yes make image
```

To also include valgrind:

```
PROJECT=Generic ARCH=x86_64 DEBUG=yes VALGRIND=yes make image
```

Note: The resulting image will be considerably larger than normal. The default boot partition is 512MB, but debug images may exceed this and require a 1GB partition.

## Private Sources

To build using package source tarballs from a private GitHub repository the `package.mk` must be modified to use token authentication else wget requests made by the buildsystem are anonymous and package downloads will fail.

First obtain a personal access token from <https://github.com/settings/tokens> and add the token to the file `.libreelec/options` in the root folder of the buildsystem as shown below:&#x20;

```
TOKEN="ghp_aZBfIlA07M32p0Cy7i5hlaSzeZMZO40GuL7b"
```

Now modify the `package.mk` for the package to include additional authentication data. In the example below we are downloading an archive using a githash for `PKG_VERSION` and with the `PKG_SHA256` check disabled. The `WGET_OPT` line has been added, and the format of the URL used in `PKG_URL` has been tweaked to include `${TOKEN}:@` between URI and domain:

```
PKG_VERSION="501631d21b37c858f32a0f0d10237b14d1cd2224"                                
PKG_SHA256=""                                                                         
WGET_OPT="--auth-no-challenge --header='Accept:application/octet-stream'"             
PKG_URL="https://${TOKEN}:@github.com/LibreELEC/kernel/archive/${PKG_VERSION}.tar.gz"
PKG_SOURCE_NAME="linux-${LINUX}-${PKG_VERSION}.tar.gz"
```

Should you need to use more than one token, create `TOKEN2` and `TOKEN3` etc. in the `options` file and reference them as variables in the `package.mk` files that require them.


# Building (Windows WSL)

## Requirements

* Windows 11 with installed WSL2 and Ubuntu WSL

## Workarounds to make it work

#### WSL adds Windows paths to the Linux path variable

```
wsl@PC:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Windows/System32/OpenSSH/:/snap/bin
```

This breaks the build and leads to unpredictable problems.

To disable that behaviour you need to create a file at your Ubuntu WSL `/etc/wsl.conf` and add these options to disable. Afterwards you need to reboot WSL or your system.

```
 [interop]
  enabled=false # enable launch of Windows binaries
  appendWindowsPath=false # append Windows path to $PATH variable
```

#### Building at the native NTFS formatted storage (C:/; D:/ ...) is dead slow

To interoperate with your Windows Desktop you want the git tree accessible from Windows.\
So you clone the Git Tree to a location at windows and try to use it at WSL.

For this example the Git Tree is cloned at `D:\WSL\LE` - `/mnt/d/WSL/LE`.\
If you start building the build folder would be located at `D:\WSL\LE\build.YOURPROJECT` .

To change the path for the build files you need to add some options to the LibreELEC options file `/home/YOURUSER/.libreelec/options` .

```
BUILD_DIR=/home/YOURUSER/LEbuild
```

After adding this line to the options file every build is now located at this folder.

The /home folder is located at the WSL ext4.vhdx and not at the native NTFS storage.

#### Optional: Move your WSL file to another location

There are several ways in moving your WSL file, the easiest solution is the dedicated tool [LxRunOffline](https://github.com/DDoSolitary/LxRunOffline#install) . The version 3.5.0 is not supporting the current Windows Version so you need to use a more recent version or a development build.

`lxrunoffline move -n Ubuntu-22.04 -d d:\wsl`

**AlpineWSL**

Or you can use <https://github.com/yuk7/AlpineWSL> which creates ext4.vhdx on your wanted disk and automatically mounts it to WSL2 itself on startup. Advanced instructions: <https://gist.github.com/onomatopellan/90024008a0d8c8a2ed6fa57e8b64df54>


# Beginners Guide to Git

Most community/user developers have simple git goals, for example:

* Changing the Linux kernel `defconfig` to enable a driver
* Bumping the version for a software or binary add-on package
* Contributing to project documentation!

The goal of this page is to explain essential git workflow and terms. Git is mind-bendingly ~~complicated~~ clever and there are hundreds of tricks to learn, but the basics are logical and quite simple to pick-up. One of the good things about git is; everyone is still learning! and everyone remembers what it was like to be a git n00b at the beginning. If you need to ask questions, ask them, as people are happy to coach.

## Forking and Cloning

The project maintains its primary git repository (repo) at <https://github.com/LibreELEC/LibreELEC.tv/>. The repo hosts the `master` development branch where the next release takes shape, and stable release branches, e.g. `libreelec-12.0` and `libreelec-11.0` that accumulate release-specific changes (commits) over time.

To self-build an image and test something you can simply `git clone` our sources and start building, but if you want to maintain personal customisations and changes over time it's better to `fork` our sources to your own git repo. Having your own fork makes the process of storing, sustaining, and sharing your changes easier. Forking is done online by visiting the LibreELEC repo and then pressing the fork button (top right of the screen). GitHub will make a copy of our sources under your own user account. Now instead of cloning OUR sources you `git clone` a copy of YOUR sources to your local hard-drive.

```
git clone https://github.com/username/LibreELEC.tv
cd LibreELEC.tv
```

## Origin and Upstream

Like ours, your fork will have a `master` branch and release branches like `libreelec-12.0` which contain a sequence of commits. When you clone your repo to your local drive, git automatically creates references to your copy on GitHub which is the `origin` of your local sources. To update your local branches with changes from our `upstream` branches, we will define a `remote` repo. You can add many remote(s), but we will add just one:

```
git remote add upstream https://github.com/LibreELEC/LibreELEC.tv.git
```

## Topic Branches

One of the most important principles of git is **NEVER WORK IN THE MASTER BRANCH !!**. To make a one-time change then build an image it's fine, but if you make changes in branches that we maintain (upstream) it becomes complicated to maintain your local (downstream) changes. It's best to keep your changes in a separate "topic" branch. To create a new topic branch, you `checkout` a new branch from the one you want to modify. For example, to modify the `libreelec-12.0` branch, we switch to it, then create the "mychanges" topic branch:

```
git checkout libreelec-12.0
git checkout -b mychanges
```

## Commit Changes

In git-speak when you save your work you `commit` changes to the working (topic) branch. The mantra for committing is "commit early, commit often" because it's always simple to combine (squash) commits together at a later stage, but hard to split a large commit into many smaller pieces. Commits can document changes to a single file or a collection of files, with a readable "commit message" that describes the changes. LibreELEC has a "house style" for commit messages: `tag: summary of changes made` where `tag` is the name of the package being changed or a functional area of the build system and `summary of changes made` explains in brief what the change does. It helps to make them descriptive so you can read the `git log` later and understand which commit changed something. For example, if we enable an extra driver or module in the Linux kernel:

```
nano projects/Generic/linux/linux.x86_64.conf
```

Make changes and save the file:

```
git add projects/Generic/linux/linux.x86_64.conf
git commit -m "linux: enable RTL8822CE wireless driver"
```

Most users will make changes first, then build and test them, then `commit` the changes.

## Fetching and Rebasing

Over time staff and users contribute changes to our `upstream` branches and your local fork falls behind. To update your "mychanges" topic branch you must first commit any unsaved changes, then switch back to the branch it was based upon, e.g. the `libreelec-12.0` branch:

```
git checkout libreelec-12.0
```

Next we need to `fetch` the latest changes from the `upstream` branch to our local cache, then reset the local copy of the branch to match the upstream one:

```
git fetch upstream libreelec-12.0
git reset --hard upstream/libreelec-12.0
```

Now the local `libreelec-12.0` branch contains the latest changes we can change back to our `mychanges` topic branch and `rebase` the branch. Rebasing re-applies the single or handful of changes that you made (and committed) to the branch you are rebasing against, e.g.

```
git checkout mychanges
git rebase libreelec-12.0
```

If you look at the log of commits you will see the `mychanges` branch matches the upstream `libreelec-12.0` branch, with your local changes applied on top.

```
git log --pretty=oneline
```

## Interactive Rebasing

This is the git trick that everyone needs to learn. It is often the "Eureka!" moment that moves a user from novice to normal. Interactive rebasing allows you to (re)edit, remove, and reorder the sequence of commits in the branch. The reasons you will want/need to do this are dropping a change, grouping commits together so the sequence is easier to understand, to edit (reword) one or more commit messages, or to combine (squash or fixup) multiple small changes into a single larger commit. Interactive rebasing is done to a specific number of commits measured from the top (HEAD) of the branch, e.g. to rebase the last five changes:

```
git rebase -i HEAD~5
```

The list of commits will open in a text editor, e.g. "nano" and you can cut (ctrl+k) and paste (ctrl+u) the commits to reorder them. For example, lets say we have the following list which shows which commits are being pick(ed) to the branch:

```
pick 73d9356c36 fix typos in file A
pick 29de6de78b add new file B
pick be444ce9e7 more typos in A
pick cf7149bc7e more typos in A
pick 750b824c04 changes to file B
```

It would be more logical to group all the `file A` and `file B` commits like this:

```
pick 73d9356c36 fix typos in file A
pick be444ce9e7 more typos in A
pick cf7149bc7e more typos in A
pick 29de6de78b add new file B
pick 750b824c04 changes to file B
```

The next logical step might be to combine the changes so there are only two commits; one for changes to file A and one for changes to file B. This is done by changing `pick` to `squash` or `fixup` which combine commits. In the sequence below, the first commit is at the top, and we want to combine the next two minor changes into it. If you `squash`commits you will be asked to edit the commit messages (choose which of the commits should be used for the message) while `fixup` combines the lower (second) commit into the upper (first) commit and uses the first commit message without prompting. For example:

```
pick 73d9356c36 fix typos in file A
fixup be444ce9e7 more typos in A
fixup cf7149bc7e more typos in A
pick 29de6de78b add new file B
fixup 750b824c04 changes to file B
```

Once you save (ctrl+o) and exit edit mode (ctrl+x) the reordering and squash/fixup changes are applied, leaving you with two commits for "fix typos in file A" and "add new file B" in the branch. It is a good habit to squash and rebase frequently to keep your changes logically grouped and in a minimum number of commits. This is important if you want to send your changes upstream in a "pull request" to our repo. Project staff want to review a small and logical set of changes, not the monster list of nip-tuck changes you needed to figure out what changes were needed.

## Push and Force-Push

Another good habit is `pushing` your local changes back to your `origin` branch on GitHub. If something gets messed up in your local branch (and when you are starting out with git, stuff will get messed up!) you can always reset your local branch to the previous known-good state stored on GitHub. Pushing the changes is simple:

```
git push origin mychanges
```

If you have rebased the `mychanges` branch the branch history will have different references and a force-push will be needed:

```
git push -f origin mychanges
```

There are also no restrictions on the number of branches you can make. So fork branches and push them upstream. It's better to fork and store changes and then tidy things up occasionally than lose changes and have to repeat/reinvent them.

## Pull Requests (PR) <a href="#pullrequests" id="pullrequests"></a>

If your changes might benefit the project and you'd like to see them included `upstream` in our repo so you don't need to maintain them in your `downstream` fork, you'll need to submit a `pull request` (referred to as a PR.) This is done in the GitHub interface. You need to push your changes to your origin branch, and then when you view the code on GitHub, select the "pull request" button. You'll be prompted to select the repo/branch to send the request to, e.g. `LibreELEC.tv/master` and you'll give the request a name and description. If your pull request modifies code, please include a good description of the problem that your changes solve or what the feature is that you added, and (important!) the testing you conducted. So called "blind requests" where there is no evidence of testing and no meaningful explanation of the change, are rarely merged (or merged quickly) into our codebase.

Note: All functional changes should be submitted to the `master` branch first, even if the target for your changes is the current stable release branch. This way the branches remain in sync, and we don't have orphaned features.


# Build Commands


# Build Commands (Add-ons)

The build-system also builds a range of LibreELEC or Kodi binary add-ons. These follow the same basic build command syntax as an image build, e.g. to build `Tvheadend 4.2`

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon tvheadend42
```

To compile all `game.libretro` add-ons:

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon game.*
```

To compile all [https://github.com/LibreELEC/LibreELEC.tv/tree/master/packages/mediacenter/kodi-binary-addons](https://github.com/LibreELEC/documentation/tree/393dc8f1e82c82b95bad32bf23af1faf455762e6/development/build-commands/Kodi%20binary%20add-ons/README.md):

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon binary
```

To compile all [https://github.com/LibreELEC/LibreELEC.tv/tree/master/packages/addons](https://github.com/LibreELEC/documentation/tree/393dc8f1e82c82b95bad32bf23af1faf455762e6/development/build-commands/LibreELEC%20binary%20add-ons/README.md):

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon official
```

To compile all add-ons:

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon all
```

It is also possible to exclude specific add-ons:

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon all -game.* -official -pvr.hts
```

To log errors to the `$BUILD/logs/` directory:

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon all --write-logs=errors
```

To show help and list all add-on building functions:

```
PROJECT=Generic ARCH=x86_64 scripts/create_addon --help
```

## Note

In LibreELEC 10.x and newer ARM SoC devices (Allwinner, Amlogic, NXP, Qualcomm, Rockchip, Samsung) use the `ARMv7` or `ARMv8` project. This project uses a minimal distro configuration (disabling most features) to reduce the overall time spent on building add-on dependencies.

```
PROJECT=ARM ARCH=arm DEVICE=ARMv7 scripts/create_addon all
PROJECT=ARM ARCH=arm DEVICE=ARMv8 scripts/create_addon all
PROJECT=ARM ARCH=aarch64 DEVICE=ARMv8 scripts/create_addon all
```


# Build Commands LE 12.0.x

## Build Commands LE 12.0.x

| Image                        | Command                                                       |
| ---------------------------- | ------------------------------------------------------------- |
| Allwinner A64                | PROJECT=Allwinner ARCH=aarch64 DEVICE=A64 make image          |
| Allwinner H3                 | PROJECT=Allwinner ARCH=arm DEVICE=H3 make image               |
| Allwinner H5                 | PROJECT=Allwinner ARCH=aarch64 DEVICE=H5 make image           |
| Allwinner H6                 | PROJECT=Allwinner ARCH=aarch64 DEVICE=H6 make image           |
| Allwinner R40                | PROJECT=Allwinner ARCH=arm DEVICE=R40 make image              |
| Amlogic GXBB/GXL/GXM/G12/SM1 | PROJECT=Amlogic ARCH=aarch64 DEVICE=AMLGX make image          |
| Generic x86\_64 GBM          | PROJECT=Generic DEVICE=Generic ARCH=x86\_64 make image        |
| Generic x86\_64 X11 (legacy) | PROJECT=Generic DEVICE=Generic-legacy ARCH=x86\_64 make image |
| NXP/Freescale iMX.6          | PROJECT=NXP ARCH=arm DEVICE=iMX6 make image                   |
| NXP/Freescale iMX.8          | PROJECT=NXP ARCH=aarch64 DEVICE=iMX8 make image               |
| Qualcomm DragonBoard         | PROJECT=Qualcomm ARCH=aarch64 DEVICE=Dragonboard make image   |
| Raspberry Pi 2/3             | PROJECT=RPi ARCH=arm DEVICE=RPi2 make image                   |
| Raspberry Pi 4               | PROJECT=RPi ARCH=aarch64 DEVICE=RPi4 make image               |
| Raspberry Pi 5               | PROJECT=RPi ARCH=aarch64 DEVICE=RPi5 make image               |
| Samsung Exynos               | PROJECT=Samsung ARCH=arm DEVICE=Exynos make image             |
| Rockchip RK3328              | PROJECT=Rockchip ARCH=arm DEVICE=RK3328 make image            |
| Rockchip RK3288              | PROJECT=Rockchip ARCH=arm DEVICE=RK3288 make image            |
| Rockchip RK3399              | PROJECT=Rockchip ARCH=arm DEVICE=RK3399 make image            |

### Notes

To improve GHA/CI automation with ARM SoC `$PROJECT`(s) that support multiple `$DEVICE` types `make image` will iterate through all board/u-boot configurations defined in `scripts/uboot_helper` resulting in \~3-10 images in the target folder. To avoid this behaviour and build a single board-specific image `UBOOT_SYSTEM=<board>` can be appended to the build command, e.g. to build an Amlogic image for a LibreComputer LePotato board:

```
PROJECT=Amlogic ARCH=aarch64 DEVICE=AMLGX UBOOT_SYSTEM=lepotato make image
```

Several ARM SoC devices have a `UBOOT_SYSTEM=box` configuration which excludes u-boot and provides all device-trees, allowing the image to boot using the Android/BSP u-boot on emmc/spi.

### Environment

Official releases were built using Ubuntu 22.04 LTS.


# Build Commands LE 11.0.x

## Build Commands LE 11.0.x

| Image                        | Command                                                       |
| ---------------------------- | ------------------------------------------------------------- |
| Allwinner A64                | PROJECT=Allwinner ARCH=arm DEVICE=A64 make image              |
| Allwinner H3                 | PROJECT=Allwinner ARCH=arm DEVICE=H3 make image               |
| Allwinner H5                 | PROJECT=Allwinner ARCH=arm DEVICE=H5 make image               |
| Allwinner H6                 | PROJECT=Allwinner ARCH=arm DEVICE=H6 make image               |
| Amlogic GXBB/GXL/GXM/G12/SM1 | PROJECT=Amlogic ARCH=arm DEVICE=AMLGX make image              |
| Generic x86\_64 GBM          | PROJECT=Generic DEVICE=Generic ARCH=x86\_64 make image        |
| Generic x86\_64 X11 (legacy) | PROJECT=Generic DEVICE=Generic-legacy ARCH=x86\_64 make image |
| NXP/Freescale iMX.6          | PROJECT=NXP ARCH=arm DEVICE=iMX6 make image                   |
| NXP/Freescale iMX.8          | PROJECT=NXP ARCH=arm DEVICE=iMX8 make image                   |
| Qualcomm DragonBoard         | PROJECT=Qualcomm ARCH=arm DEVICE=Dragonboard make image       |
| Raspberry Pi 2/3             | PROJECT=RPi ARCH=arm DEVICE=RPi2 make image                   |
| Raspberry Pi 4               | PROJECT=RPi ARCH=arm DEVICE=RPi4 make image                   |
| Raspberry Pi 5               | PROJECT=RPi ARCH=arm DEVICE=RPi5 make image                   |
| Samsung Exynos               | PROJECT=Samsung ARCH=arm DEVICE=Exynos make image             |
| Rockchip RK3328              | PROJECT=Rockchip ARCH=arm DEVICE=RK3328 make image            |
| Rockchip RK3288              | PROJECT=Rockchip ARCH=arm DEVICE=RK3288 make image            |
| Rockchip RK3399              | PROJECT=Rockchip ARCH=arm DEVICE=RK3399 make image            |

### Notes

To improve GHA/CI automation with ARM SoC `$PROJECT`(s) that support multiple `$DEVICE` types `make image` will iterate through all board/u-boot configurations defined in `scripts/uboot_helper` resulting in \~3-10 images in the target folder. To avoid this behaviour and build a single board-specific image `UBOOT_SYSTEM=<board>` can be appended to the build command, e.g. to build an Amlogic image for a LibreComputer LePotato board:

```
PROJECT=Amlogic ARCH=arm DEVICE=AMLGX UBOOT_SYSTEM=lepotato make image
```

Several ARM SoC devices have a `UBOOT_SYSTEM=box` configuration which excludes u-boot and provides all device-trees, allowing the image to boot using the Android/BSP u-boot on emmc/spi.

### Environment

Official releases were built using Ubuntu 22.04 LTS.


# Build Commands LE 10.0.x

| Image                        | Command                                                 |
| ---------------------------- | ------------------------------------------------------- |
| Allwinner A64                | PROJECT=Allwinner ARCH=arm DEVICE=A64 make image        |
| Allwinner H3                 | PROJECT=Allwinner ARCH=arm DEVICE=H3 make image         |
| Allwinner H5                 | PROJECT=Allwinner ARCH=arm DEVICE=H5 make image         |
| Allwinner H6                 | PROJECT=Allwinner ARCH=arm DEVICE=H6 make image         |
| Amlogic GXBB/GXL/GXM/G12/SM1 | PROJECT=Amlogic ARCH=arm DEVICE=AMLGX make image        |
| Generic Intel/AMD x86\_64    | PROJECT=Generic ARCH=x86\_64 make image                 |
| NXP/Freescale iMX.6          | PROJECT=NXP ARCH=arm DEVICE=iMX6 make image             |
| NXP/Freescale iMX.8          | PROJECT=NXP ARCH=arm DEVICE=iMX8 make image             |
| Qualcomm DragonBoard         | PROJECT=Qualcomm ARCH=arm DEVICE=Dragonboard make image |
| Raspberry Pi 2/3             | PROJECT=RPi ARCH=arm DEVICE=RPi2 make image             |
| Raspberry Pi 4               | PROJECT=RPi ARCH=arm DEVICE=RPi4 make image             |
| Samsung Exynos               | PROJECT=Samsung ARCH=arm DEVICE=Exynos make image       |
| Rockchip RK3328              | PROJECT=Rockchip ARCH=arm DEVICE=RK3328 make image      |
| Rockchip RK3288              | PROJECT=Rockchip ARCH=arm DEVICE=RK3288 make image      |
| Rockchip RK3399              | PROJECT=Rockchip ARCH=arm DEVICE=RK3399 make image      |

## Notes

To improve Jenkins/CI automation with ARM SoC `$PROJECT`(s) that support multiple `$DEVICE` types `make image` will iterate through all board/u-boot configurations defined in `scripts/uboot_helper` resulting in \~3-10 images in the target folder. To avoid this behaviour and build a single board-specific image `UBOOT_SYSTEM=<board>` can be appended to the build command, e.g. to build an Amlogic image for a LibreComputer LePotato board:

```
PROJECT=Amlogic ARCH=arm DEVICE=AMLGX UBOOT_SYSTEM=lepotato make image
```

Several ARM SoC devices have a `UBOOT_SYSTEM=box` configuration which excludes u-boot and provides all device-trees, allowing the image to boot using the Android/BSP u-boot on emmc/spi.

## Environment

Official releases were built using Ubuntu 18.04 and 20.04 LTS.


# Build Commands LE 9.2.x

Amlogic images based on the legacy Linux 3.14 kernel were dropped for this release, with development shifting to the mainline Linux kernel.

| Image                     | Command                                                 |
| ------------------------- | ------------------------------------------------------- |
| Allwinner A64             | PROJECT=Allwinner ARCH=arm DEVICE=A64 make image        |
| Allwinner H3              | PROJECT=Allwinner ARCH=arm DEVICE=H3 make image         |
| Allwinner H6              | PROJECT=Allwinner ARCH=arm DEVICE=H6 make image         |
| Generic Intel/AMD x86\_64 | PROJECT=Generic ARCH=x86\_64 make image                 |
| Raspberry Pi 0/1          | PROJECT=RPi ARCH=arm DEVICE=RPi make image              |
| Raspberry Pi 2/3          | PROJECT=RPi ARCH=arm DEVICE=RPi2 make image             |
| Raspberry Pi 4            | PROJECT=RPi ARCH=arm DEVICE=RPi4 make image             |
| Rockchip MiQi             | PROJECT=Rockchip ARCH=arm DEVICE=MiQi make image        |
| Rockchip RK3328           | PROJECT=Rockchip ARCH=arm DEVICE=RK3328 make image      |
| Rockchip RK3399           | PROJECT=Rockchip ARCH=arm DEVICE=RK3399 make image      |
| Rockchip Tinkerboard/S    | PROJECT=Rockchip ARCH=arm DEVICE=Tinkerboard make image |

## Notes

To improve Jenkins/CI automation with ARM SoC projects that support multiple `$DEVICE` types `make image` will iterate through all board/u-boot configurations for the device defined in `scripts/uboot_helper` resulting in \~3-10 images in the target folder. To avoid this behaviour and build a single board-specific image `UBOOT_SYSTEM=<board>` can be appended to the build command, e.g. to build an Amlogic image for a LibreComputer LePotato board:

```
PROJECT=Amlogic ARCH=arm DEVICE=AMLGX UBOOT_SYSTEM=lepotato make image
```

Several ARM SoC devices have a `UBOOT_SYSTEM=box` configuration which excludes u-boot and provides all device-trees, allowing the image to boot using the Android/BSP u-boot on eMMC/SPI.

## Environment

Official releases were built using Ubuntu 18.04 LTS.


# Build Commands LE 9.0.x

| Image             | Command                                          |
| ----------------- | ------------------------------------------------ |
| Generic (x86\_64) | PROJECT=Generic ARCH=x86\_64 make image          |
| Raspberry Pi 0/1  | PROJECT=RPi ARCH=arm DEVICE=RPi make image       |
| Raspberry Pi 2/3  | PROJECT=RPi ARCH=arm DEVICE=RPi2 make image      |
| Raspberry Pi 4    | PROJECT=RPi ARCH=arm DEVICE=RPi4 make image      |
| Allwinner A20     | PROJECT=Allwinner ARCH=arm DEVICE=A20 make image |
| Allwinner A64     | PROJECT=Allwinner ARCH=arm DEVICE=A64 make image |
| Allwinner H3      | PROJECT=Allwinner ARCH=arm DEVICE=H3 make image  |
| Allwinner H5      | PROJECT=Allwinner ARCH=arm DEVICE=H5 make image  |
| Allwinner H6      | PROJECT=Allwinner ARCH=arm DEVICE=H6 make image  |

## Notes

The Virtual project was combined into the Generic image. Running `make image` will output an OVA file in addition to the normal .img.gz and .tar files.

Amlogic, Raspberry Pi, and Rockchip build projects require a `DEVICE=<name>` to be specified. For example, to build an Amlogic image for a LibreComputer LePotato board:

```
PROJECT=Amlogic ARCH=arm DEVICE=LePotato make image
```

## Environment

Official releases were built using Ubuntu 16.04 and 18.04 LTS.


# Build Commands LE 8.2.x

| Image                      | Command                                        |
| -------------------------- | ---------------------------------------------- |
| Freescale iMX6             | PROJECT=imx6 ARCH=arm make image               |
| Generic (x86\_64)          | PROJECT=Generic ARCH=x86\_64 make image        |
| Odroid C2                  | PROJECT=Odroid\_C2 ARCH=aarch64 make image     |
| Raspberry Pi 0/1           | PROJECT=RPi ARCH=arm make image                |
| Raspberry Pi 2/3           | PROJECT=RPi2 ARCH=arm make image               |
| VMware (not Virtualbox)    | PROJECT=Virtual ARCH=x86\_64 make image        |
| WeTek Play, WeTek OpenELEC | PROJECT=WeTek\_Play ARCH=arm make image        |
| WeTek Play 2               | PROJECT=WeTek\_Play\_2 ARCH=aarch64 make image |
| WeTek Core                 | PROJECT=WeTek\_Core ARCH=arm make image        |
| WeTek Hub                  | PROJECT=WeTek\_Hub ARCH=aarch64 make image     |

## Environment

Official releases were built using Ubuntu 16.04 LTS.


# Build Commands LE 8.0.x

| Image                      | Command                                        |
| -------------------------- | ---------------------------------------------- |
| Freescale iMX6             | PROJECT=imx6 ARCH=arm make image               |
| Generic (x86\_64)          | PROJECT=Generic ARCH=x86\_64 make image        |
| Odroid C2                  | PROJECT=Odroid\_C2 ARCH=aarch64 make image     |
| Raspberry Pi 0/1           | PROJECT=RPi ARCH=arm make image                |
| Raspberry Pi 2/3           | PROJECT=RPi2 ARCH=arm make image               |
| VMware (not Virtualbox)    | PROJECT=Virtual ARCH=x86\_64 make image        |
| WeTek Play, WeTek OpenELEC | PROJECT=WeTek\_Play ARCH=arm make image        |
| WeTek Play 2               | PROJECT=WeTek\_Play\_2 ARCH=aarch64 make image |
| WeTek Core                 | PROJECT=WeTek\_Core ARCH=arm make image        |
| WeTek Hub                  | PROJECT=WeTek\_Hub ARCH=aarch64 make image     |

## Environment

Official releases were built using Ubuntu 16.04 LTS.


# Build Commands LE 7.0.x

| Image                      | Command                                 |
| -------------------------- | --------------------------------------- |
| Freescale iMX6             | PROJECT=imx6 ARCH=arm make image        |
| Generic (x86\_64)          | PROJECT=Generic ARCH=x86\_64 make image |
| Raspberry Pi 0/1           | PROJECT=RPi ARCH=arm make image         |
| Raspberry Pi 2/3           | PROJECT=RPi2 ARCH=arm make image        |
| VMware (not Virtualbox)    | PROJECT=Virtual ARCH=x86\_64 make image |
| WeTek Play, WeTek OpenELEC | PROJECT=WeTek\_Play ARCH=arm make image |
| WeTek Core                 | PROJECT=WeTek\_Core ARCH=arm make image |

## Environment

Official releases were built using Ubuntu 14.04 and 16.04 LTS.


# Nightly Images

We use GitHub Actions to automate building of "nightly" development snapshots of the master and stable branches and the add-ons for testing. Images can be downloaded from <https://test.libreelec.tv/>.


# Release Management

Release management is as simple as plan, build, test, prepare and deploy.

## Package management

LibreELEC is made up of over 800 packages which are in themselves developed by many other teams and groups across the Internet. These packages are maintained in the `packages` directory. An example of a package is **Linux** which has its main **LibreELEC** `makefile` as `packages/linux/package.mk`, or **Kodi** `packages/mediacenter/kodi/package.mk`.

The project team and Contributors prepare and regularly update the code that makes up the LibreELEC distribution. This is done by "bumping" the `PKG_VERSION` in the `package.mk` file and updating the other variables, code, patches and dependencies that make up the distribution. These are then rolled up into a [https://github.com/LibreELEC/documentation/blob/master/development-1/git-tutorial.md#pullrequests](https://github.com/LibreELEC/documentation/blob/master/development-1/git-tutorial.md#pullrequests "mention")and submitted as a change.

### Release Monitoring

The `update-scan` tool has been developed to check `PKG_VERSION` of packages against release monitoring sites. This tool currently uses **Anitya** from [https://release-monitoring.org/](https://release-monitoring.org) with the following distribution <https://release-monitoring.org/distro/LibreELEC/>

An example of the output from `update-scan` is below:

```
$ tools/update-scan
Github api usage activated

Updates found:

Package            | LE git master         | upstream location
--------------------------------------------------------------
Pillow             | 8.4.0                 | 9.0.1
Python3            | 3.8.12                | 3.11.0a5
RPi.GPIO           | 0.7.1a4               | 0.7.0
.
.
.
```

The tool provides a report at the end of the currency of the packages in the current checked out **LibreELEC** code.

```
Current 449:
Jinja2 Mako MarkupSafe ...

Ignored 84:
adafruit-libraries alsa ...

Packages not known at tracker 23:
RTL8192CU configtools dvb-latest edid-decode firmware-dragonboard \
firmware-imx gcc-riscv64-unknown-linux-gnu getscancodes \
gnulib jdk-aarch64-zulu jdk-arm-zulu jdk-x86_64-zulu kmscube \
lan951x-led-ctl media_tree oscam szap-s2 t2scan tune-s2 unfsd \
vdr-plugin-dummydevice vdr-plugin-wirbelscancontrol vdr-plugin-wirbelscan
```

Packages are ignored if either the `PKG_VERSION` *or* `PKG_URL` \_\_ are empty or hosted by **LibreELEC**.

For packages not known at the tracker - this means that the package is either not release monitored or not configured for release monitoring at <https://release-monitoring.org/distro/LibreELEC/>.

The following image shows the **Projects of LibreELEC** monitored by **release-monitoring**.

![](/files/9cvPPrAgAaQpqTwzsTGb)

Adding a project to the distro can be made by logging in using your **Fedora** ID.

![](/files/VTsz1Hepj7L7a542YY6Z)

Search for the project that you have developed the package.mk for and you want release-monitoring to monitor. In the example - we have added the distro **LibreELEC** to `aixlog`.

![](/files/cBWgBDKnyOVYHzF37N6Y)

Click the `Add new distribution mapping` button within the Project <https://release-monitoring.org/project/141477/> (**aixlog** example.)

![](/files/vYj6dc5jC9b04LPJU9yK)

You need to choose **LibreELEC** from the **Distribution** drop down. Then click `+ Add mapping to project`.

{% hint style="info" %}
The Package Name must match the `PKG_NAME` variable from the **LibreELEC** `package.mk` file. The `Project name` from the Project in release-monitoring.org does not have to match the **LibreELEC** `PKG_NAME`.
{% endhint %}


# Website

how to edit the website

## Installation

#### Ubuntu dependencies

`sudo apt install ruby-full make gcc gpp build-essential zlib1g zlib1g-dev ruby-dev dh-autoreconf`

#### Update gem packages

`sudo gem update`

#### Install Gem bundler

`sudo gem install bundler`

#### Clone the website

`git clone https://github.com/LibreELEC/website.git`

#### Install Jekyll

`cd /path/to/git/website/`

`bundle install`

## Run the website from Linux

Run the command from the cloned website folder.

`bundle exec jekyll serve --livereload --unpublished --incremental`

## Run the website from Windows (WSL2)

It is possible to run Ruby natively in Windows but this is difficult to do. So in our example we just run it at WSL and bypass all those problems.

Run the command from the cloned website folder.

`bundle exec jekyll serve --force_polling --livereload --unpublished`

![](/files/PVqqFpkpNzF2D9vRxV3H)

## Display the website

After starting the server the website is autogenerated at every change excluding changes at `_config.yml` and `packages.json` that requires a restart of the server.

The website is now located at [http://127.0.0.1:4000/](http://127.0.0.1:4000) .


# Releases

An official archive of all Alpha, Beta, and Release images is here: <http://archive.libreelec.tv>

Nightly test and development snapshot images are here: <https://test.libreelec.tv>

## 12.0 (Kodi v21, Omega)

| Version | Status | Release Post                                                    |
| ------- | ------ | --------------------------------------------------------------- |
| 12.0.2  | Stable | [Blog](https://libreelec.tv/2025/01/22/libreelec-nexus-12-0-2/) |
| 12.0.1  | Stable | [Blog](https://libreelec.tv/2024/08/26/libreelec-nexus-12-0-1/) |
| 12.0.0  | Stable | [Blog](https://libreelec.tv/2024/05/01/libreelec-nexus-12-0-0/) |

## 11.0 (Kodi v20, Nexus)

| Version | Status                 | Release Post                                                    |
| ------- | ---------------------- | --------------------------------------------------------------- |
| 11.0.3  | Stable                 | [Blog](https://libreelec.tv/2023/07/20/libreelec-nexus-11-0-3/) |
| 11.0.2  | Not released (skipped) | -                                                               |
| 11.0.1  | Stable                 | [Blog](https://libreelec.tv/2023/03/24/libreelec-nexus-11-0-1/) |
| 11.0.0  | Stable                 | [Blog](https://libreelec.tv/2023/03/06/libreelec-nexus-11-0-0/) |

## 10.0 (Kodi v19, Matrix)

| Version | Status | Release Post                                                   |
| ------- | ------ | -------------------------------------------------------------- |
| 10.0.0  | Stable | [Blog](https://libreelec.tv/2021/08/26/libreelec-matrix-10-0/) |

## 9.2 (Kodi v18, Leia)

| Version | Status | Release Post                                                      |
| ------- | ------ | ----------------------------------------------------------------- |
| 9.2.8   | Hotfix | [Blog](https://libreelec.tv/2021/07/le-9-2-fix-2-for-widevine/)   |
| 9.2.7   | Hotfix | [Blog](https://libreelec.tv/2021/05/le-9-2-7-10b4-fix-widevine/)  |
| 9.2.6   | Stable | [Blog](https://libreelec.tv/2020/11/libreelec-leia-9-2-6)         |
| 9.2.5   | Hotfix | [Blog](https://libreelec.tv/2020/08/libreelec-leia-9-2-5)         |
| 9.2.4   | Stable | [Blog](https://libreelec.tv/2020/08/libreelec-leia-9-2-4)         |
| 9.2.3   | Stable | [Blog](https://libreelec.tv/2020/06/libreelec-leia-9-2-3)         |
| 9.2.2   | Hotfix | [Blog](https://libreelec.tv/2020/03/libreelec-leia-9-2-2-hotfix)  |
| 9.2.1   | Stable | [Blog](https://libreelec.tv/2020/03/libreelec-leia-9-2-1)         |
| 9.2.0   | Stable | [Blog](https://libreelec.tv/2019/11/libreelec-leia-9-2-0)         |
| 9.1.502 | Beta   | [Blog](https://libreelec.tv/2019/10/libreelec-leia-9-2-beta-2)    |
| 9.1.501 | Beta   | [Blog](https://libreelec.tv/2019/09/libreelec-leia-9-2-beta1)     |
| 9.1.002 | Alpha  | [Blog](https://libreelec.tv/2019/07/libreelec-leia-9-1-002-alpha) |
| 9.1.001 | Alpha  | [Blog](https://libreelec.tv/2019/06/libreelec-9-2-alpha1-rpi4b)   |

## 9.0 (Kodi v18, Leia)

| Version  | Status | Release Post                                                        |
| -------- | ------ | ------------------------------------------------------------------- |
| 9.0.2    | Stable | [Blog](https://libreelec.tv/2019/05/libreelec-leia-9-0-2-mr)        |
| 9.0.1    | Stable | [Blog](https://libreelec.tv/2019/02/libreelec-leia-9-0-1-mr)        |
| 9.0.0    | Stable | [Blog](https://libreelec.tv/2019/02/libreelec-leia-9-0-0-release)   |
| 8.95.003 | Beta   | [Blog](https://libreelec.tv/2019/01/libreelec-leia-v8-95-3-beta)    |
| 8.95.002 | Beta   | [Blog](https://libreelec.tv/2019/01/libreelec-leia-v8-95-2-beta)    |
| 8.95.001 | Beta   | [Blog](https://libreelec.tv/2018/12/libreelec-leia-v8-95-1-beta)    |
| 8.90.009 | Alpha  | [Blog](https://libreelec.tv/2018/12/libreelec-leia-v8-90-009-alpha) |
| 8.90.008 | Alpha  | [Blog](https://libreelec.tv/2018/11/libreelec-leia-v8-90-008-alpha) |
| 8.90.007 | Alpha  | [Blog](https://libreelec.tv/2018/11/libreelec-leia-v8-90-007-alpha) |
| 8.90.006 | Alpha  | [Blog](https://libreelec.tv/2018/10/libreelec-leia-v8-90-006-alpha) |
| 8.90.005 | Alpha  | [Blog](https://libreelec.tv/2018/09/libreelec-leia-v8-90-005-alpha) |
| 8.90.004 | Alpha  | [Blog](https://libreelec.tv/2018/09/libreelec-leia-v8-90-004-alpha) |
| 8.90.003 | Alpha  | [Blog](https://libreelec.tv/2018/08/libreelec-leia-v8-90-003-alpha) |

## 8.2 (Kodi v17, Krypton)

| Version | Status | Release Post                                                         |
| ------- | ------ | -------------------------------------------------------------------- |
| 8.2.5   | Stable | [Blog](https://libreelec.tv/2018/04/libreelec-krypton-8-2-5-mr)      |
| 8.2.4   | Stable | [Blog](https://libreelec.tv/2018/03/libreelec-krypton-8-2-4-mr)      |
| 8.2.3   | Stable | [Blog](https://libreelec.tv/2018/01/libreelec-krypton-8-2-3-mr)      |
| 8.2.2   | Stable | [Blog](https://libreelec.tv/2017/12/libreelec-krypton-8-2-2-mr)      |
| 8.2.1   | Stable | [Blog](https://libreelec.tv/2017/11/libreelec-krypton-v8-2-1-mr)     |
| 8.2.0   | Stable | [Blog](https://libreelec.tv/2017/10/libreelec-krypton-8-2-0-release) |
| 8.1.2   | Beta   | [Blog](https://libreelec.tv/2017/09/libreelec-krypton-v8-1-2-beta)   |
| 8.1.1   | Beta   | [Blog](https://libreelec.tv/2017/09/libreelec-krypton-v8-1-1-beta)   |
| 8.1.0   | Beta   | [Blog](https://libreelec.tv/2017/08/libreelec-krypton-v8-1-0-beta)   |

## 8.0 (Kodi v17, Krypton)

| Version  | Status | Release Post                                                           |
| -------- | ------ | ---------------------------------------------------------------------- |
| 8.0.2    | Stable | [Blog](https://libreelec.tv/2017/05/libreelec-krypton-v8-0-2-mr)       |
| 8.0.1    | Stable | [Blog](https://libreelec.tv/2017/03/libreelec-krypton-v8-0-1-mr)       |
| 8.0.0    | Stable | [Blog](https://libreelec.tv/2017/02/libreelec-krypton-v8-0-0-release)  |
| 7.95.3   | Beta   | [Blog](https://libreelec.tv/2017/02/libreelec-krypton-v7-95-3-beta)    |
| 7.95.2   | Beta   | [Blog](https://libreelec.tv/2017/02/libreelec-krypton-v7-95-2-beta)    |
| 7.95.1   | Beta   | [Blog](https://libreelec.tv/2017/01/libreelec-krypton-v7-95-1-beta)    |
| 7.90.010 | Alpha  | [Blog](https://libreelec.tv/2016/12/libreelec-krypton-v7-90-010-alpha) |
| 7.90.009 | Alpha  | [Blog](https://libreelec.tv/2016/12/libreelec-krypton-v7-90-009-alpha) |
| 7.90.008 | Alpha  | [Blog](https://libreelec.tv/2016/10/libreelec-krypton-v7-90-008-alpha) |
| 7.90.007 | Alpha  | [Blog](https://libreelec.tv/2016/10/libreelec-krypton-v7-90-007-alpha) |
| 7.90.006 | Alpha  | [Blog](https://libreelec.tv/2016/09/libreelec-krypton-v7-90-006-alpha) |

## 7.0 (Kodi v16, Jarvis)

| Version | Status | Release Post                                                         |
| ------- | ------ | -------------------------------------------------------------------- |
| 7.0.3   | Stable | [Blog](https://libreelec.tv/2016/12/libreelec-jarvis-v7-0-3-mr)      |
| 7.0.2   | Stable | [Blog](https://libreelec.tv/2016/06/libreelec-jarvis-v7-0-2-mr)      |
| 7.0.1   | Stable | [Blog](https://libreelec.tv/2016/05/libreelec-jarvis-v7-0-1)         |
| 7.0.0   | Stable | [Blog](https://libreelec.tv/2016/04/libreelec-jarvis-v7-0-0-release) |

## 6.0 - 1.0

LibreELEC releases start at 7.0.0 after the project forked from OpenELEC. The team chose to continue the existing numbering scheme.


# Forks

In 2015 the OpenELEC project team had a falling out with project founder @sraue over change management practices and maintenance of project infrastructure. Despite many months of talking and trying to resolve our differences, it became clear the founders vision for his hobby did not match everyone else's vision of being a project, and in March 2016 the codebase was forked and the "LibreELEC" project was born. The meaning of "Libre" in our name is "freedom" (to run the project as we like) not the Libre-software meaning, although the core project team are strong advocates for open-source code and we strive to manage the project along open-source principles.

Since we are ourselves a fork, the project team have always encouraged others to fork and (re)use our codebase as this helps to shake out issues in our build-system, and over time increases the number of people who contribute changes to it.

The following are known forks of our codebase:

| Name             | URL                    | Purpose      |
| ---------------- | ---------------------- | ------------ |
| Lakka (Libretro) | <https://lakka.tv>     | Retro Gaming |
| RetroELEC        | n/a                    | Retro Gaming |
| CoreELEC         | <https://coreelec.org> | Kodi         |


# Licenses


# Source Code

LibreELEC original code is licensed under the GPL v2.0

<https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html>


# Documentation

[Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](https://creativecommons.org/licenses/by-nc-sa/4.0/)

This is a human-readable summary of (and not a substitute for) the [license](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode)

You are free to:

> Share — copy and redistribute the material in any medium or format
>
> Adapt — remix, transform, and build upon the material

The licensor cannot revoke these freedoms as long as you follow the license terms.

Under the following terms:

> Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
>
> NonCommercial — You may not use the material for commercial purposes.
>
> ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
>
> No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.


# Mirrors

To provide a better download experience and offload bandwidth and hosting charges from the project, our main downloads (releases and installers) are distributed over a global network of volunteer mirror servers. The project is always interested in adding new mirrors to our pool, and we welcome offers of assistance!

If you would like to help, you should:

* Be an experienced provider of mirroring services
* Be able to sync with a frequency between 1-12 hours
* Be able to handle at least 100Mbit/sec of traffic with no bandwidth limits
* Be able to mirror for a long term period (years)

The majority of existing mirrors are Telco's, ISP's or Universities, and whilst this is not a fixed requirement, they are our preferred mirror partners as we need to trust the provider.

If you meet the criteria above please drop an email with the offer to <mirrors@libreelec.tv>

## Rsync Details

```
rsync://releases.libreelec.tv/releases
```

## Current Mirrors

| Country        | Mirror Provider                 | Mirror URL                                                                                                |
| -------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Australia      | Digital Pacific                 | [https://libreelec.mirror.digitalpacific.com.au](http://libreelec.mirror.digitalpacific.com.au)           |
| Belgium        | Belnet                          | [https://ftp.belnet.be/mirror/libreelec.tv](http://ftp.belnet.be/mirror/libreelec.tv)                     |
| Bulgaria       | Burgaslan                       | <http://mirrors.burgaslan.bg/libreelec>                                                                   |
| Czech Republic | Karneval                        | [https://mirror.karneval.cz/pub/linux/libreelec](http://mirror.karneval.cz/pub/linux/libreelec)           |
| France         | Reloumirrors                    | <http://libreelec.reloumirrors.net>                                                                       |
| Germany        | Friedrich-Alexander Universität | [https://ftp.fau.de/libreelec](http://ftp.fau.de/libreelec)                                               |
| Germany        | Heiko Richter                   | <http://ftp.heikorichter.name/libreelec>                                                                  |
| Germany        | RWTH Aachen University          | [https://ftp.halifax.rwth-aachen.de/libreelec](http://ftp.halifax.rwth-aachen.de/libreelec)               |
| Greece         | University of Crete             | [https://ftp.cc.uoc.gr/mirrors/linux/libreelec](http://ftp.cc.uoc.gr/mirrors/linux/libreelec)             |
| Netherlands    | NLUUG                           | [https://ftp.nluug.nl/pub/mediaplayer/libreelec](http://ftp.nluug.nl/pub/mediaplayer/libreelec)           |
| Netherlands    | Serverion                       | [https://mirror.serverion.com/libreelec](https://mirror.serverion.com)                                    |
| Netherlands    | WeAreTriple                     | [https://libreelec.mirror.wearetriple.com](http://libreelec.mirror.wearetriple.com)                       |
| Netherlands    | Weppel                          | <http://mirror.ehv.weppel.nl/libreelec>                                                                   |
| Portugal       | University of Porto             | [https://mirrors.fe.up.pt/pub/libreelec](http://mirrors.fe.up.pt/pub/libreelec)                           |
| Sweden         | University of Umea              | [https://ftp.acc.umu.se/mirror/libreelec.tv/releases](http://ftp.acc.umu.se/mirror/libreelec.tv/releases) |
| United Kingdom | UK2.net                         | <http://libreelec.mirrors.uk2.net/releases>                                                               |
| United Kingdom | University of Warwick           | [https://anorien.csc.warwick.ac.uk/mirrors/libreelec](http://anorien.csc.warwick.ac.uk/mirrors/libreelec) |
| United States  | Limestone Networks              | [https://mirror.lstn.net/libreelec](http://mirror.lstn.net/libreelec)                                     |
| United States  | Georgia Tech                    | <http://www.gtlib.gatech.edu/pub/LibreELEC>                                                               |

## Live Statistics

Mirrorbits supports detailed statistics on downloads and available mirrors. This information can be accessed by appending `?mirrorstats` or `?mirrorlist` to the download URL, e.g.

<https://releases.libreelec.tv/LibreELEC-RPi4.arm-10.0.1.img.gz?mirrorstats>

<https://releases.libreelec.tv/LibreELEC-RPi4.arm-10.0.1.img.gz?mirrorlist>

Global mirror statistics can be found here: <https://releases.libreelec.tv/mirrorstats>


