search
  • Sign In
  • Sign Up
Password reset successful

Follow the proiects vou are interested in andi aet the latestnews about them taster

Table of Contents
1. Why is sun.audio not recommended?
2. Use javax.sound.sampled.Clip to implement basic audio looping
2.1 Core concepts
3.1 Implementation steps and code examples
3. Manage audio playback in a separate thread
4. Precautions and Best Practices
Summarize
Home Java javaTutorial A professional guide to implementing audio loop playback in Java

A professional guide to implementing audio loop playback in Java

Jan 01, 2026 am 10:03 AM

A professional guide to implementing audio loop playback in Java

This article details the correct way to implement audio loop playback in Java. We will abandon the deprecated `sun.audio` class in favor of the standard and powerful `javax.sound.sampled` package. The tutorial will cover how to load audio files, use the `Clip` interface to achieve infinite loop playback, and further explore how to manage audio playback in a separate thread to ensure that the background music can continue to run even if the main thread ends, providing complete code examples and precautions.

It is a common requirement to implement loop playback of background music in Java applications. However, many beginners may encounter problems with audio playback being interrupted or failing to loop. This article aims to provide a professional and robust solution that mainly utilizes the javax.sound.sampled package in the Java standard library to process audio and avoids the use of the deprecated sun.audio internal API.

Before we begin, one thing needs to be made clear: the classes under the sun.audio package belong to Sun (now Oracle) internal API. This means that they are not part of the Java standard API and may be removed or modified in future Java versions, causing the code to be no longer compatible. Therefore, it is highly recommended to avoid using these classes in a production environment or any serious project.

Java provides a feature-rich and stable javax.sound.sampled package, which is a standard way to process audio, supports multiple audio formats (such as WAV, AIFF, AU, etc.), and provides advanced control of audio streams, mixers, editing, etc.

2. Use javax.sound.sampled.Clip to implement basic audio looping

The javax.sound.sampled.Clip interface is ideal for handling short-term audio clips, such as sound effects or background music clips. It allows the entire audio data to be preloaded into memory, allowing for fast and precise playback and looping.

2.1 Core concepts

  • AudioSystem : Responsible for obtaining audio resources (such as Clip instances) and processing audio input streams.
  • AudioInputStream : Represents a readable audio data stream.
  • Clip : A special data line that can load audio data and provide controls such as play, stop, and loop.

2.2 Implementation steps and code examples

The following code demonstrates how to use Clip to load a WAV file and make it play in an infinite loop:

 import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.*; // used for error message dialog import java.io.File;

public class AudioPlayerBasic {

    public static void main(String[] args) {
        // Define the audio file path, please replace it with your actual path String audioFilePath = "C:\\Users\\Ученик\\IdeaProjects\\Game\\src\\com\\company\\audio\\skeleton.wav";

        // Get and prepare the Clip object Clip clip = getClip(audioFilePath);

        // Check if clip is successfully obtained if (clip != null) {
            // Implement infinite loop playback playForever(clip);

            // The main thread can continue to perform other tasks System.out.println("The audio has started looping...");

            // Example: Stop playing after waiting for a period of time (in actual applications, it may be triggered by user operations)
            // try {
            // Thread.sleep(10000); // Play for 10 seconds // } catch (InterruptedException e) {
            // Thread.currentThread().interrupt();
            // }
            // clip.stop();
            // clip.close(); // Release resources // System.out.println("Audio playback has stopped.");
        }
    }

    /**
     * Start infinite loop playback of Clip.
     * @param clip Clip object to be played */
    public static void playForever(Clip clip) {
        // Set to infinite loop playback clip.loop(Clip.LOOP_CONTINUOUSLY);
        //Start playback clip.start();
    }

    /**
     * Get a prepared Clip object based on the file path.
     * @param filepath audio file path * @return Returns the Clip object if successful, otherwise returns null
     */
    public static Clip getClip(String filepath) {
        // ANSI escape code for console output color String reset = "\u001B[0m";
        String red = "\u001B[31m";
        try {
            // 1. Get the Clip instance Clip clip = AudioSystem.getClip();
            // 2. Open the audio input stream and load it into Clip clip.open(AudioSystem.getAudioInputStream(new File(filepath)));
            return clip;
        } catch (Exception e) {
            // Error handling: file not found, unsupported audio format, etc. JOptionPane.showMessageDialog(null, "Error: Unable to find or play audio file: " filepath);
            System.out.println(red "Error: Unable to find or play audio file: " filepath reset);
            // In actual applications, more detailed logging or exception handling may be required return null; // Returning null indicates acquisition failure}
    }
}

