How to play back audio in Java with examples
- Details
- Written by Nam Ha Minh
- Last Updated on 01 July 2019   |   Print Email
In this tutorial we’re going to understand how Java supports for playing audio with some interesting example programs.
Currently the Java Sound API supports playing back the following audio file format: AIFC, AIFF, AU, SND and WAVE. That means we cannot play the popular audio format MP3 with Java Sound API, so the examples will play with the WAVE format (.wav).
Generally, the Java Sound API (package: javax.sound) provides two ways for playing back audio: using a Clip and using a SourceDataLine. Each way has its own advantages and drawbacks. Let’s explore the details.
1. Playing back audio using a Clip
Use a Clip (javax.sound.sampled.Clip) when you want to play non-real-time sound data such as a short sound file. The whole file is pre-loaded into memory before playing back, therefore we have total control over the playback.
Advantages:
- It’s possible to start playing from any position in the sound (using either of the Clip’s methods setMicrosecondPosition(long)or setFramePosition(int)).
- It’s possible to repeatedly play (loop) all or a part of the sound (using the setLoopPoints(int, int) and loop(int) methods).
- It’s possible to know duration of the sound before playing (using the getFrameLength() or getMicrosecondLength() methods).
- It’s possible to stop playing back at the current position and resume playing later (using the stop() and start() methods).
Drawbacks:
- It’s not suitable and inefficient to play back lengthy sound data such as a big audio file because it consumes too much memory.
- The Clip’s start() method does playing the sound but it does not block the current thread (it returns immediately), so it requires to implement the LineListener interface to know when the playing completes. We’ll see how to do that in the examples.
Steps to play:
Following are the steps to implement code for playing back an audio file (typically in .wav format) using the Clip:
- Create an AudioInputStream from a given sound file:
File audioFile = new File(audioFilePath); AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
- Acquire audio format and create a DataLine.Infoobject:
AudioFormat format = audioStream.getFormat(); DataLine.Info info = new DataLine.Info(Clip.class, format);
- Obtain the Clip:
Clip audioClip = (Clip) AudioSystem.getLine(info);
- Open the AudioInputStream and start playing:
audioClip.open(audioStream); audioClip.start();
- Close and release resources acquired:
audioClip.close(); audioStream.close();
Java Audio Playback Example using Clip:
Here’s an example program that plays back a given audio file using the Clip:
package net.codejava.sound; 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.Clip; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineListener; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.UnsupportedAudioFileException; /** * This is an example program that demonstrates how to play back an audio file * using the Clip in Java Sound API. * @author www.codejava.net * */ public class AudioPlayerExample1 implements LineListener { /** * this flag indicates whether the playback completes or not. */ boolean playCompleted; /** * Play a given audio file. * @param audioFilePath Path of the audio file. */ void play(String audioFilePath) { File audioFile = new File(audioFilePath); try { AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile); AudioFormat format = audioStream.getFormat(); DataLine.Info info = new DataLine.Info(Clip.class, format); Clip audioClip = (Clip) AudioSystem.getLine(info); audioClip.addLineListener(this); audioClip.open(audioStream); audioClip.start(); while (!playCompleted) { // wait for the playback completes try { Thread.sleep(1000); } catch (InterruptedException ex) { ex.printStackTrace(); } } audioClip.close(); } catch (UnsupportedAudioFileException ex) { System.out.println("The specified audio file is not supported."); ex.printStackTrace(); } catch (LineUnavailableException ex) { System.out.println("Audio line for playing back is unavailable."); ex.printStackTrace(); } catch (IOException ex) { System.out.println("Error playing the audio file."); ex.printStackTrace(); } } /** * Listens to the START and STOP events of the audio line. */ @Override public void update(LineEvent event) { LineEvent.Type type = event.getType(); if (type == LineEvent.Type.START) { System.out.println("Playback started."); } else if (type == LineEvent.Type.STOP) { playCompleted = true; System.out.println("Playback completed."); } } public static void main(String[] args) { String audioFilePath = "E:/Test/Audio.wav"; AudioPlayerExample1 player = new AudioPlayerExample1(); player.play(audioFilePath); } }
In this program, the play() method implements all the above mentioned steps, and the current thread will wait till the playback completes. We make this class implements the LineListener interface in order to receive line events (OPEN, CLOSE, START and STOP) to know when the playback completes (a STOP event is fired). Specify a listener for the Clip as follows:
audioClip.addLineListener(this);
Where this is the current class that implements the LineListener interface:
public class AudioPlayerExample1 implements LineListener
And we have to override the update() method defined in the LineListener interface as follows:
@Override public void update(LineEvent event) { LineEvent.Type type = event.getType(); if (type == LineEvent.Type.START) { System.out.println("Playback started."); } else if (type == LineEvent.Type.STOP) { playCompleted = true; System.out.println("Playback completed."); } }
If the line event type is STOP, we set the flag playCompletedto true, so the current thread stops waiting and the program exits.
In addition, we can do the following things with the Clip:
- To know length (duration) of the sound:
int frameLength = audioClip.getFrameLength(); // length in frames long duration = audioClip.getMicrosecondLength(); // length in microseconds
You need to divide the duration in microseconds by one million to get the value in seconds.
- To specify the position to start playing back:
audioClip.setMicrosecondPosition(50_000_000); // start playing from the 50th second audioClip.setFramePosition(300_000); // start playing from the 300,000th frame
- To loop playing all the sound for 2 times:
audioClip.loop(2); // loop 2 times (total play 3 times)
- To loop a portion of the sound for 1 time:
// loop from frame 10,000th to frame 500,000th audioClip.setLoopPoints(10_000, 500_000); audioClip.loop(1);
- To stop playing back at the current position:
audioClip.stop();
To resume playing, call start() method again.
And all the above statements (except the stop()) should be called after audioClip.open() and before audioClip.start(), for example:
audioClip.open(audioStream); int frameLength = audioClip.getFrameLength(); System.out.println("Frame length = " + frameLength); long duration = audioClip.getMicrosecondLength(); System.out.println("Duration = " + (duration / 1_000_000) + " sec"); audioClip.setMicrosecondPosition(10_000_000); // start playing from the 10th second audioClip.loop(1); // loop 1 time audioClip.start();
2. Playing back using a SourceDataLine
Use a SourceDataLine (javax.sound.sampled.SourceDataLine) when you want to play a long sound file which cannot be pre-loaded into memory or to stream real-time sound data such as playing sound back as it’s being captured.
Advantages:
- It’s suitable and efficient to play back long sound file or to stream sound in real-time.
- It’s possible to control what sound data to be written to the audio line’s playback buffer.
- Unlike the Clip, we don’t have to implement the LineListener interface to know when the playback completes.
Drawbacks:
- Cannot start playing from an arbitration position in the sound.
- Cannot repeatedly play (loop) all or a part of the sound.
- Cannot stop and resume playing in the middle.
- Cannot know duration of the sound before playing.
Steps to play:
Following are the steps to implement code for playing back a sound file using the SourceDataLine:
- Obtain a SourceDataLine is similar to obtain a Clip:
File audioFile = new File(audioFilePath); AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile); AudioFormat format = audioStream.getFormat(); DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); SourceDataLine audioLine = (SourceDataLine) AudioSystem.getLine(info);
- Open and start the audio line:
audioLine.open(format); audioLine.start();
- Repeatedly read a chunk of bytes from the AudioInputStream and send it to the SourceDataLine’splayback buffer, until reaching end of the input stream:
int BUFFER_SIZE = 4096; byte[] bytesBuffer = new byte[BUFFER_SIZE]; int bytesRead = -1; while ((bytesRead = audioStream.read(bytesBuffer)) != -1) { audioLine.write(bytesBuffer, 0, bytesRead); }
- Close and release resources acquired:
audioLine.drain(); audioLine.close(); audioStream.close();
Java Playback Audio Example using DataSourceLine:
Here’s an example program that plays back a given audio file using the SourceDataLine:
package net.codejava.sound; 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; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; /** * This is an example program that demonstrates how to play back an audio file * using the SourceDataLine in Java Sound API. * @author www.codejava.net * */ public class AudioPlayerExample2 { // size of the byte buffer used to read/write the audio stream private static final int BUFFER_SIZE = 4096; /** * Play a given audio file. * @param audioFilePath Path of the audio file. */ void play(String audioFilePath) { File audioFile = new File(audioFilePath); try { AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile); AudioFormat format = audioStream.getFormat(); DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); SourceDataLine audioLine = (SourceDataLine) AudioSystem.getLine(info); audioLine.open(format); audioLine.start(); System.out.println("Playback started."); byte[] bytesBuffer = new byte[BUFFER_SIZE]; int bytesRead = -1; while ((bytesRead = audioStream.read(bytesBuffer)) != -1) { audioLine.write(bytesBuffer, 0, bytesRead); } audioLine.drain(); audioLine.close(); audioStream.close(); System.out.println("Playback completed."); } catch (UnsupportedAudioFileException ex) { System.out.println("The specified audio file is not supported."); ex.printStackTrace(); } catch (LineUnavailableException ex) { System.out.println("Audio line for playing back is unavailable."); ex.printStackTrace(); } catch (IOException ex) { System.out.println("Error playing the audio file."); ex.printStackTrace(); } } public static void main(String[] args) { String audioFilePath = "E:/Test/Audio.wav"; AudioPlayerExample1 player = new AudioPlayerExample1(); player.play(audioFilePath); } }
As we can see, this program is simpler than the Clip-based version, without having to implement the LineListener interface.
Related Java Sound Tutorials:
- How to capture and record sound using Java Sound API
- How to develop a sound recorder program in Java Swing
- Java sound record utility class
- Java audio player sample application in Swing
Other Java Tutorials:
- 10 Common Mistakes Every Beginner Java Programmer Makes
- 10 Java Core Best Practices Every Java Programmer Should Know
- How to become a good programmer? 13 tasks you should practice now
Comments
I'm using this code to play a audio. But I want the audio to start at certain time like 05:15 pm and 05:25 pm.
I am trying to develop basic music player initially later I would like to make recommendation based, as of now can you please tell me what should I do, cannot put on SOF as I have least idea about is so far.