Search code examples
javaaudiojavasoundjavax.sound.sampled

Any supported sound formats for Java on Windows 7?


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.


Solution

  • After figuring out it was a problem with our JNI code doing this:

    rc=CoInitialize(NULL);
    rc=OleInitialize(NULL);
    {
         WNDCLASSEX     wc; 
         // Register the class of our window to host the browser. 'WindowProc' is our message handler
     // and 'ClassName' is the class name. You can choose any class name you want.
     ZeroMemory(&wc, sizeof(WNDCLASSEX));
     wc.cbSize = sizeof(WNDCLASSEX);
     wc.hInstance = hinstance;
     wc.lpfnWndProc = WindowProc;
     wc.lpszClassName = &ClassName[0];
     rc=RegisterClassEx(&wc);
    }
    

    It was a problem because we were calling it in the wrong place in dllMain(...). Instead, we moved it into the place where it is only called once, right before it is actually needed to open an embedded browser.

    This resolved our problem.