Code analysis:

  1. The getClip(String filepath) method is responsible for loading audio files. It first obtains a Clip instance through AudioSystem.getClip(), then uses AudioSystem.getAudioInputStream(new File(filepath)) to create an audio input stream, and finally loads audio data into the Clip through clip.open().
  2. The playForever(Clip clip) method is the key to implementing the loop. clip.loop(Clip.LOOP_CONTINUOUSLY) will instruct the Clip to automatically start looping from the beginning after playback ends. Clip.LOOP_CONTINUOUSLY is a constant that represents an infinite loop.
  3. clip.start() starts audio playback.
  4. The try-catch block is used to catch exceptions that may occur, such as the file does not exist (FileNotFoundException) or the audio format is not supported (UnsupportedAudioFileException).

3. Manage audio playback in a separate thread

The basic example above will work fine in most cases. However, if your main thread is a short-lived process (for example, it performs some tasks and then exits), then even if the Clip is set to loop, the Java Virtual Machine (JVM) may shut down when the main thread terminates, causing audio playback to be interrupted.

To solve this problem, we can encapsulate the audio playback logic in a separate thread. This way, even if the main thread completes its task, the music will continue to play as long as the audio thread is running.

3.1 Implementation steps and code examples

 import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.*;
import java.io.File;

public class AudioPlayerThreaded {

    public static void main(String[] args) {
        String audioFilePath = "C:\\Users\\Ученик\\IdeaProjects\\Game\\src\\com\\company\\audio\\skeleton.wav";

        Clip clip = getClip(audioFilePath);

        if (clip != null) {
            // Start audio loop playback in a new thread Thread audioThread = playForever(clip);

            System.out.println("The audio has started looping in a separate thread...");

            // The main thread can continue to perform other tasks and may end early // For example:
            // try {
            // System.out.println("The main thread performs other tasks...");
            // Thread.sleep(5000); // The main thread waits for 5 seconds // } catch (InterruptedException e) {
            // Thread.currentThread().interrupt();
            // }
            // System.out.println("Main thread task completed.");

            // If you need to stop the audio, you can call the stopAudio method // boolean shouldStopAudio = false; // Assume a certain condition determines whether to stop // if (shouldStopAudio) {
            // stopAudio(audioThread);
            // clip.close(); // Release resources after stopping // }
        }
    }

    /**
     * Start the infinite loop playback of Clip in a new thread.
     * This thread will continue to run until explicitly stopped.
     * @param clip The Clip object to be played * @return The thread instance responsible for audio playback */
    public static Thread playForever(Clip clip) {
        Thread thread = new Thread(() -> {
            clip.loop(Clip.LOOP_CONTINUOUSLY); // Set up an infinite loop clip.start(); // Start playback // Use the wait/notify mechanism to keep the thread active until it is notified to stop synchronized (Thread.currentThread()) {
                try {
                    Thread.currentThread().wait(); // The thread waits here} catch (InterruptedException e) {
                    // When the thread is interrupted, stop playing and clean up clip.stop();
                    clip.close();
                    Thread.currentThread().interrupt(); // Reset the interrupt status System.out.println("The audio playback thread was interrupted and stopped playing.");
                }
            }
        });
        thread.setDaemon(false); // Set as a non-daemon thread to ensure that the JVM will not close because the main thread ends thread.start(); // Start the thread return thread;
    }

    /**
     * Stop the playback of the specified audio thread.
     * @param audioThread Thread instance responsible for audio playback*/
    public static void stopAudio(Thread audioThread) {
        synchronized (audioThread) {
            audioThread.notify(); // Notify the audio thread to continue execution (thereby exiting the wait state)
        }
    }

    /**
     * Get a prepared Clip object based on the file path.
     * @param filepath audio file path * @return Returns the Clip object if successful * @throws RuntimeException If the Clip cannot be obtained, a runtime exception will be thrown */
    public static Clip getClip(String filepath) {
        String reset = "\u001B[0m";
        String red = "\u001B[31m";
        try {
            Clip clip = AudioSystem.getClip();
            clip.open(AudioSystem.getAudioInputStream(new File(filepath)));
            return clip;
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "Error: Unable to find or play audio file: " filepath);
            System.out.println(red "Error: Unable to find or play audio file: " filepath reset);
            // Throw a runtime exception and let the caller handle it or the program terminates throw new RuntimeException("Unable to load audio file: " filepath, e);
        }
    }
}

