systemd integration for kodi & emulationstation
-
Hello,
I'd like to share a few systemd service definitions that enable running kodi & emulationstation back to back.
To use these services:
- Disable the existing entries in
/opt/retropie/configs/all/autostart.sh
(which is what retropie typically uses to run those). - Install the
fbset
package.
How the services are supposed to work:
- Kodi runs after boot by default, which is defined via the following systemd link:
# ls -la /etc/systemd/system/multi-user.target.wants/kodi.service lrwxrwxrwx 1 root root 32 Aug 18 2021 /etc/systemd/system/multi-user.target.wants/kodi.service -> /etc/systemd/system/kodi.service
It may be modified to run emulationstation by removing the above link to kodi and adding one pointing to emulationstation.service:
lrwxrwxrwx 1 root root 32 Aug 18 2021 /etc/systemd/system/multi-user.target.wants/emulationstation.service -> /etc/systemd/system/emulationstation.service
- Kodi service definition. Of note, the service intentionally conflicts with emulationstation on purpose, rendering the startup of both impossible.
On kodi shut down, the service will start emulationstation.
Should kodi fail to start, a getty on the initial tty (tty1) is started. The getty definition is included below. The pulseaudio related parts are relevant for starting pulseaudio (as a system-wide service) alongside kodi and may be commented out. Note this service sets original depth to allow restoring it easily by getty.
# cat /etc/systemd/system/kodi.service [Unit] Description=kodi After=pulseaudio.service BindsTo=pulseaudio.service Conflicts=emulationstation.service OnFailure=getty@tty1.service [Service] User=pi Environment=PULSE_SERVER=/run/pulse/native ExecStartPre=+sh -c 'fbset | grep -Pom1 "geometry.* \K[0-9]+$" | xargs -ri systemctl set-environment ORIGINAL_DEPTH={}' ExecStart=kodi-standalone ExecStopPost=+sh -c 'ip route show default | cut -f3 -d" " | xargs ping -c1 -w3 -q' ExecStopPost=+sh -c "systemctl start emulationstation && systemctl -q is-active emulationstation || systemctl start getty@tty1" StandardOutput=journal StandardError=journal TTYPath=/dev/tty1 [Install] WantedBy=multi-user.target
- Emulation station service. Likewise, it conflicts with kodi to prevent startup of both at the same time. On failure, it will run getty on tty1. On emulationstation shut down this service will run kodi.
# cat /etc/systemd/system/emulationstation.service [Unit] Description=emulationstation Conflicts=kodi.service OnFailure=getty@tty1.service [Service] User=pi ExecStart=/usr/bin/emulationstation ExecStopPost=+systemctl start kodi StandardOutput=journal StandardError=journal TTYPath=/dev/tty1 [Install] WantedBy=multi-user.target
- Additional drop-in: if no joypad is plugged in, emulationstation will not start. In which case, fall back to kodi. It isn't strictly necessary when you are ok with emulationstation starting without a joypad (but it might make you unable to control it without one).
It's particularly useful when there isn't any keyboard connected to your raspberry pi and the only controls are either the joypad (attached or not) and the CEC-driven input (a tv remote).
When emulationstation allows fall-back control via CEC input, this drop-in will be redundant.
# cat /etc/systemd/system/emulationstation.service.d/10_controls.conf [Unit] ConditionPathExists=|/dev/input/js0
To allow quitting to getty from kodi when the joypad is plugged in, create a /dev/shm/getty file (via ssh):
# cat /etc/systemd/system/emulationstation.service.d/10_force_getty.conf [Unit] ConditionPathExists=!/dev/shm/getty
- Mandatory TTY redirection for emulationstation. The problem here is emulationstation needs a tty for standard input. By default a service receives /dev/null for standard input. Without this service drop-in, emulationstation or emulators will face input problems. /dev/tty1 is normally owned by root so to grant direct access, it needs to be made world-writable:
# cat /etc/systemd/system/emulationstation.service.d/10_tty.conf [Service] TTYPath=/dev/tty1 StandardOutput=tty StandardInput=tty ExecStartPre=!chmod o+rw /dev/tty1
- Getty configuration, updated via drop-ins. Specific to the getty instance on tty1, gettys on other ttys are not impacted by these drop-ins.
Restores console depth post kodi (or emulationstation failure. If it fails, kodi will be started. On a log out from getty on tty1, it will run kodi.
# cat /etc/systemd/system/getty@tty1.service.d/post_kodi_failure.conf [Unit] OnFailure=kodi.service [Service] ExecStartPre=fbset -depth $ORIGINAL_DEPTH ## Commented out - detect if keyboard is attached and fail to run getty if none is found. However, when none found it has the side effect of leading to a failure of the service (systemd rev 246 in buster is missing the ConditionExec statement that doesn't fail a service) #ExecStartPre=sh -c 'grep -l 03 /sys/bus/*/*/*/bInterfaceClass | sed s/Class$$/Protocol/ | xargs grep -q 01' ExecStart= ExecStart=-/sbin/agetty --autologin pi --noclear %I $TERM ExecStopPost=+systemctl start kodi Restart=no
On a default raspbian build, getty is normally configured to run on boot. Since it will be either kodi or emulationstation that run on the console, getty startup on boot needs to be disabled. Getty will still run when kodi or emulationstation fail.
# ls -la /etc/systemd/system/multi-user.target.wants/getty.target lrwxrwxrwx 1 root root 9 May 11 10:47 /etc/systemd/system/multi-user.target.wants/getty.target -> /dev/null
- Getty service drop-in updates. Specific to the getty session on tty1. Do not run getty on tty1 when either kodi or emulationstation is active.
# cat /etc/systemd/system/getty@tty1.service [Unit] Conflicts="kodi.service emulationstation.service"
Ensure the console on tty1 is not cleared.
# cat /etc/systemd/system/getty@tty1.service.d/noclear.conf [Service] TTYVTDisallocate=no
I've had this running for quite some time and it works flawlessly.
These services capture kodi & emulationstation console output in the systemd journal, viewable via:
# journalctl -u emulationstation # journalctl -u kodi
One caveat of how these services operate is restarting one service twice brings up the other service. Other than that, in regular operation without systemctl restarts, the services run truly back to back.
[emulationstation running] # systemctl restart kodi [brings up kodi] # systemctl restart kodi Job for kodi.service canceled. [brings up emulationstation]
- Disable the existing entries in
-
mdx
-
mdx
-
mdx
Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.
Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.