今天在利用JAVA3D播放聲音的時(shí)候,碰到一個(gè)很奇怪的問(wèn)題,那就是聲音設(shè)備無(wú)法初始化。它拋出如下異常:
java.lang.UnsupportedOperationException: No AudioDevice specified
但是教程上面包括SUN的例子里面都是這樣寫(xiě)的,他那樣寫(xiě)肯定有它的道理,他不可能寫(xiě)一個(gè)錯(cuò)誤的代碼吧?那心里就納悶了,為什么我的電腦就是播放不了呢,難道又像播放MIDI一樣,因?yàn)檠b了JMF的原因?我把JMF也缷了,電腦也重啟了,還是不行,該不會(huì)是人品問(wèn)題吧:(
后來(lái)查看錯(cuò)誤的調(diào)用順序,發(fā)現(xiàn)是這句話拋出了異常:
......
viewer.createAudioDevice();
......
也就是在生成音頻設(shè)備的時(shí)候,這個(gè)方法會(huì)生成并初始化好音頻設(shè)備,我們?cè)诓シ乓纛l的時(shí)候,一定需要調(diào)此方法的。
然后再看這句話里面的代碼,說(shuō)到這里,突然覺(jué)得用JAVA挺爽的,可以看到你用的類的JAVA的源碼,Viewver是JAVA3D里面的類,查看這個(gè)方法,發(fā)現(xiàn)這個(gè)方法如下:
if (physicalEnvironment == null) {
System.err.println("Java 3D: createAudioDevice: physicalEnvironment is null");
return null;
}
try {
String audioDeviceClassName =
(String) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
return System.getProperty("j3d.audiodevice");
}
});
if (audioDeviceClassName == null) {
throw new UnsupportedOperationException("No AudioDevice specified");
}
// Issue 341: try the current class loader first before trying the
// system class loader
Class audioDeviceClass = null;
try {
audioDeviceClass = Class.forName(audioDeviceClassName);
} catch (ClassNotFoundException ex) {
// Ignore excpetion and try system class loader
}
if (audioDeviceClass == null) {
ClassLoader audioDeviceClassLoader =
(ClassLoader) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
return ClassLoader.getSystemClassLoader();
}
});
if (audioDeviceClassLoader == null) {
throw new IllegalStateException("System ClassLoader is null");
}
audioDeviceClass = Class.forName(audioDeviceClassName, true,
audioDeviceClassLoader);
}
Class physEnvClass = PhysicalEnvironment.class;
Constructor audioDeviceConstructor =
audioDeviceClass.getConstructor(new Class[] {physEnvClass});
PhysicalEnvironment[] args = new PhysicalEnvironment[] { physicalEnvironment };
AudioEngine3DL2 mixer =
(AudioEngine3DL2) audioDeviceConstructor.newInstance((Object[])args);
mixer.initialize();
return mixer;
}
catch (Throwable e) {
e.printStackTrace();
physicalEnvironment.setAudioDevice(null);
System.err.println("Java 3D: audio is disabled");
return null;
}
}
然后再細(xì)看異常是在
if (audioDeviceClassName == null) {
throw new UnsupportedOperationException("No AudioDevice specified");
}
這一句拋出來(lái)的,而audioDeviceClassName 是通過(guò)System.getProperty("j3d.audiodevice");來(lái)獲得的,之所以會(huì)拋出這個(gè)異常,還是因?yàn)橄到y(tǒng)沒(méi)有j3d.audiodevice的屬性,后來(lái)我輸出System的所有Properties看了一下,果然沒(méi)有j3d.audiodevice的屬性,那就怪了,為什么我的電腦會(huì)沒(méi)有這個(gè)屬性呢?
后來(lái)才知道,本來(lái)這個(gè)屬性裝了JAVA3D以后都會(huì)有的,但是由于JAVA3D1.3發(fā)現(xiàn)了一個(gè)BUG,一個(gè)播放聲音的BUG,所以在后續(xù)的版本中把這個(gè)屬性去掉了,也就是不再讓人用JAVA3D來(lái)播放聲音了。我用的是JAVA3D1.5,所以就沒(méi)有這個(gè)屬性了,所以音頻設(shè)備也就初始化不了了。
那怎么樣呢?JAVA不裝這個(gè)屬性,我們自己指定就是了,于是在viewer.createAudioDevice();代碼調(diào)用之前,我調(diào)用如下代碼為它設(shè)置這個(gè)屬性,讓它可以自己找到音頻播放設(shè)備:
System.setProperty("j3d.audiodevice", "com.sun.j3d.audioengines.javasound.JavaSoundMixer");
這樣就好了,我們?cè)诓シ诺臅r(shí)候,使用的就是com.sun.j3d.audioengines.javasound.JavaSoundMixer來(lái)播放了,不過(guò),因?yàn)橛蠦UG的報(bào)道,所以用它播放可能會(huì)出現(xiàn)一些問(wèn)題,聽(tīng)說(shuō)現(xiàn)在JOAL正在努力解決這個(gè)問(wèn)題。讓我們共同期待吧。
JOAL的地址:https://joal.dev.java.net
JOGL的地址:https://jogl.dev.java.net
盡管千里冰封
依然擁有晴空
你我共同品味JAVA的濃香.