Code analysis:

  1. The playForever(Clip clip) method now returns a Thread object. In this new thread, we execute clip.loop() and clip.start().
  2. In order to keep this thread running even after clip.start() returns, we use the synchronized (Thread.currentThread()) { Thread.currentThread().wait(); } mechanism. This puts the audio thread into a wait state and won't end immediately.
  3. thread.setDaemon(false): This is a very important setting. By default, newly created threads are non-daemon threads. If set to a daemon thread (thread.setDaemon(true)), when all non-daemon threads end, the JVM will forcefully terminate all daemon threads, which may cause the audio to stop suddenly. Therefore, remaining a non-daemon thread ensures that the audio thread remains running after the main thread ends until it is explicitly stopped.
  4. The stopAudio(Thread audioThread) method uses audioThread.notify() to wake up the waiting audio thread. Once the thread is awakened, it will jump out of the wait() state and can perform subsequent cleanup work (such as clip.stop() and clip.close()).
  5. In the getClip method, we change the error handling to throw a RuntimeException. This is a common practice when a critical resource fails to load, often preventing the program from continuing because subsequent operations will not be possible.

4. Precautions and Best Practices

  • Resource management : No matter which playback method is used, when the audio is no longer needed, be sure to call clip.stop() to stop playback and call clip.close() to release system resources. This helps prevent memory leaks and resource exhaustion.
  • Error handling : A complete try-catch block is crucial for handling exceptions such as file non-existence and unsupported audio format. In a production environment, detailed error messages should be logged instead of simply popping up a dialog box.
  • Audio format : javax.sound.sampled supports WAV, AIFF, AU and other formats by default. For other formats such as MP3, additional libraries may need to be introduced (such as Java SPI for MP3 or other third-party libraries).
  • Thread synchronization : If your application requires precise control over starting, stopping, and pausing audio and involves multiple threads accessing the same Clip object, be sure to use appropriate thread synchronization mechanisms to avoid race conditions.
  • UI blocking : If the audio loading or playback process takes a long time and is executed in the main UI thread, it may cause the UI interface to freeze. In this case, it is best practice to put audio operations in a separate thread.

Summarize

By following the guidance of this article, you can reliably loop audio using the javax.sound.sampled package of the Java standard library. For simple background music, Clip.loop(Clip.LOOP_CONTINUOUSLY) provides a straightforward solution. For background music that needs to run independently of the main program life cycle, it will be a more robust and professional choice to encapsulate it in a separate thread and use the wait/notify mechanism to control it. Always remember to practice proper resource management and error handling to ensure the stability and reliability of your application.

The above is the detailed content of A professional guide to implementing audio loop playback in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

ArtGPT

ArtGPT

AI image generator for creative art from text prompts.

Stock Market GPT

Stock Market GPT

AI powered investment research for smarter decisions

Popular tool

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to configure Spark distributed computing environment in Java_Java big data processing 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 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 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 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 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) 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 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 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.

Related articles