Java SourceDataLine 播放音频

Java SourceDataLine 播放音频

  • [1 依赖](#1 依赖)
  • [2 接口](#2 接口)
  • [3 实现](#3 实现)
  • [4 测试](#4 测试)
项目 Value
音频格式 添加依赖
*.wav (JDK 原生支持)
*.pcm (JDK 原生支持)
*.au (JDK 原生支持)
*.aiff (JDK 原生支持)
*.mp3 mp3spi.jar
*.flac jflac-codec.jar

1 依赖

xml 复制代码
<dependency>
	<groupId>com.googlecode.soundlibs</groupId>
	<artifactId>mp3spi</artifactId>
	<version>1.9.5.4</version>
</dependency>

<!-- 如果需要解码播放flac文件则引入这个jar包 -->
<dependency>
	<groupId>org.jflac</groupId>
	<artifactId>jflac-codec</artifactId>
	<version>1.5.2</version>
</dependency>

2 接口

java 复制代码
package com.xu.music.player.player;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFormat.Encoding;
import javax.sound.sampled.AudioInputStream;

import java.io.File;
import java.net.URL;

/**
 * Java 音频播放
 *
 * @author hyacinth
 * @date 2019年10月31日19:06:39
 */
public interface Player {

    /**
     * Java Music 加载音频
     *
     * @param url 音频文件url
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(URL url) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param file 音频文件
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(File file) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param path 文件路径
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(String path) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param stream 音频文件输入流
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(AudioInputStream stream) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param encoding Encoding
     * @param stream   AudioInputStream
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(Encoding encoding, AudioInputStream stream) throws Exception;

    /**
     * Java Music 加载音频
     *
     * @param format AudioFormat
     * @param stream AudioInputStream
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void load(AudioFormat format, AudioInputStream stream) throws Exception;

    /**
     * Java Music 暂停播放
     *
     * @date 2019年10月31日19:06:39
     */
    void pause();

    /**
     * Java Music 继续播放
     *
     * @date 2019年10月31日19:06:39
     */
    void resume();

    /**
     * Java Music 开始播放
     *
     * @throws Exception 异常
     * @date 2019年10月31日19:06:39
     */
    void play() throws Exception;

    /**
     * Java Music 结束播放
     *
     * @description: Java Music 结束播放
     * @date 2019年10月31日19:06:39
     */
    void stop();

}

3 实现

java 复制代码
package com.xu.music.player.player;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.CharSequenceUtil;
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Deque;
import java.util.LinkedList;

import com.xu.music.player.system.Constant;

/**
 * Java 音频播放
 *
 * @author hyacinth
 * @date 2019年10月31日19:06:39
 */
public class XPlayer implements Player {

    private static SourceDataLine data = null;

    private static AudioInputStream audio = null;

    public static final Deque<Double> deque = new LinkedList<>();

    public void put(Double v) {
        synchronized (deque) {
            deque.add(v);
            if (deque.size() > Constant.SPECTRUM_TOTAL_NUMBER) {
                deque.removeFirst();
            }
        }
    }

    private XPlayer (){

    }

    public static XPlayer createPlayer() {
        return XPlayer.SingletonHolder.player;
    }

    private static class SingletonHolder {
        private static final XPlayer player = new XPlayer();
    }

    @Override
    public void load(URL url) throws Exception {
        load(AudioSystem.getAudioInputStream(url));
    }

    @Override
    public void load(File file) throws Exception {
        String name = file.getName();
        if (CharSequenceUtil.endWithIgnoreCase(name, ".mp3")) {
            AudioInputStream stream = new MpegAudioFileReader().getAudioInputStream(file);

            AudioFormat format = stream.getFormat();
            format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(),
                    format.getChannels() * 2, format.getSampleRate(), false);

            stream = AudioSystem.getAudioInputStream(format, stream);
            load(stream);
        } else if (CharSequenceUtil.endWithIgnoreCase(name, ".flac")) {
            AudioInputStream stream = AudioSystem.getAudioInputStream(file);

            AudioFormat format = stream.getFormat();
            format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(),
                    format.getChannels() * 2, format.getSampleRate(), false);

            stream = AudioSystem.getAudioInputStream(format, stream);

            load(stream);
        } else {
            load(AudioSystem.getAudioInputStream(file));
        }
    }

    @Override
    public void load(String path) throws Exception {
        load(new File(path));
    }

    @Override
    public void load(AudioInputStream stream) throws Exception {
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, stream.getFormat(), AudioSystem.NOT_SPECIFIED);
        data = (SourceDataLine) AudioSystem.getLine(info);
        data.open(stream.getFormat());
        audio = stream;
    }

    @Override
    public void load(AudioFormat.Encoding encoding, AudioInputStream stream) throws Exception {
        load(AudioSystem.getAudioInputStream(encoding, stream));
    }

    @Override
    public void load(AudioFormat format, AudioInputStream stream) throws Exception {
        load(AudioSystem.getAudioInputStream(format, stream));
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void play() throws IOException {
        if (null == audio || null == data) {
            return;
        }
        data.start();
        byte[] buf = new byte[4];
        int channels = audio.getFormat().getChannels();
        float rate = audio.getFormat().getSampleRate();
        while (audio.read(buf) != -1) {
            if (channels == 2) {//立体声
                if (rate == 16) {
                    put((double) ((buf[1] << 8) | buf[0]));//左声道
                    //put((double) ((buf[3] << 8) | buf[2]));//右声道
                } else {
                    put((double) buf[1]);//左声道
                    put((double) buf[3]);//左声道
                    //put((double) buf[2]);//右声道
                    //put((double) buf[4]);//右声道
                }
            } else {//单声道
                if (rate == 16) {
                    put((double) ((buf[1] << 8) | buf[0]));
                    put((double) ((buf[3] << 8) | buf[2]));
                } else {
                    put((double) buf[0]);
                    put((double) buf[1]);
                    put((double) buf[2]);
                    put((double) buf[3]);
                }
            }
            data.write(buf, 0, 4);
        }
    }

    @Override
    public void stop() {
        if (null == audio || null == data) {
            return;
        }
        IoUtil.close(audio);
        data.stop();
        IoUtil.close(data);
    }

}

4 测试

java 复制代码
package com.xu.music.player.player;

import java.io.File;

/**
 * Java 音频播放
 *
 * @author hyacinth
 * @date 2019年10月31日19:06:39
 */
public class Test {

    public static void main(String[] args) throws Exception {
        Player player = XPlayer.createPlayer();
        player.load(new File("D:\\Kugou\\梦涵 - 加减乘除.mp3"));
        player.play();
    }

}