We'll, I've been beating my head against a wall trying to get Java to play some simple wav files without any luck. I've tried this code:
Clip clip = AudioSystem.getClip();
AudioInputStream inputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(soundBytes));
clip.open(inputStream);
clip.start();
This fails on "clip.open(...)" with the Exception:
javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian not supported.
And I've tried the more complicated (streaming version):
int BUFFER_SIZE = 128000;
AudioInputStream audioStream = null;
AudioFormat audioFormat;
SourceDataLine sourceLine = null;
try {
audioStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(soundBytes));
} catch (Exception e){
e.printStackTrace();
}
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();
} catch (Exception e) {
e.printStackTrace();
}
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();
This also fails on "sourceLine.open(...)" with the Exception:
javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian not supported.
I've tried two different wav files, including the venerable "tada.wav" that comes in C:\Windows\Media.
I also used GoldWave to change one of the files to unsigned 8 bit mono, but that only changed the error message to:
javax.sound.sampled.LineUnavailableException: line with format PCM_UNSIGNED 44100.0 Hz, 8 bit, mono, 1 bytes/frame, not supported.
Any thoughts on where I might be going wrong? Seems like playing a simple wave file should be simple, so I'm guessing I've gotten off in the weeds somewhere.
Thanks in advance.
UPDATE
So, the plot thickens. The code works fine if we move it into a separate stand alone java program. Something in our application must be cooking the Java's ability to play sounds.
Here is the stack trace for the above errors:
javax.sound.sampled.LineUnavailableException: line with format PCM_UNSIGNED 44100.0 Hz, 8 bit, mono, 1 bytes/frame, not supported.
at com.sun.media.sound.DirectAudioDevice$DirectDL.implOpen(DirectAudioDevice.java:492)
at com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:107)
at com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:139)
at com.hcs.orc.detail.SoundAddEdit.playButtonActionPerformed(SoundAddEdit.java:315)
at com.hcs.orc.detail.SoundAddEdit.access$100(SoundAddEdit.java:40)
at com.hcs.orc.detail.SoundAddEdit$2.actionPerformed(SoundAddEdit.java:225)
UPDATE 2
More interesting finds. It seems that we have a conflict when loading DLLs. We have our own DLL to help us do things (such as find a reliable and usable MAC Address). If you play a sound (which loads the sound related DLLs) before you load our DLL, then both work. However, if you our DLL and then try to play a sound, the sound gives you the errors reported above.
Anyone have any insight into why a seemingly unrelated DLL would cause another DLL to load incorrectly later?
As an entry for really lame and bad workarounds, we can play a fraction of a second of silence on start up before we look up the MAC address. This is bad form for several reasons including that many of our clients don't use sound at all.
UPDATE 3
Digging into our library, it seems the problem is caused by a call to RegisterClassEx(...). We do this so we can display an embedded IE window with our HTML help file.
An audio file format is a file format for storing digital audio data on a computer system. The bit layout of the audio data (excluding metadata) is called the audio coding format and can be uncompressed, or compressed to reduce the file size, often using lossy compression.
I've run into a similar issue before (though not in relation to loading DLLs.) Javasound works underneath by using 1 or more mixers, each with 1 or more lines. Each of those lines has a number of formats that it says it supports, but this doesn't mean it won't spontaneously combust when given that format to play (essentially, there's nothing stopping it from boasting about playing formats it can't.)
When you use AudioSystem.getLine()
, it will iterate over all these lines from all these mixers, and essentially return the first one it comes across that says it can handle that format. If that line is a big fat liar, then it won't look for others - it'll just go with it and produce the error that you're seeing.
Now the important thing to remember here is that the order it iterates over these lines is compeltely arbitrary. So anything could cause it to change, including something that seems seemingly irrelevant, such as loading a DLL. I can see one of two possibilities here, the DLL is somehow providing another audio line that's causing the issue, or loading the DLL just causes the arbitrary order to change, and when you do that it comes across the suspect line first for some reason.
The workaround isn't nice, but it's nicer than playing a sound and waiting a bit, you essentially have to test the line to see if it's telling the truth:
SourceDataLine dataline = null;
for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
try {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
dataline = (SourceDataLine)mixer.getLine(info);
if(dataline==null) {
continue; //Doesn't support this format
}
dataline.open(audioFormat);
dataline.start();
}
catch (Exception ex) {
//If we get here it's a buggered line, so loop round again
continue;
}
try {
dataline.close();
}
catch (Exception ex) {
ex.printStackTrace(); //Shouldn't get here
}
}
if(dataline==null) {
//No dataline capable of *really* playing the stream
}
else {
//We have a non-lying dataline!
}
This way takes a bit longer, but it's essentially a double check - we loop through each data line, and if it says it can play the format, we check if it really can - and only in that case do we then determine if it's safe to use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With