systemd integration for kodi & emulationstation
-
Hello,
UPDATED: 07/06/2022. Added
tvservice -c
entries fordispmanx_vnc
support. Some users may choose to run their RetroPie without a physical display overdispmanx_vnc
.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) or remove/etc/profile.d/10-retropie.sh
(which triggers/opt/retropie/configs/all/autostart.sh
) when logged in. - 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. Either comment them out or follow the guide for glitchless playback to install them. 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 # If screen is off, we enable it here (NTSC 4:3 is the default when no display is plugged in) ExecStartPre=sh -c 'tvservice -s | grep -v off || tvservice -c "NTSC 4:3"' # Record original depth to restore it later ExecStartPre=+sh -c 'fbset | grep -Pom1 "geometry.* \K[0-9]+$" | xargs -ri systemctl set-environment ORIGINAL_DEPTH={}' ExecStart=kodi-standalone StandardOutput=journal StandardError=journal TTYPath=/dev/tty1 [Install] WantedBy=multi-user.target
Drop-in that controls the service spawned after kodi service completes (successfully or not):
# cat /etc/systemd/system/kodi.service.d/quit_to_es.conf [Service] # Missing OnSuccess in systemd 241, quit to es or fall back to getty@tty1 ExecStopPost=+sh -c 'case $${EXIT_STATUS} in 0) systemctl start emulationstation;; *) systemctl start getty@tty1;; esac'
- Emulationstation 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 # getty@tty1 hogs /dev/tty1, preventing input to amiberry and the runcommand menu, we stop it if it is still running ExecStartPre=+sh -c 'systemctl is-active getty@tty1 && systemctl stop getty@tty1 || systemctl reset-failed getty@tty1' # Enable screen if it is still off ExecStartPre=sh -c 'tvservice -s | grep -v off || tvservice -c "NTSC 4:3"' ExecStart=/usr/bin/emulationstation ExecStopPost=+systemctl start kodi # Key part: ensure the emulationstation process owns /dev/tty1; without this runcommand input & output won't work StandardInput=tty-force StandardOutput=tty 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/require_controls.conf [Unit] ConditionPathExists=|/dev/input/js0
- Getty configuration, updated via drop-ins. Specific to the getty instance on tty1, gettys on other ttys are not impacted by these drop-ins.
# cat /etc/systemd/system/getty@tty1.service.d/post_kodi_failure.conf [Service] # Reset output if off, keep dispmanx_vnc on ExecStartPre=sh -c 'tvservice -s | grep -v off || tvservice -c "NTSC 4:3"' # Restores console after kodi depth changes ExecStartPre=-fbset -depth $ORIGINAL_DEPTH # Autologin to pi ExecStart= ExecStart=-/sbin/agetty --autologin pi --noclear %I $TERM # Stop all spawned processes including login to avoid hogging /dev/tty1 KillMode=control-group # Allow quitting to kodi or emulationstation 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
These two drop-ins control what happens when getty process finishes (or dies). They're numbered sequentially to indicate the parsing order for systemd. kodi runs by default. If emulationstation service exists, it replaces (note
OnFailureJobMode=replace
) kodi.The last service from
systemctl show
prevails:# systemctl show getty@tty1 | grep OnFailure OnFailure=kodi.service emulationstation.service OnFailureJobMode=replace
Admittedly, these drop-ins are a hack: systemd 241 from buster doesn't support starting a service when
getty@tty1
completes successfully other than by triggering a pretend failure. When a more recent systemd withOnSuccess
is available,ExecStopPost=false
may be removed andOnFailure
amended toOnSuccess
.# cat /etc/systemd/system/getty@tty1.service.d/01_quit_to_kodi.conf [Unit] OnFailure=kodi.service [Service] # Missing OnSuccess in systemd 241, triggers failure to run OnFailure process ExecStopPost=false
# cat /etc/systemd/system/getty@tty1.service.d/02_quit_to_es.conf [Unit] OnFailure=emulationstation.service # Replace other queued failure processes OnFailureJobMode=replace [Service] # Missing OnSuccess in systemd 241, triggers failure to run OnFailure process ExecStopPost=false
- 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.d/conflicts.conf [Unit] Conflicts=emulationstation.service kodi.service
Ensure the console on tty1 is not cleared.
# cat /etc/systemd/system/getty@tty1.service.d/noclear.conf [Service] TTYVTDisallocate=no
Do not run getty without a keyboard. It properly detects the
dispmanx_vnc
virtual keyboard.# cat /etc/systemd/system/getty@tty1.service.d/require_keyboard.conf [Service] ExecStartPre=sh -c 'grep -l 03 /sys/bus/*/*/*/bInterfaceClass | sed s/Class$$/Protocol/ | xargs grep -q 01 || grep -qi Keyboard /proc/bus/input/devices'
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
-
-
-
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.