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 .