在 Linux 上通过 console 播放音频

工作中有项目使用 jfxLinux 运行。有需求需要播放音频。

默认的 jfx 播放音频需要 javafx.media。很不幸,mvn 中央仓库中的版本相对于我们目标机来说版本太高了。只能自己编译。

在经过一系列折腾后,我认命地发现我无法正确编译 javafx.media。最终的报错信息如下:

> Task :media:buildLinuxGStreamer FAILED
make: Entering directory '/code/jfx22/modules/javafx.media/src/main/native/gstreamer/projects/linux/gstreamer-lite'
gcc -fPIC -Wformat -Wextra -Wformat-security -fstack-protector -Werror=implicit-function-declaration -Werror=trampolines -Werror=deprecated-declarations -D_GNU_SOURCE -DGST_REMOVE_DEPRECATED -DGSTREAMER_LITE -DHAVE_CONFIG_H -DOUTSIDE_SPEEX -DLINUX -DGST_DISABLE_GST_DEBUG -DGST_DISABLE_LOADSAVE -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_48 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_48 -ffunction-sections -fdata-sections -Os -I../../../plugins -I../../../gstreamer-lite/projects/build/linux/common -I../../../gstreamer-lite/gstreamer -I../../../gstreamer-lite/gstreamer/libs -I../../../gstreamer-lite/gstreamer/gst/parse -I../../../gstreamer-lite/gst-plugins-base -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/projects/plugins -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst/isomp4 -I../../../gstreamer-lite/gst-plugins-bad/gst-libs -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -c ../../../gstreamer-lite/gstreamer/gst/gst.c -o /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gst.o
gcc -fPIC -Wformat -Wextra -Wformat-security -fstack-protector -Werror=implicit-function-declaration -Werror=trampolines -Werror=deprecated-declarations -D_GNU_SOURCE -DGST_REMOVE_DEPRECATED -DGSTREAMER_LITE -DHAVE_CONFIG_H -DOUTSIDE_SPEEX -DLINUX -DGST_DISABLE_GST_DEBUG -DGST_DISABLE_LOADSAVE -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_48 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_48 -ffunction-sections -fdata-sections -Os -I../../../plugins -I../../../gstreamer-lite/projects/build/linux/common -I../../../gstreamer-lite/gstreamer -I../../../gstreamer-lite/gstreamer/libs -I../../../gstreamer-lite/gstreamer/gst/parse -I../../../gstreamer-lite/gst-plugins-base -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/projects/plugins -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst/isomp4 -I../../../gstreamer-lite/gst-plugins-bad/gst-libs -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -c ../../../gstreamer-lite/gstreamer/gst/gstallocator.c -o /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstallocator.o
gcc -fPIC -Wformat -Wextra -Wformat-security -fstack-protector -Werror=implicit-function-declaration -Werror=trampolines -Werror=deprecated-declarations -D_GNU_SOURCE -DGST_REMOVE_DEPRECATED -DGSTREAMER_LITE -DHAVE_CONFIG_H -DOUTSIDE_SPEEX -DLINUX -DGST_DISABLE_GST_DEBUG -DGST_DISABLE_LOADSAVE -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_48 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_48 -ffunction-sections -fdata-sections -Os -I../../../plugins -I../../../gstreamer-lite/projects/build/linux/common -I../../../gstreamer-lite/gstreamer -I../../../gstreamer-lite/gstreamer/libs -I../../../gstreamer-lite/gstreamer/gst/parse -I../../../gstreamer-lite/gst-plugins-base -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/projects/plugins -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst/isomp4 -I../../../gstreamer-lite/gst-plugins-bad/gst-libs -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -c ../../../gstreamer-lite/gstreamer/gst/gstatomicqueue.c -o /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstatomicqueue.o
gcc -fPIC -Wformat -Wextra -Wformat-security -fstack-protector -Werror=implicit-function-declaration -Werror=trampolines -Werror=deprecated-declarations -D_GNU_SOURCE -DGST_REMOVE_DEPRECATED -DGSTREAMER_LITE -DHAVE_CONFIG_H -DOUTSIDE_SPEEX -DLINUX -DGST_DISABLE_GST_DEBUG -DGST_DISABLE_LOADSAVE -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_48 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_48 -ffunction-sections -fdata-sections -Os -I../../../plugins -I../../../gstreamer-lite/projects/build/linux/common -I../../../gstreamer-lite/gstreamer -I../../../gstreamer-lite/gstreamer/libs -I../../../gstreamer-lite/gstreamer/gst/parse -I../../../gstreamer-lite/gst-plugins-base -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/projects/plugins -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst/isomp4 -I../../../gstreamer-lite/gst-plugins-bad/gst-libs -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -c ../../../gstreamer-lite/gstreamer/gst/gstbin.c -o /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstbin.o
gcc -fPIC -Wformat -Wextra -Wformat-security -fstack-protector -Werror=implicit-function-declaration -Werror=trampolines -Werror=deprecated-declarations -D_GNU_SOURCE -DGST_REMOVE_DEPRECATED -DGSTREAMER_LITE -DHAVE_CONFIG_H -DOUTSIDE_SPEEX -DLINUX -DGST_DISABLE_GST_DEBUG -DGST_DISABLE_LOADSAVE -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_48 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_48 -ffunction-sections -fdata-sections -Os -I../../../plugins -I../../../gstreamer-lite/projects/build/linux/common -I../../../gstreamer-lite/gstreamer -I../../../gstreamer-lite/gstreamer/libs -I../../../gstreamer-lite/gstreamer/gst/parse -I../../../gstreamer-lite/gst-plugins-base -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/projects/plugins -I../../../gstreamer-lite/gst-plugins-base/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst-libs -I../../../gstreamer-lite/gst-plugins-good/gst/isomp4 -I../../../gstreamer-lite/gst-plugins-bad/gst-libs -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -c ../../../gstreamer-lite/gstreamer/gst/gstbuffer.c -o /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstbuffer.o
In file included from ../../../gstreamer-lite/gstreamer/gst/gst.c:100:
../../../gstreamer-lite/gstreamer/gst/gst_private.h:28:12: fatal error: config.h: No such file or directory
28 | # include "config.h"
| ^~~~~~~~~~
In file included from ../../../gstreamer-lite/gstreamer/gst/gstbin.c:135:
../../../gstreamer-lite/gstreamer/gst/gst_private.h:28:12: fatal error: config.h: No such file or directory
28 | # include "config.h"
| ^~~~~~~~~~
compilation terminated.
compilation terminated.
In file included from ../../../gstreamer-lite/gstreamer/gst/gstatomicqueue.c:23:
../../../gstreamer-lite/gstreamer/gst/gst_private.h:28:12: fatal error: config.h: No such file or directory
28 | # include "config.h"
| ^~~~~~~~~~
compilation terminated.
make: *** [Makefile:281: /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gst.o] Error 1
make: *** Waiting for unfinished jobs....
make: *** [Makefile:281: /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstbin.o] Error 1
../../../gstreamer-lite/gstreamer/gst/gstallocator.c:45:10: fatal error: config.h: No such file or directory
45 | #include "config.h"
| ^~~~~~~~~~
compilation terminated.
make: *** [Makefile:281: /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstatomicqueue.o] Error 1
In file included from ../../../gstreamer-lite/gstreamer/gst/gstbuffer.c:121:
../../../gstreamer-lite/gstreamer/gst/gst_private.h:28:12: fatal error: config.h: No such file or directory
28 | # include "config.h"
| ^~~~~~~~~~
compilation terminated.
make: *** [Makefile:281: /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstallocator.o] Error 1
make: *** [Makefile:281: /code/jfx22/modules/javafx.media/build/native/linux/Release/obj/gstreamer-lite/gstreamer/gst/gstbuffer.o] Error 1
make: Leaving directory '/code/jfx22/modules/javafx.media/src/main/native/gstreamer/projects/linux/gstreamer-lite'

FAILURE: Build failed with an exception.

* Where:
Build file '/code/compubdev/jfx22/build.gradle' line: 3055

死心,另寻他途。一个可行的办法是通过 console 程序播放音频。这样就可以通过 java 调用 console 程序播放音频了。

可选命令:

  • paplay: pulseaudio 音频库的命令行版本。
  • pw-play: pipewire 音频库的命令行版本。
  • aplay: alsa 音频库的命令行版本。
  • ffplay: ffmpeg 的命令行版本。
  • cvlc: vlc 播放器的命令行版本。
  • play: sox 音频播放工具的命令行版本。

经过评估,paplay/pw-play 作为音频库的附属工具,只要音频库安装了,就会附带,不需要额外安装。而其他都需要安装,都会增加额外的依赖。

最终方案

启动时添加校验测试代码

  1. 检查 /usr/bin/pacat 是否存在,如果存在,则使用 paplay 播放音频,存为目标执行命令。
  2. 如果不存在,则检查 /usr/bin/pw-cat 是否存在,如果存在,则使用 pw-play 播放音频,存为目标执行命令。
  3. 如果不存在,弹框提示用户安装需要的音频库。

需要播放时,读取目标执行命令,执行命令。至此,完美规避 javafx.media 播放音频的编译问题。