Error Playing Audio File from Java via Pulseaudio on Ubuntu

Java audio fails to play wav file in Linux

Looks like there are two separate issues involved here.

First, relying on AudioSystem.getClip() is not a good idea as basically there's no guarantee that the clip will be able to handle the specific format of the wav file. Instead, one of the following approaches should be used:

  • As suggested by @Dave: Loop through the available mixers and query if the target format is supported:

    URL url = getClass().getResource("drop.wav");
    AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
    AudioFormat format = audioInputStream.getFormat();
    DataLine.Info lineInfo = new DataLine.Info(Clip.class, format);

    Mixer.Info selectedMixer = null;

    for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
    Mixer mixer = AudioSystem.getMixer(mixerInfo);
    if (mixer.isLineSupported(lineInfo)) {
    selectedMixer = mixerInfo;
    break;
    }
    }

    if (selectedMixer != null) {
    Clip clip = AudioSystem.getClip(selectedMixer);
    [...]
    }
  • Or, as suggested by @egorlitvinenko, use AudioSystem.getLine(DataLine.Info) to get a line with the desired capabilities.

Both of the above approaches "should" work.

On top of that, there is an additional problem with PulseAudio, which is that there is a bug which may result in an "invalid format" exception even though the PulseAudio mixer can actually handle the format. This is described in the following bug reports (the second one contains workarounds):

  • https://icedtea.classpath.org/bugzilla/show_bug.cgi?id=3452 (my own)
  • https://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2915

How to play .wav files with java

Finally I managed to do the following and it works fine

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

public class MakeSound {

private final int BUFFER_SIZE = 128000;
private File soundFile;
private AudioInputStream audioStream;
private AudioFormat audioFormat;
private SourceDataLine sourceLine;

/**
* @param filename the name of the file that is going to be played
*/
public void playSound(String filename){

String strFilename = filename;

try {
soundFile = new File(strFilename);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}

try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}

audioFormat = audioStream.getFormat();

DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}

sourceLine.start();

int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
@SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}

sourceLine.drain();
sourceLine.close();
}
}

can IcedTea's Pulse Audio implementation of Java Sound be taken from OpenJDK and run on Sun Java

Here is a reference in an Ubuntu bug report to using the OpenJDK Pulse Audio implementation with the Sun JDK. I have not done it myself so cannot confirm if it works.

FreeTTS, Java, Linux: Workaround for LINE UNAVAILABLE: Format is ...

Hmm, I had better luck googling after asking the question, so...:
http://workorhobby.blogspot.com/2011/02/java-audio-freetts-line-unavailable.html
A big thanks to the author.

Update: Actually, this is not a nice workaround since it will keep FreeTTS on hold until the line is free.

FWIU, the mentioned patch had better solution - not demanding exclusive access or such.

Update: I've compiled a FreeTTS troubleshooting page.


A program based on FreeTTS, the free text-to-speech engine for Java, was getting occasional errors

"LINE UNAVAILABLE: Format is ..."

Turns out there is no Java Exception or other mechanism to detect this error that occurs inside the FreeTTS library. All you get is the message on System.out, so there is no good way to react programatically.

Workaround: Configure the FreeTTS audio player to attempt accessing the audio device more than once until it succeeds. In this example, a short delay of 0.1 seconds is used to not miss an opportunity to grab the audio device; we keep trying for 30 seconds:

System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.openFailDelayMs", "100");
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.totalOpenFailDelayMs", "30000");

If the audio device is permanently used by another program, there is of course no way to get access. Under Linux, this command will display the ID of the process that is currently holding the audio device, so you can then try to get rid of the offending program:

/sbin/fuser /dev/dsp

How can I make my Java application with audio play nice in Linux?

I fear that audio in Linux is a lost cause itself. But in this case, it really is a known Java Bug. You should try to figure out what sound architecture you are using. I think the default for Ubuntu is PulseAudio/ALSA. I'm not not sure about Kubuntu though.

There is a known workaround (I never tried it myself though).

It's also possible that some other applications you're running is exclusively using the soundcard, so make sure to test with different applications (i.e. applications that play nicely with others).



Related Topics



Leave a reply



Submit