I want to play sound in a Java Swing application. I referred to https://www.baeldung.com/java-play-sound and modify like this:
module-info.java
module sound {
requires java.desktop;
}
The source files are in the same folder [mydomain]/desktopproject/sound. There is a Swing JFrame with a JButton, when I press the button the following snippet runs until the last line throws a ClassCastException:
audioStream = AudioSystem.getAudioInputStream(new BufferedInputStream(
new FileInputStream(new File("/path-to-my.wav"))
));
AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
Clip audioClip = (Clip) AudioSystem.getLine(info);
The exception message is like this:
Exception in thread "AWT-EventQueue-0"
java.lang.ClassCastException: class com.sun.media.sound.DirectAudioDevice$DirectSDL
cannot be cast to class javax.sound.sampled.Clip
(com.sun.media.sound.DirectAudioDevice$DirectSDL
and javax.sound.sampled.Clip are in module java.desktop
of loader 'bootstrap')
I am not sure where the problem is. I use openjdk version "11.0.20" 2023-07-18 and when I ran java --list-module
, I got:
java.desktop@11.0.20
According to the documentation (here), the first argument of the DataLine.Info
constructor you are using is:
the class of the data line described by the info object
Then, according to the documentation of AudioSystem
's getLine
method (here):
Obtains a line that matches the description in the specified
Line.Info
object.
Also, DataLine.Info
is a Line.Info
, hence I assumed that the documentation of getLine
applies to DataLine.Info
as well. My assumption results mainly from OOP inheritance and trust in the implementation.
Finally, the error is a ClassCastException
, which indicates (and states) that the returned object by getLine
was not of type Clip
.
From the docs and the observation of the error and if the assumption is true and after searching similar usages to get inspired, one can maybe conclude that the first argument of DataLine.Info
constructor should be the type of object returned by getLine
. This is why I suggested in the comments of the question to try the following solution to this:
Change the following line of code:
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
to:
DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);
in order to obtain a instance of Clip
(which is a DataLine
, which is a Line
).
I didn't try it and I am not really familiar with javax.sound.sampled
package (hence a comment initially), but since you reported it worked, I figured it is an answer and wrote it here.