NixOS/Linux上Minecraft无法初始化OpenAL

需求

  • HMCL启动器(测试版)
  • pipewire (或许要)
  • alsa-oss

故障

2023-03-30 更新: 最近开始学习制作Minecraft Mod(刚好大学课程也开始学Java),Modding框架是Fabric,使用的IDE是Intellj IDEA,通过fabric-loom生成的构建配置运行MC遇到了同样的问题,详情见后文。


从Windows迁移到Linux时留下了宝贵的Minecraft存档以及本体。虽然linux上有PolyMC,但是就连离线游玩都需要正版账号,惊讶发现原先使用的HMCL官方就有jar打包,故只需要java -jar即可运行,省了不少事(而且HMCL确实功能完备,操作简单,强推)

然而打开游戏发现没有声音,其他一切正常(包括Mod、光影、存档),打开日志发现错误所在:

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
26
27
28
29
30
31
[21:17:30] [Render thread/ERROR]: Error starting SoundSystem. Turning off sounds & music
java.lang.IllegalStateException: Failed to open OpenAL device
at net.minecraft.class_4225.method_38501(class_4225.java:283) ~[client-intermediary.jar:?]
at net.minecraft.class_4225.method_19661(class_4225.java:153) ~[client-intermediary.jar:?]
at net.minecraft.class_1140.method_4846(class_1140.java:113) ~[client-intermediary.jar:?]
at net.minecraft.class_1140.method_4837(class_1140.java:103) ~[client-intermediary.jar:?]
at net.minecraft.class_1144.method_18182(class_1144.java:112) ~[client-intermediary.jar:?]
at net.minecraft.class_1144.method_18788(class_1144.java:38) ~[client-intermediary.jar:?]
at net.minecraft.class_4080.method_18790(class_4080.java:13) ~[client-intermediary.jar:?]
at java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:718) ~[?:?]
at java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482) ~[?:?]
at net.minecraft.class_4014.method_18365(class_4014.java:69) ~[client-intermediary.jar:?]
at net.minecraft.class_1255.execute(class_1255.java:103) ~[client-intermediary.jar:?]
at net.minecraft.class_4014.method_18367(class_4014.java:68) ~[client-intermediary.jar:?]
at java.util.concurrent.CompletableFuture$UniCompletion.claim(CompletableFuture.java:572) ~[?:?]
at java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:714) ~[?:?]
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[?:?]
at java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614) ~[?:?]
at java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:726) ~[?:?]
at java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482) ~[?:?]
at com.mojang.blaze3d.systems.RenderSystem.replayQueue(RenderSystem.java:211) [client-intermediary.jar:?]
at com.mojang.blaze3d.systems.RenderSystem.flipFrame(RenderSystem.java:198) [client-intermediary.jar:?]
at net.minecraft.class_1041.method_15998(class_1041.java:315) [client-intermediary.jar:?]
at net.minecraft.class_310.method_1523(class_310.java:1205) [client-intermediary.jar:?]
at net.minecraft.class_310.method_1514(class_310.java:768) [client-intermediary.jar:?]
at net.minecraft.client.main.Main.method_44604(Main.java:244) [client-intermediary.jar:?]
at net.minecraft.client.main.Main.main(Main.java:51) [client-intermediary.jar:?]
at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:461) [fabric-loader-0.14.9.jar:?]
at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:74) [fabric-loader-0.14.9.jar:?]
at net.fabricmc.loader.impl.launch.knot.KnotClient.main(KnotClient.java:23) [fabric-loader-0.14.9.jar:?]

解决

2023-03-30 更新:

笔者最近编写Mod而IDEA的应用程序构建配置没有Wrapper Command,导致原来使用的 aoss 方法无效了,所以查了一下 aoss 的原理。原来就是把 LD_PRELOAD 环境变量加上 alsa-oss 包中的 lib/libaoss.so,于是乎直接在构建配置中的环境变量加上这个库即可(前提是安装了 alsa-oss 包)。

1
LD_PRELOAD=/nix/store/ajzicg9yc58j2wczlhyh6cypfbv3275g-alsa-oss-1.1.8/lib/libaoss.so

不过这种方法还是有点”dirty”,万一 LD_PRELOAD 原本就有值怎么办,IDEA这个环境变量设置疑似只能字面量定义不支持Shell Variable……但这大概是在NixOS这么另类的发布版上较好的解决方法了。

下面是原来的解决方法,适用于有办法在 java 命令前加个 Wrapper 的情况。


第一时间想到安装OpenAL包,无果,在网上搜索一番尝试了一些方法包括但不限于修改声音驱动配置文件等。

意识到OpenAL实在太过久远,可能现代的ALSA或者PulseAudio对其支持可能不是很好,再加上我用了最新的6.0内核可能会有兼容性的问题,于是乎我想到了更换音频服务器试试运气——pipewire注意,更换了以后并没有解决,详细往后看

NixOS上启用pipewire还算简单,只需在configuration.nix中添加:

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
26
27
28
29
30
31
32
33
34
35
# Pipewire config
# PulseAudio conflicts with Pipewire
hardware.pulseaudio.enable = false;
security.rtkit.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;

# Bluetooth support, selective.
media-session.config.bluez-monitor.rules = [
{
# Matches all cards
matches = [{ "device.name" = "~bluez_card.*"; }];
actions = {
"update-props" = {
"bluez5.auto-connect" = [ "hfp_hf" "hsp_hs" "a2dp_sink" ];
};
};
}
{
matches = [
# Matches all sources
{ "node.name" = "~bluez_input.*"; }
# Matches all outputs
{ "node.name" = "~bluez_output.*"; }
];
actions = {
"node.pause-on-idle" = false;
};
}
];
};

ArchLinux参考
https://wiki.archlinux.org/title/PipeWire

其他发行版参考官网
https://pipewire.org/

可以选择安装Helvum来监测音频节点之间的连接情况:

1
2
3
environment.systemPackages = [
pkgs.helvum
];

安装后重启系统,再次尝试,发现仍然没有声音,又在网络上搜索一番,发现一个叫做alsa-oss的音频兼容层:

aoss is a simple wrapper script which facilitates the use of the ALSA OSS compatibility library. It just sets the appropriate LD_PRELOAD path and then runs the command.

aoss <command> 可以让命令启动ALSA的OSS兼容,个人推测OpenAL可能是OSS的一部分,刚好HMCL提供了丰富的启动设置,我采用了包装命令,填入aoss,启动器即可在java命令之前加上这个命令。

这时再打开游戏,声音回来咯!Helvum也显示程序与输出正常连接~

注意:经过测试,pipewireaoss都是必需的!

原因推测

笔者本以为原因大概是:在Windows下下载的LWJGL不兼容Linux(至少是不兼容ALSA),需要通过一个兼容层。并且据同为NixOS用户的朋友所说,他使用PolyMC下载安装的Minecraft并未发生该问题,所以我之前认为这大概是迁移所带来的问题🤔

但是当我切换游戏目录,删除assets下所有内容,重新下载安装,问题仍然出现,所以我也很懵逼,大概率是我系统配置的问题了,未能找到根本原因,有点遗憾……

2023-03-30 更新:并非不兼容,而是因为NixOS非FHS,jdk找不到alsa库(