kodi-gbm遥控器控制

我现在在建设一个All in One一体机,HomeNAS里面并没有安装桌面系统,但可以运行kodi-gbm来直接使用hdmi视频输出,这样就可以将电视盒子的功能移植到NAS上了。
我有一个接收器的遥控器,这个遥控器在操作系统启动后默认是/dev/input/event1,我想实现的功能是,我可以按遥控器的电源键来启动kodi-gbm.service,而这个电源键并不会触发操作系统关机。

设计操作逻辑

第一步是处理遥控器的电源键命令。在不做任何处理的情况下,电源键的处理逻辑都是关机,所以,我们要设计一个程序来占用遥控器这个设备,让电源键这个按键信号直接让程序处理而不传给操作系统。当遇到电源键信号的时候,唤醒kodi-gbm.service并停止这个程序,因为接下来遥控器的信号要转交给kodi。

那么,kodi在关闭的时候,要想办法重新唤醒这个遥控器监听程序,以实现可重复操作的逻辑。

设计监听程序

那么现成的这种监听功能就是evtest。所以,我们可以写一个systemd unit来作为kodi没有启动时的遥控器监听程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
# /etc/systemd/system/input-listener.service
[Unit]
Description=Listen for KEY_POWER events on /dev/input/event1
After=multi-user.target

[Service]
Type=simple
ExecStart=/bin/bash -c "/usr/bin/evtest --grab /dev/input/event1 | grep --line-buffered 'KEY_POWER.*value 1' | /usr/bin/systemd-cat -t key_power_event"
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

这一个systemd unit会直接占用遥控器设备,处理遥控器按键信号,并将电源键信号KEY_POWER输出到journal日志。

接下来设计一个service来监听日志,当日志中出现了关键字就启动kodi-gbm.service

1
2
3
4
5
6
7
8
9
10
11
12
13
# /etc/systemd/system/kodi-keypower-trigger.service
[Unit]
Description=Listen to key_power_event logs and restart kodi-gbm.service
After=multi-user.target

[Service]
Type=simple
ExecStart=/bin/bash -c 'journalctl -n0 -f -t key_power_event | while read -r line; do systemctl restart kodi-gbm.service; systemctl stop input-listener.service; done;'
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

修改kodi-gbm

kodi-gbm.service也需要修改,要让它在退出(exit/failure)的时候重启启动我们的电源键监听程序。可以利用OnFailure这个字段,但是这个字段并不能直接填input-listener.service,是的,这就是systemd的逻辑限制,所以,我另外写一个input-listener.service启动器服务

1
2
3
4
5
6
7
8
9
10
11
# /etc/systemd/system/input-listener-restart.service
[Unit]
Description=Restart the input listener service
After=input-listener.service

[Service]
Type=oneshot
ExecStart=/bin/systemctl start input-listener.service ; echo 'restart input-listener.service finished.'

[Install]
WantedBy=multi-user.target

然后修改kodi-gbm.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# /usr/lib/systemd/system/kodi-gbm.service
[Unit]
Description=Kodi standalone (GBM)
After=remote-fs.target systemd-user-sessions.service network-online.target nss-lookup.target sound.target bluetooth.target polkit.service upower.service mysqld.service lircd.service
Wants=network-online.target polkit.service upower.service
Conflicts=getty@tty1.service
# new line here
OnFailure=input-listener-restart.service

[Service]
User=kodi
Group=kodi
EnvironmentFile=-/etc/conf.d/kodi-standalone
SupplementaryGroups=input
PAMName=login
TTYPath=/dev/tty1
ExecStart=/usr/bin/kodi-standalone --audio-backend=alsa
ExecStop=/usr/bin/killall --exact --wait kodi.bin
#ExecStopPost=/usr/bin/systemctl start kodi-keypower-trigger.service
Restart=on-abort
StandardInput=tty
StandardOutput=journal

[Install]
Alias=display-manager.service

生效方法

命令:
systemctl enalbe kodi-keypower-trigger.service --now
systemctl enable input-listener.service --now

这样就行,开机后按遥控器电源键会启动kodi-gbm,然后input-listener.service会被自动stop。看完影视后,在kodi里面也是可以通过电源键关闭kodi应用程序的。在关闭的时候会触发input-listener-restart.service这个服务,这个服务是一次性的,它会启动input-listener服务。这样就回到了开机时的状态了,可以再使用电源键打开kodi。完美闭环。(虽然是一个非常潦草没那么优雅的启动逻辑。但是够用了,给家人简单培训下也能很容易懂。)