javadockeraudiodevicemixer

How can a containerized JAR (Java) access the default system mixer?


I previously took this question down, it's going back up since it's still a problem we're encountering. We have a JAR that we're resurrecting from three years ago. Back then (before I joined the project), it ran bare-metal (presumably on an RPM-based Linux distribution). Before a developer left, he had containerized it (CentOS7) and left us with very little documentation.

Ultimately, the JAR is calling the function getSourceDataLine() described here: https://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/AudioSystem.html#getSourceDataLine(javax.sound.sampled.AudioFormat)

The returned line will be provided by the default system mixer, or, if not possible, by any other mixer installed in the system that supports a matching SourceDataLine object.

However, the program encounters an IllegalArgumentException

if the system does not support at least one source data line supporting the specified audio format through any installed mixer

java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_SIGNED 8000.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported.  
at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:479)  
at javax.sound.sampled.AudioSystem.getSourceDataLine(AudioSystem.java:606)  

I inspected the contents of the sound.properties file: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64/jre/lib/sound.properties inside the container and ./jvm/java-1.8.0-openjdk-1.8.0.322.b06-2.el8_5.x86_64/jre/lib/sound.properties on the host. Both are completely commented/empty, so I assume the default system mixer is being used.

In the docker/docker-compose run parameters, I tried adding all capabilities to the Linux container, and that did not resolve the issue (regardless of permissions, I assume the needed sound card device doesn't appear at all).

I suspected there was a --device flag that could be passed to the docker run command (or docker-compose yaml). However, I tried running the container as privileged (access to all host devices), and this did not allow access to a system mixer.

I may try inspecting the devices available to the Java runtime with code similar to here: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4269230

I have heard "audio is difficult in containers". I may try doing full virtualization with QEMU to to try to recreate the host environment, but that seems a little drastic. If anyone has worked with the Java audio system as well as containers and could point me in the right direction, that would be much appreciated.


Solution

  • In Linux accessing the audio devices is all done via the filesystem. So if you mount the necessary files (/dev/audio?) into the container and give suitable privileges you should be good to go.