Java Audio Looping Guide: Using javax.sound.sampled

This article details the correct way to implement audio loop playback in Java, abandoning the deprecated `sun.audio` internal API in favor of the standard and powerful `javax.sound.sampled` package. The tutorial covers the basic infinite loop playback implementation, and how to manage audio playback in a separate thread to ensure that the background music continues to play even if the main thread ends, and provides complete code examples and considerations.
1. Java audio playback API selection: Say goodbye to sun.audio
When doing audio processing in Java, developers sometimes come across classes in the sun.audio package. However, the classes under the sun.* package are internal implementations of Oracle JDK and do not belong to the standard Java API. They may change or even be removed between different JDK versions, so they are strongly not recommended for use in production code.
For robust and cross-platform Java audio playback requirements, the javax.sound.sampled package is officially recommended. This package provides rich functionality, including audio input, output, mixing, and support for various audio formats.
2. Use javax.sound.sampled to implement audio loop playback
The Clip interface in the javax.sound.sampled package is the key to realizing audio loop playback. Clip represents a special data line that can load the entire audio data into memory and play it.
2.1 Core concepts
- AudioSystem : Responsible for obtaining audio input streams, audio lines (such as Clip), etc.
- AudioInputStream : Used to read audio data from a file or URL.
- Clip : A special data line that can load audio data and provide controls such as play, stop, and loop.
2.2 Implementation steps
- Get a Clip instance through AudioSystem.getClip().
- Use AudioSystem.getAudioInputStream() to create an AudioInputStream from an audio file.
- Open the AudioInputStream into the Clip, that is, clip.open(audioInputStream).
- Call clip.loop(Clip.LOOP_CONTINUOUSLY) to set infinite loop playback.
- Call clip.start() to start playback.
2.3 Sample code
The following code shows how to use javax.sound.sampled to achieve infinite loop playback of audio:
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
public class AudioLoopPlayer {
/**
* Main method, demo audio playback * @param args command line parameters */
public static void main(String[] args) {
// Please replace it with your WAV file path String audioFilePath = "C:\\Users\\Ученик\\IdeaProjects\\Game\\src\\com\\company\\audio\\skeleton.wav";
try {
Clip clip = getClip(audioFilePath);
playForever(clip);
// The main thread can continue to perform other tasks System.out.println("The audio starts looping...");
// Assume there is some game logic or UI operation here // For demonstration, we let the main thread wait for a while Thread.sleep(10000); // Stop after playing for 10 seconds // If you need to stop, you can call clip.stop()
// clip.stop();
// System.out.println("Audio playback stops.");
// clip.close(); // Release resources} catch (RuntimeException e) {
// The error has been handled in the getClip method, and the stack is captured and printed here e.printStackTrace();
} catch (InterruptedException e) {
System.err.println("The main thread was interrupted: " e.getMessage());
Thread.currentThread().interrupt(); // Reset interrupt status}
}
/**
* Get a Clip instance ready to be played.
* @param filepath The path of the audio file.
* @return prepared Clip instance.
* @throws RuntimeException if the audio file cannot be found, is not supported, or cannot be opened.
*/
public static Clip getClip(String filepath) {
String reset = "\u001B[0m"; // ANSI color code: reset String red = "\u001B[31m"; // ANSI color code: red try {
File audioFile = new File(filepath);
if (!audioFile.exists()) {
throw new IOException("Audio file does not exist: " filepath);
}
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(audioFile));
return clip;
} catch (UnsupportedAudioFileException e) {
JOptionPane.showMessageDialog(null, "Error: Unsupported audio file format.");
System.err.println(red "Error: Unsupported audio file format." reset);
throw new RuntimeException("Unsupported audio file format", e);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error: Unable to find or read audio file.");
System.err.println(red "Error: Unable to find or read audio file." reset);
throw new RuntimeException("Audio file processing error", e);
} catch (LineUnavailableException e) {
JOptionPane.showMessageDialog(null, "Error: Audio line is unavailable.");
System.err.println(red "Error: Audio line unavailable." reset);
throw new RuntimeException("Audio line not available", e);
}
}
/**
* Make the specified Clip play in an infinite loop.
* @param clip The Clip instance to be played.
*/
public static void playForever(Clip clip) {
clip.loop(Clip.LOOP_CONTINUOUSLY); //Set an infinite loop clip.start(); //Start playing}
}
3. Manage audio playback in a separate thread
The above method starts audio playback in the main thread. If the main thread exits before audio playback is complete, the JVM may terminate, stopping the audio. To ensure that the audio continues to play in the background, even if the main thread completes its task, we need to put the audio playback logic in a separate daemon thread.
3.1 Why do we need independent threads?
- Lifecycle management : Allow the main thread to perform other tasks while the audio runs independently in the background.
- Prevent blocking : If audio playback itself is a long-running operation (although Clip is non-blocking), placing it in a separate thread can avoid UI freezes or other performance issues.
- Control : More granular control over starting, stopping and pausing audio without affecting the flow of the main program.
3.2 Implementation steps
- Create a new Thread object.
- Execute the audio loop playback logic in the run() method of the thread.
- Use Thread.currentThread().wait() to make the audio thread wait until told to stop.
- When you need to stop the audio, wake up the audio thread through notify().
3.3 Sample code
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
public class ThreadedAudioLoopPlayer {
public static void main(String[] args) {
// Please replace it with your WAV file path String audioFilePath = "C:\\Users\\Ученик\\IdeaProjects\\Game\\src\\com\\company\\audio\\skeleton.wav";
Clip clip = null;
Thread audioThread = null;
try {
clip = getClip(audioFilePath);
audioThread = playForeverInThread(clip);
System.out.println("Audio starts looping in a separate thread...");
// Simulate the main thread to perform other tasks Thread.sleep(15000); // After 15 seconds, the main thread is ready to stop the audio System.out.println("The main thread has completed the task and is ready to stop the audio.");
stopAudioThread(audioThread); // Stop the audio thread System.out.println("Audio playback has stopped.");
} catch (RuntimeException e) {
e.printStackTrace();
} catch (InterruptedException e) {
System.err.println("The main thread was interrupted: " e.getMessage());
Thread.currentThread().interrupt();
} finally {
if (clip != null && clip.isOpen()) {
clip.close(); // Make sure to release Clip resources}
}
}
/**
* Get a Clip instance ready to be played.
* (Same as previous example, duplicate code omitted)
*/
public static Clip getClip(String filepath) {
String reset = "\u001B[0m";
String red = "\u001B[31m";
try {
File audioFile = new File(filepath);
if (!audioFile.exists()) {
throw new IOException("Audio file does not exist: " filepath);
}
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(audioFile));
return clip;
} catch (UnsupportedAudioFileException e) {
JOptionPane.showMessageDialog(null, "Error: Unsupported audio file format.");
System.err.println(red "Error: Unsupported audio file format." reset);
throw new RuntimeException("Unsupported audio file format", e);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Error: Unable to find or read audio file.");
System.err.println(red "Error: Unable to find or read audio file." reset);
throw new RuntimeException("Audio file processing error", e);
} catch (LineUnavailableException e) {
JOptionPane.showMessageDialog(null, "Error: Audio line is unavailable.");
System.err.println(red "Error: Audio line unavailable." reset);
throw new RuntimeException("Audio line not available", e);
}
}
/**
* Make the specified Clip play in an infinite loop in a new thread.
* @param clip The Clip instance to be played.
* @return The started audio playback thread.
*/
public static Thread playForeverInThread(Clip clip) {
Thread thread = new Thread(() -> {
try {
clip.loop(Clip.LOOP_CONTINUOUSLY); // Set up an infinite loop clip.start(); // Start playing // Use the wait/notify mechanism to control the thread life cycle synchronized (Thread.currentThread()) {
try {
Thread.currentThread().wait(); // The thread waits here until awakened by notify()} catch (InterruptedException e) {
// The thread is interrupted, which usually means that playback needs to be stopped System.out.println("The audio playback thread is interrupted.");
}
}
} finally {
// Make sure to stop playback and close the Clip when the thread ends
if (clip.isRunning()) {
clip.stop();
}
if (clip.isOpen()) {
clip.close();
}
}
});
thread.setDaemon(true); // Set as a daemon thread so that when all non-daemon threads exit, the JVM will automatically terminate thread.start();
return thread;
}
/**
* Stop the audio playback thread.
* @param thread The audio thread to stop.
*/
public static void stopAudioThread(Thread thread) {
if (thread != null && thread.isAlive()) {
synchronized (thread) {
thread.notify(); // Wake up the waiting thread}
// You can choose to wait for the thread to end, but it is usually not necessary for daemon threads // try {
// thread.join(1000); // Wait up to 1 second // } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// }
}
}
}
4. Precautions and Best Practices
- Resource management : No matter which playback method is used, when the Clip is no longer needed, be sure to call clip.stop() to stop playback and call clip.close() to release system resources. Especially in loop playback scenarios, if the program runs for a long time, not closing the Clip may cause resource leaks.
- Error handling : When loading and playing audio, you may encounter various exceptions, such as UnsupportedAudioFileException (the file format is not supported), IOException (the file does not exist or cannot be read), LineUnavailableException (the audio line is occupied or unavailable). Be sure to add appropriate try-catch blocks to handle these exceptions and provide friendly error messages.
- Audio format : javax.sound.sampled usually supports WAV, AU, AIFF and other formats. For compressed formats such as MP3, additional SPI (Service Provider Interface) plug-ins or the use of other libraries (such as JLayer) may be required.
- Daemon thread : When playing audio in a separate thread, it is a good practice to set the thread as a daemon thread (thread.setDaemon(true)). This means that when all non-daemon threads (usually the main thread) have exited, the JVM will automatically terminate the daemon thread without the need to stop it explicitly, which can simplify program exit logic in some cases.
- Volume control : The Clip interface also provides FloatControl to control volume, pan and other parameters, which can be obtained and set through clip.getControl(FloatControl.Type.MASTER_GAIN).
5. Summary
Through the javax.sound.sampled package, we can reliably and flexibly implement audio loop playback in Java. Whether it is simple single-threaded playback or complex background thread management, the Clip interface provides powerful support. Following the guidance and best practices in this tutorial can help you build a stable and efficient Java audio application.
The above is the detailed content of Java Audio Looping Guide: Using javax.sound.sampled. For more information, please follow other related articles on the PHP Chinese website!
Hot AI Tools
Undress AI Tool
Undress images for free
AI Clothes Remover
Online AI tool for removing clothes from photos.
Undresser.AI Undress
AI-powered app for creating realistic nude photos
ArtGPT
AI image generator for creative art from text prompts.
Stock Market GPT
AI powered investment research for smarter decisions
Hot Article
Popular tool
Notepad++7.3.1
Easy-to-use and free code editor
SublimeText3 Chinese version
Chinese version, very easy to use
Zend Studio 13.0.1
Powerful PHP integrated development environment
Dreamweaver CS6
Visual web development tools
SublimeText3 Mac version
God-level code editing software (SublimeText3)
Hot Topics
20518
7
13631
4
How to configure Spark distributed computing environment in Java_Java big data processing
Mar 09, 2026 pm 08:45 PM
Spark cannot run in local mode, ClassNotFoundException: org.apache.spark.sql.SparkSession. This is the most common first step of getting stuck: even the dependencies are not correct. Only spark-core_2.12 is written in Maven, but spark-sql_2.12 is not added. SparkSession crashes as soon as it is built. The Scala version must strictly match the official Spark compiled version - Spark3.4.x uses Scala2.12 by default. If you use spark-sqljar of 2.13, the class loader cannot directly find the main class. Practical advice: Go to mvnre
How to safely map user-entered weekday string to integer value and implement date offset operation in Java
Mar 09, 2026 pm 09:43 PM
This article introduces a concise and maintainable way to map the weekday string (such as "Monday") to the corresponding serial number (1-7), and use the modulo operation to realize the forward and backward offset of any number of days (such as Monday plus 4 days to get Friday), avoiding lengthy if chains and hard-coded logic.
How to generate a list of duplicate elements using Java's Collections.nCopies_Initialization tips
Mar 06, 2026 am 06:24 AM
Collections.nCopies returns an immutable view. Calling add/remove will throw UnsupportedOperationException; it needs to be wrapped with newArrayList() to modify it, and it is disabled for mutable objects.
How to use Homebrew to install Java on Mac_A must-have Java tool chain for developers
Mar 09, 2026 pm 09:48 PM
Homebrew installs the latest stable version of openjdk (such as JDK22) by default, not the LTS version; you need to explicitly execute brewinstallopenjdk@17 or brewinstallopenjdk@21 to install the LTS version, and manually configure PATH and JAVA_HOME to be correctly recognized by the system and IDE.
What is exception masking (Suppressed Exceptions) in Java_Multiple resource shutdown exception handling
Mar 10, 2026 pm 06:57 PM
What is SuppressedException: It is not "swallowed", but actively archived by the JVM. SuppressedException is not an exception loss, but the JVM quietly attaches the secondary exception to the main exception under the premise that "only one exception must be thrown" for you to verify afterwards. It is automatically triggered by the JVM in only two scenarios: one is that the resource closure in try-with-resources fails, and the other is that you manually call addSuppressed() in finally. The key difference is: the former is fully automatic and safe; the latter requires you to keep it to yourself, and it can be written as shadowing if you are not careful. try-
How to correctly implement runtime file writing in Java applications (avoiding JAR internal write failures)
Mar 09, 2026 pm 07:57 PM
After a Java application is packaged as a JAR, data cannot be written directly to the resources in the JAR package (such as test.txt) because the JAR is essentially a read-only ZIP archive; the correct approach is to write variable data to an external path (such as a user directory, a temporary directory, or a configuration-specified path).
What is the underlying principle of array expansion in Java_Java memory dynamic adjustment analysis
Mar 09, 2026 pm 09:45 PM
ArrayList.add() triggers expansion because grow() is called when size is equal to elementData.length. The first add allocates 10 capacity, and subsequent expansion is 1.5 times and not less than the minimum requirement, relying on delayed initialization and System.arraycopy optimization.
How to safely read a line of integer input in Java and avoid Scanner blocking
Mar 06, 2026 am 06:21 AM
This article introduces typical blocking problems when using Scanner to read multiple integers in a single line. It points out that hasNextInt() will wait indefinitely when there is no subsequent input, and recommends a safe alternative with nextLine() string splitting as the core.





