I tried to come up with the simplest possible way of writing a Java class that can play mp3 and ogg files, using standard Java Sound APIs, with purely Open Source libraries from the public Maven Central repositories.
The LGPL-licensed mp3spi and vorbisspi libraries from javazoom.net satisfy these requirements and worked for me right away. As service provider implementations (SPI), they transparently add support for the mp3 and ogg audio formats to javax.sound.sampled, simply by being in the classpath.
For my AudioFilePlayer class below I basically took the example code from javazoom and simplified it as much as possible. Please note that it requires Java 7 as it uses try-with-resources.
Maven dependencies
<!-- We have to explicitly instruct Maven to use tritonus-share 0.3.7-2 and NOT 0.3.7-1, otherwise vorbisspi won't work. --> <dependency> <groupId>com.googlecode.soundlibs</groupId> <artifactId>tritonus-share</artifactId> <version>0.3.7-2</version> </dependency> <dependency> <groupId>com.googlecode.soundlibs</groupId> <artifactId>mp3spi</artifactId> <version>1.9.5-1</version> </dependency> <dependency> <groupId>com.googlecode.soundlibs</groupId> <artifactId>vorbisspi</artifactId> <version>1.0.3-1</version> </dependency>
AudioFilePlayer.java
package net.doepner.audio; import java.io.File; import java.io.IOException; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine.Info; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; import static javax.sound.sampled.AudioSystem.getAudioInputStream; import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED; public class AudioFilePlayer { public static void main(String[] args) { final AudioFilePlayer player = new AudioFilePlayer (); player.play("something.mp3"); player.play("something.ogg"); } public void play(String filePath) { final File file = new File(filePath); try (final AudioInputStream in = getAudioInputStream(file)) { final AudioFormat outFormat = getOutFormat(in.getFormat()); final Info info = new Info(SourceDataLine.class, outFormat); try (final SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info)) { if (line != null) { line.open(outFormat); line.start(); stream(getAudioInputStream(outFormat, in), line); line.drain(); line.stop(); } } } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) { throw new IllegalStateException(e); } } private AudioFormat getOutFormat(AudioFormat inFormat) { final int ch = inFormat.getChannels(); final float rate = inFormat.getSampleRate(); return new AudioFormat(PCM_SIGNED, rate, 16, ch, ch * 2, rate, false); } private void stream(AudioInputStream in, SourceDataLine line) throws IOException { final byte[] buffer = new byte[65536]; for (int n = 0; n != -1; n = in.read(buffer, 0, buffer.length)) { line.write(buffer, 0, n); } } }
Thank you for this (relatively) simple example.
I am an absolute beginner with Java and I learned that Java can play .Wav files as standard but I was more interested in playing an MP3 file.
I managed to play an mp3 track using this code.
But I had to find out about how to make Maven projects.
And also I had to add some plug in as found here (to make compilation work): “https://stackoverflow.com/questions/20806470/resource-specification-not-allowed-here-for-source-level-below-1-7”
org.apache.maven.plugins
maven-compiler-plugin
2.5.1
1.7
1.7
And to make that work I had to write that code in between this code:
https://maven.apache.org/guides/mini/guide-configuring-plugins.html
I wish there was more comments explaining what actually happens in the program.
But I guess it reads the file piece by piece and plays it as it goes along?
It feels like (although this was a fun experiment) it is a bit sad that the program seems completely occupied while the song is playing.
How hard would it be to make a program that can do other things while the music / sound plays?
I mean it as an honest question!
I am not just saying “how hard could it be!”
Cause I really do not have any feeling for how hard it would be. :p
Sorry about the late approval of your comment. I am responding now because I just noticed and approved it.
I think when I needed to play audio in the background I wrapped the call to “play” in a new Thread.
Yes!
Thank you! =)
Yes, I guess when I wrote my comment I did not yet know about threads! ^^
The code does not paly MP3 or OGG files (issues “UnsupportedAudioFileException”). It only plays WAV files … which you do not include!! How lame this is!
It works for me and other people. I am usually quite willing to help people. If you calm down and ask nicely then maybe I’ll help you troubleshoot your problem.
hi,the code cannot play the mp3 file, it just can play the wav file. if play mp3 file,it shows Exception like this: Exception in thread “main” java.lang.IllegalStateException: javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
Are you sure you have the dependencies in your pom.xml and are running the code with those libraries in the classpath? Without tritonus-share and mp3spi in your classpath, the JVM won’t be able to find an implementation for MP3 decoding.
xception in thread “main” java.lang.IllegalStateException: javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
at net.doepner.audio.AudioFilePlayer.play(AudioFilePlayer.java:48)
at net.doepner.audio.AudioFilePlayer.main(AudioFilePlayer.java:21)
Caused by: javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1189)
at net.doepner.audio.AudioFilePlayer.play(AudioFilePlayer.java:28)
… 1 more
i am getting these errors please help me dude!
What file are you trying to play? mp3 or wav? If it was a wav file, check out this: https://stackoverflow.com/questions/14943962/java-wav-file-error-javax-sound-sampled-unsupportedaudiofileexception-could-no
Hi, I am doing an AWS blog post on the new Polly API and I would like to use your class here. Do you mind if I cross reference your blog? Thanks, Nick
Sure, go ahead. The code is nothing too special, I consider it public domain, so no need to worry about copyright. :)
Thank you it’ll be helpful
Is there any way to play more than one file at a time? Even if I put it in another thread it doesn’t work.. =T
You shouldn’t need threads for concurrent audio. It might be a matter of your audio setup. If you are on Linux, make sure you have Pulseaudio installed. What Operating system are you using?
Sure. Do you have email?
Yes. See http://oliver.doepner.net/.
Hi Oliver can´t stopAll()…!!! Why?
Can you explain more what your problem is?
But how can I stop it when I want ?
Take a look at the stopAll() method in the three Player classes here:
https://github.com/guppy4j/libraries/tree/master/sound-impl/src/main/java/org/guppy4j/sound
If the audio resource is to be packed inside a jar, you would use URL instead of File. Also, you would use a relative address. Common practice: make a subfolder to the folder of the source code, named “audio”. Then invoke via:
URL url = this.getClass().getResource(“./audio/yourMusicCue.wav”);
ais = AudioSystem.getAudioInputStream(url);
Yeah, that’s true. I have actually improved the code since I wrote that blog post, and it now works with URLs instead of file names. You can find it at: https://github.com/guppy4j/libraries/tree/master/sound-impl/src/main/java/org/guppy4j/sound
My ears prefer AAC to Ogg Vorbis and MP3. I would be grateful if you would add the ability to play M4A/AAC files to your Java music player.
Thanks for the comment, Ben!
I might try adding http://sourceforge.net/projects/jaadec/ into the mix. Cannot promise anything though, since my time for working on this is limited. :o)
Related question: What do you think about FLAC ?
Thanks for the simplifications! Just one more question! In which folder should the audio file be saved, in order not to throw exception?
You can save the file anywhere. Just make sure you pass the full path to the play(..) method. For example:
player.play(“C:\Temp\something.mp3”);
Thanks for the reply!