我已经设置了一个 systemd 服务文件来在系统启动时执行一些 pactl 操作以进行测试过程。虽然从终端执行这些命令时工作正常,但通过启动服务从 systemd 服务运行相同的脚本时,我总是收到“pa_context_connect() 连接失败被拒绝”的消息。我还在服务文件中使用“User=”指令来确保自动登录用户与用于运行服务命令的用户匹配。
我读到这在某种程度上与pulseaudio会话在systemd服务的无环境上下文中无效有关,但我无法进一步弄清楚这一点。
尽管对于您可能正在从事的任何项目来说可能有点晚了,但这就是我发现的。
常规的systemctl,PID为1,在启动服务时确实无法访问当前用户的环境变量。由于 pactl 依赖这些变量来查找它需要连接到的pulseaudio 实例,因此当通过服务启动时它无法这样做。我确信有一个相当肮脏的解决方法,但我找到了更好的方法。
大多数系统都有第二个 systemd 实例在用户空间中运行(可以通过
systemctl --user
访问,但不以 root 身份连接)。该实例确实可以访问所有用户空间环境变量,并且我发现 pactl 在直接调用或通过脚本调用时不会返回任何错误。
您需要做的就是将服务放入
/usr/lib/systemd/user/
、/etc/systemd/user/
或 ~/.config/systemd/user/
,从服务文件中删除 User=
指令并以普通用户身份运行 systemctl --user daemon-reload
以确保它们已被发现了。
在我看来,将守护进程移至用户服务是确保消除横向麻烦的最佳方法。
尽管如此,在我的用例中,我仍然不确定这是一个好方法。所以我寻找 PulseAudio 缺少的环境变量。
看来只需要一个,那就是
XDG_RUNTIME_DIR
。
然后,只需在
[Service]
部分添加此行:
Environment=XDG_RUNTIME_DIR=/run/user/1000
在我的例子中,1000 是我的服务用户的用户 ID。您可以通过在以服务用户身份登录的 shell 中输入命令
id
来获取您的服务。
如果这不是您可以连接的用户,只需检查第三列
/etc/passwd
中的号码。
以我为例,我有这样一行:
anc:x:1000:1000:,,,:/home/anc:/bin/bash
这是第一个
1000
,在x
之后。