8

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.

4

2 回答 2

4

我之前遇到过类似的问题(尽管与加载 DLL 无关。)Javasound 通过使用 1 个或多个混音器在下面工作,每个混音器有 1 或更多行。这些行中的每一行都有许多它说它支持的格式,但这并不意味着当它播放该格式时它不会自发燃烧(基本上,没有什么可以阻止它吹嘘它不能播放格式。 )

当您使用AudioSystem.getLine()时,它将遍历所有这些混音器的所有这些行,并基本上返回它遇到的第一个表示它可以处理该格式的行。如果那条线是一个大骗子,那么它就不会寻找其他人——它只会跟着它走,并产生你所看到的错误。

现在要记住的重要一点是,它遍历这些行的顺序是完全任意的。因此,任何事情都可能导致它发生变化,包括看似无关紧要的事情,例如加载 DLL。我可以在这里看到两种可能性之一,DLL 以某种方式提供了导致问题的另一条音频线,或者加载 DLL 只会导致任意顺序发生变化,并且当您这样做时,由于某种原因它首先遇到了可疑线。

解决方法不是很好,但它比播放声音并稍等片刻要好,您基本上必须测试线路以查看它是否在说真话:

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!
}

这种方式需要更长的时间,但它本质上是一个双重检查——我们循环遍历每条数据线,如果它说它可以播放该格式,我们检查它是否真的可以——​​只有在这种情况下,我们才能确定它是否安全使用。

于 2014-01-07T01:00:07.530 回答
0

在确定这是我们的 JNI 代码这样做的问题之后:

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);
}

这是一个问题,因为我们在 dllMain(...) 中的错误位置调用它。相反,我们将它移到只调用一次的地方,就在实际需要打开嵌入式浏览器之前。

这解决了我们的问题。

于 2014-01-08T19:49:04.760 回答