Перейти к основному содержимому

Как воспроизвести звук с помощью Java

· 7 мин. чтения

1. Обзор

В этом уроке мы узнаем, как воспроизводить звук с помощью Java. API-интерфейсы Java Sound предназначены для плавного и непрерывного воспроизведения звуков, даже очень длинных.

В рамках этого руководства мы будем воспроизводить аудиофайл с помощью API-интерфейсов Clip и SourceDataLine Sound, предоставляемых Java. Мы также будем воспроизводить файлы различных аудиоформатов.

Кроме того, мы обсудим плюсы и минусы каждого API. Далее мы увидим пару сторонних библиотек Java, которые тоже умеют воспроизводить звук.

2. Java API для воспроизведения звука

В общем, API-интерфейсы Java Sound, присутствующие в пакете javax.sound , предоставляют два способа воспроизведения звука. Между этими двумя подходами есть разница в том, как указываются данные звукового файла. API-интерфейсы Java Sound могут обрабатывать передачу звука как в потоковом режиме с буферизацией, так и в режиме памяти без буферизации. Двумя наиболее известными звуковыми API в Java являются Clip и SourceDataLine.

2.1. Клип API

Clip API — это небуферизованный или находящийся в памяти звуковой API для Java. Класс Clip является частью пакета javax.sound.sampled и полезен при чтении и воспроизведении коротких звуковых файлов . Перед воспроизведением весь аудиофайл загружается в память, и пользователь имеет полный контроль над воспроизведением.

Помимо зацикливания звуков, он также позволяет пользователям запускать воспроизведение в произвольном месте.

Давайте сначала создадим пример класса SoundPlayerWithClip , который реализует интерфейс LineListener для получения линейных событий ( OPEN , CLOSE , START и STOP ) для воспроизведения. Мы реализуем метод update() из LineListener для проверки статуса воспроизведения:

public class SoundPlayerUsingClip implements LineListener {

boolean isPlaybackCompleted;

@Override
public void update(LineEvent event) {
if (LineEvent.Type.START == event.getType()) {
System.out.println("Playback started.");
} else if (LineEvent.Type.STOP == event.getType()) {
isPlaybackCompleted = true;
System.out.println("Playback completed.");
}
}
}

Во-вторых, давайте прочитаем аудиофайл из папки ресурсов нашего проекта. Наша папка ресурсов содержит три аудиофайла разных форматов, а именно, WAV, MP3 и MPEG:

InputStream inputStream = getClass().getClassLoader().getResourceAsStream(audioFilePath);

В-третьих, из файлового потока мы создадим AudioInputStream :

AudioInputStream audioStream = AudioSystem.getAudioInputStream(inputStream);

Теперь мы создадим объект DataLine.Info :

AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);

Давайте создадим объект Clip из этого DataLine.Info и откроем поток, а затем вызовем start , чтобы начать воспроизведение звука:

Clip audioClip = (Clip) AudioSystem.getLine(info);
audioClip.addLineListener(this);
audioClip.open(audioStream);
audioClip.start();

Наконец, нам нужно закрыть любой открытый ресурс:

audioClip.close();
audioStream.close();

Как только код запустится, аудиофайл будет воспроизводиться.

Поскольку звук предварительно загружается в память, у нас есть много других полезных API, от которых мы можем извлечь пользу.

Мы можем использовать метод Clip.loop для непрерывного воспроизведения аудиоклипа в цикле.

Например, мы можем настроить воспроизведение звука пять раз:

audioClip.loop(4);

Или мы можем настроить его на воспроизведение звука в течение бесконечного времени (или до прерывания):

audioClip.loop(Clip.LOOP_CONTINUOUSLY);

Clip.setMicrosecondPosition устанавливает положение мультимедиа . Когда клип начнет воспроизводиться в следующий раз, он начнется с этой позиции. Например, чтобы начать с 30-й секунды, мы можем установить его как:

audioClip.setMicrosecondPosition(30_000_000);

2.2. API SourceDataLine

API SourceDataLine — это API буферизованного или потокового звука для java. Класс SourceDataLine является частью пакета javax.sound.sampled и может воспроизводить длинные звуковые файлы, которые нельзя предварительно загрузить в память.

Использование SourceDataLine более эффективно, когда мы хотим оптимизировать память для больших аудиофайлов или при потоковой передаче аудиоданных в реальном времени. Это также полезно, если мы не знаем заранее, какова продолжительность звука и когда он закончится.

Давайте сначала создадим пример класса и прочитаем аудиофайл из папки ресурсов нашего проекта. Наша папка ресурсов содержит три аудиофайла разных форматов, а именно, WAV, MP3 и MPEG:

InputStream inputStream = getClass().getClassLoader().getResourceAsStream(audioFilePath);

Во-вторых, из входного потока файла мы создадим AudioInputStream :

AudioInputStream audioStream = AudioSystem.getAudioInputStream(inputStream);

Теперь мы создадим объект DataLine.Info :

AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);

Давайте создадим объект SourceDataLine из этого DataLine.Info , откроем поток и вызовем start , чтобы начать воспроизведение звука:

SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);
sourceDataLine.open(audioFormat);
sourceDataLine.start();

Теперь, в случае с SourceDataLine , аудиоданные загружаются порциями, и нам нужно указать размер буфера :

private static final int BUFFER_SIZE = 4096;

Теперь давайте прочитаем аудиоданные из AudioInputStream и отправим их в буфер воспроизведения SourceDataLine, пока они не достигнут конца потока:

byte[] bufferBytes = new byte[BUFFER_SIZE];
int readBytes = -1;
while ((readBytes = audioStream.read(bufferBytes)) != -1) {
sourceDataLine.write(bufferBytes, 0, readBytes);
}

Наконец, давайте закроем любой открытый ресурс:

sourceDataLine.drain();
sourceDataLine.close();
audioStream.close();

Как только код запустится, аудиофайл будет воспроизводиться.

Здесь нам не нужно реализовывать какой -либо интерфейс LineListener .

2.3. Сравнение между Clip и SourceDataLine

Давайте обсудим плюсы и минусы обоих:

   | **Клип**    | **SourceDataLine**   | 
| Поддерживает воспроизведение с любой позиции в аудио.

См. setMicrosecondPosition(long) или setFramePosition(int). | Невозможно начать воспроизведение с произвольной позиции в звуке. | | Поддерживает воспроизведение в цикле (весь или часть звука).

см. setLoopPoints(int, int) и цикл(int). | Невозможно воспроизвести (зациклить) весь звук или его часть. | | Может знать продолжительность звука перед воспроизведением.

См. getFrameLength() или getMicrosecondLength(). | Невозможно узнать продолжительность звука перед воспроизведением. | | Можно остановить воспроизведение в текущей позиции и возобновить воспроизведение позже. см. стоп() и старт() | Не могу остановиться и возобновить воспроизведение в середине. | | Не подходит и неэффективен для воспроизведения больших аудиофайлов, так как он находится в памяти. | Он подходит и эффективен для воспроизведения длинных звуковых файлов или потоковой передачи звука в режиме реального времени. | | Метод start () в Clip воспроизводит звук, но он не блокирует текущий поток (он немедленно возвращается), поэтому он требует реализации интерфейса LineListener , чтобы знать статус воспроизведения. | В отличие от Clip , нам не нужно реализовывать интерфейс LineListener , чтобы знать, когда завершится воспроизведение. | | Невозможно контролировать, какие звуковые данные должны быть записаны в буфер воспроизведения аудиолинии. | Можно контролировать, какие звуковые данные должны быть записаны в буфер воспроизведения аудиолинии. |

2.4. Поддержка Java API для формата MP3

В настоящее время и Clip , и SourceDataLine могут воспроизводить аудиофайлы в форматах AIFC, AIFF, AU, SND и WAV.

Мы можем проверить поддерживаемый аудиоформат с помощью AudioSystem :

Type[] list = AudioSystem.getAudioFileTypes();
StringBuilder supportedFormat = new StringBuilder("Supported formats:");
for (Type type : list) {
supportedFormat.append(", " + type.toString());
}
System.out.println(supportedFormat.toString());

Однако мы не можем воспроизводить популярный аудиоформат MP3/MPEG с помощью API-интерфейсов Java Sound Clip и SourceDataLine. Нам нужно искать какие-то сторонние библиотеки, которые могут воспроизводить формат MP3.

Если мы предоставим файл формата MP3 либо Clip , либо SourceDataLine API, мы получим UnsupportedAudioFileException :

javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1189)

3. Сторонние API Java для воспроизведения звука

Давайте взглянем на пару сторонних библиотек, которые также могут воспроизводить файлы различных аудиоформатов.

3.1. Библиотека JavaFX

JavaFX имеет классы Media и MediaPlayer , которые будут воспроизводить файлы MP3. Он также может воспроизводить другие аудиоформаты, такие как WAV.

Давайте создадим пример класса и воспользуемся классом Media и MediaPlayer для воспроизведения нашего файла MP3:

String audioFilePath = "AudioFileWithMp3Format.mp3";
SoundPlayerUsingJavaFx soundPlayerWithJavaFx = new SoundPlayerUsingJavaFx();
try {
com.sun.javafx.application.PlatformImpl.startup(() -> {});
Media media = new Media(
soundPlayerWithJavaFx.getClass().getClassLoader().getResource(audioFilePath).toExternalForm());
MediaPlayer mp3Player = new MediaPlayer(media);
mp3Player.play();
} catch (Exception ex) {
System.out.println("Error occured during playback process:" + ex.getMessage());
}

Одним из преимуществ этого API является то, что он может воспроизводить аудиоформаты WAV, MP3 и MPEG.

3.2. Библиотека JLayer

Библиотека JLayer может воспроизводить аудиоформаты, такие как форматы MPEG, включая MP3 . Однако он не может воспроизводить другие форматы, такие как WAV.

Давайте создадим пример класса, используя класс Javazoom Player :

String audioFilePath = "AudioFileWithMp3Format.mp3";
SoundPlayerUsingJavaZoom player = new SoundPlayerUsingJavaZoom();
try {
BufferedInputStream buffer = new BufferedInputStream(
player.getClass().getClassLoader().getResourceAsStream(audioFilePath));
Player mp3Player = new Player(buffer);
mp3Player.play();
} catch (Exception ex) {
System.out.println("Error occured during playback process:" + ex.getMessage());
}

4. Вывод

В этой статье мы узнали, как воспроизводить звук с помощью Java. Мы также узнали о двух разных API звука Java, Clip и SourceDataLine . Позже мы увидели различия между API-интерфейсами Clip и SourceDataLine , которые помогут нам выбрать подходящий для любого варианта использования.

Наконец, мы увидели некоторые сторонние библиотеки, которые также могут воспроизводить аудио и поддерживать другие форматы, такие как MP3.

Как всегда, пример кода, используемый в этой статье, доступен на GitHub .