📄 basicplayer.java
字号:
package player1;
import java.io.*;
import java.util.*;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Control;
public class BasicPlayer
implements Runnable {
private static final int EXTERNAL_BUFFER_SIZE = 4000 * 4;
private Thread m_thread = null;
private Object m_dataSource;
private AudioInputStream m_audioInputStream;
private AudioFileFormat m_audioFileFormat;
private SourceDataLine m_line;
private FloatControl m_gainControl;
private FloatControl m_panControl;
/**
* These variables are used to distinguish stopped, paused, playing states.
* We need them to control Thread.
*/
private static final int PLAYING = 0;
private static final int PAUSED = 1;
private static final int STOPPED = 2;
private static final int READY = 3;
private int m_status = READY;
private long doSeek = -1;
private File _file = null;
private boolean ifPaused = false;
private BasicPlayerListener m_bpl = null;
/**
* Constructs a Basic Player.
*/
public BasicPlayer() {
m_dataSource = null;
m_audioInputStream = null;
m_audioFileFormat = null;
m_line = null;
m_gainControl = null;
m_panControl = null;
}
/**
* Constructs a Basic Player with a BasicPlayerListener.
*/
public BasicPlayer(BasicPlayerListener bpl) {
this();
m_bpl = bpl;
}
/**
* Sets the data source as a file.
*/
protected void setDataSource(File file) throws UnsupportedAudioFileException,
LineUnavailableException, IOException {
if (file != null) {
m_dataSource = file;
initAudioInputStream();
}
}
/**
* Sets the data source as an url.
*/
protected void setDataSource(URL url) throws UnsupportedAudioFileException,
LineUnavailableException, IOException {
if (url != null) {
m_dataSource = url;
initAudioInputStream();
}
}
/**
* Inits Audio ressources from the data source.<br>
* - AudioInputStream <br>
* - AudioFileFormat
*/
private void initAudioInputStream() throws UnsupportedAudioFileException,
LineUnavailableException, IOException {
if (m_dataSource instanceof URL) {
initAudioInputStream( (URL) m_dataSource);
}
else if (m_dataSource instanceof File) {
initAudioInputStream( (File) m_dataSource);
}
}
/**
* Inits Audio ressources from file.
*/
private void initAudioInputStream(File file) throws
UnsupportedAudioFileException, IOException {
_file = file;
m_audioInputStream = AudioSystem.getAudioInputStream(file);
m_audioFileFormat = AudioSystem.getAudioFileFormat(file);
}
/**
* Inits Audio ressources from URL.
*/
private void initAudioInputStream(URL url) throws
UnsupportedAudioFileException, IOException {
m_audioInputStream = AudioSystem.getAudioInputStream(url);
m_audioFileFormat = AudioSystem.getAudioFileFormat(url);
}
/**
* Inits Audio ressources from AudioSystem.<br>
* DateSource must be present.
*/
protected void initLine() throws LineUnavailableException {
if (m_line == null) {
createLine();
openLine();
}
else {
AudioFormat lineAudioFormat = m_line.getFormat();
AudioFormat audioInputStreamFormat = m_audioInputStream == null ? null :
m_audioInputStream.getFormat();
if (!lineAudioFormat.equals(audioInputStreamFormat)) {
m_line.close();
openLine();
}
}
}
/**
* Inits a DateLine.<br>
*
* We check if the line supports Volume and Pan controls.
*
* From the AudioInputStream, i.e. from the sound file, we
* fetch information about the format of the audio data. These
* information include the sampling frequency, the number of
* channels and the size of the samples. There information
* are needed to ask JavaSound for a suitable output line
* for this audio file.
* Furthermore, we have to give JavaSound a hint about how
* big the internal buffer for the line should be. Here,
* we say AudioSystem.NOT_SPECIFIED, signaling that we don′t
* care about the exact size. JavaSound will use some default
* value for the buffer size.
*/
private void createLine() throws LineUnavailableException {
if (m_line == null) {
AudioFormat sourceFormat = m_audioInputStream.getFormat();
AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.
PCM_SIGNED,
sourceFormat.getSampleRate(),
16,
sourceFormat.getChannels(),
sourceFormat.getChannels() * 2,
sourceFormat.getSampleRate(),
false);
m_audioInputStream = AudioSystem.getAudioInputStream(targetFormat,
m_audioInputStream);
AudioFormat audioFormat = m_audioInputStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat,
AudioSystem.NOT_SPECIFIED);
m_line = (SourceDataLine) AudioSystem.getLine(info);
/*-- Display supported controls --*/
Control[] c = m_line.getControls();
for (int p = 0; p < c.length; p++) {
}
/*-- Is Gain Control supported ? --*/
if (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.
MASTER_GAIN);
}
/*-- Is Pan control supported ? --*/
if (m_line.isControlSupported(FloatControl.Type.PAN)) {
m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN);
}
}
}
/**
* Opens the line.
*/
private void openLine() throws LineUnavailableException {
if (m_line != null) {
AudioFormat audioFormat = m_audioInputStream.getFormat();
m_line.open(audioFormat, m_line.getBufferSize());
}
}
/**
* Stops the playback.<br>
*
* Player Status = STOPPED.<br>
* Thread should free Audio ressources.
*/
protected void stopPlayback() {
if ( (m_status == PLAYING) || (m_status == PAUSED)) {
if (m_line != null) {
m_line.flush();
m_line.stop();
ifPaused=false;
}
m_status = STOPPED;
}
}
/**
* Pauses the playback.<br>
*
* Player Status = PAUSED.
*/
public void pausePlayback() {
if (m_line != null) {
if (m_status == PLAYING) {
m_line.flush();
m_line.stop();
m_status = PAUSED;
ifPaused=true;
}
}
}
/**
* Resumes the playback.<br>
*
* Player Status = PLAYING.
*/
public void resumePlayback() {
if (m_line != null) {
if (m_status == PAUSED) {
m_line.start();
m_status = PLAYING;
ifPaused=false;
}
}
}
/**
* Starts playback.
*/
public String startPlayback() {
if ( (m_status == STOPPED) || (m_status == READY)) {
if (! (m_thread == null || !m_thread.isAlive())) {
while (m_status != READY) {
try {
if (m_thread != null) {
m_thread.sleep(1000);
}
}
catch (Exception e) {
}
}
}
try {
initLine();
}
catch (Exception e) {
//e.printStackTrace();
return "ERROR";
}
m_thread = new Thread(this);
m_thread.start();
if (m_line != null) {
m_line.start();
ifPaused=false;
}
}
return null;
}
/**
* Main loop.
*
* Player Status == STOPPED => End of Thread + Freeing Audio Ressources.<br>
* Player Status == PLAYING => Audio stream data sent to Audio line.<br>
* Player Status == PAUSED => Waiting for another status.
*/
public void run() {
if (m_audioInputStream.markSupported()) m_audioInputStream.mark(m_audioFileFormat.getByteLength());
int nBytesRead = 1;
m_status = PLAYING;
int nBytesCursor = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
float nFrameSize = (float) m_line.getFormat().getFrameSize();
float nFrameRate = m_line.getFormat().getFrameRate();
float bytesPerSecond = nFrameSize * nFrameRate;
int secondsTotal = Math.round( (float) m_audioFileFormat.getByteLength() /
bytesPerSecond);
while ( (nBytesRead != -1) && (m_status != STOPPED)) {
if (m_status == PLAYING) {
try {
// Seek implementation.
if (doSeek > -1) {
if ( (secondsTotal != AudioSystem.NOT_SPECIFIED) &&
(secondsTotal > 0)) {
m_line.flush();
m_line.stop();
//m_audioInputStream.reset();
m_audioInputStream.close();
m_audioInputStream = AudioSystem.getAudioInputStream(_file);
nBytesCursor = 0;
if (m_audioFileFormat.getByteLength() - doSeek < abData.length) {
doSeek = m_audioFileFormat.getByteLength() - abData.length;
}
doSeek = doSeek - doSeek % 4;
int toSkip = (int) doSeek;
// skip(...) instead of read(...) runs out of memory ?!
while ( (toSkip > 0) && (nBytesRead > 0)) {
if (toSkip > abData.length) {
nBytesRead = m_audioInputStream.read(abData, 0, abData.length);
}
else {
nBytesRead = m_audioInputStream.read(abData, 0, toSkip);
}
toSkip = toSkip - nBytesRead;
nBytesCursor = nBytesCursor + nBytesRead;
}
m_line.start();
}
else {
}
doSeek = -1;
}
nBytesRead = m_audioInputStream.read(abData, 0, abData.length);
}
catch (Exception e) {
}
if (nBytesRead >= 0) {
if (m_bpl != null) {
m_bpl.updateMediaData(abData);
}
int nBytesWritten = m_line.write(abData, 0, nBytesRead);
nBytesCursor = nBytesCursor + nBytesWritten;
if (m_bpl != null) {
m_bpl.updateCursor( (int) Math.round( (float) nBytesCursor /
bytesPerSecond), secondsTotal);
}
}
}
else {
try {
Thread.sleep(1000);
}
catch (Exception e) {
}
}
}
if (m_line != null) {
try {
m_line.drain();
m_line.stop();
m_line.close();
}
catch (Exception e) {
}
finally {
m_line = null;
}
}
m_status = READY;
if (m_bpl != null) {
m_bpl.updateMediaState("EOM");
}
}
/*----------------------------------------------*/
/*-- Gain Control --*/
/*----------------------------------------------*/
/**
* Returns true if Gain control is supported.
*/
public boolean hasGainControl() {
return m_gainControl != null;
}
/**
* Sets Gain value.
* Linear scale 0.0 <--> 1.0
* Threshold Coef. : 1/2 to avoid saturation.
*/
public void setGain(double fGain) {
if (hasGainControl()) {
double minGainDB = getMinimum();
double ampGainDB = ( (10.0f / 20.0f) * getMaximum()) - getMinimum();
double cste = Math.log(10.0) / 20;
double valueDB = minGainDB +
(1 / cste) * Math.log(1 + (Math.exp(cste * ampGainDB) - 1) * fGain);
//trace(1,getClass().getName(), "Gain : "+valueDB);
m_gainControl.setValue( (float) valueDB);
}
}
/**
* Returns Gain value.
*/
public float getGain() {
if (hasGainControl()) {
return m_gainControl.getValue();
}
else {
return 0.0F;
}
}
/**
* Gets max Gain value.
*/
public float getMaximum() {
if (hasGainControl()) {
return m_gainControl.getMaximum();
}
else {
return 0.0F;
}
}
/**
* Gets min Gain value.
*/
public float getMinimum() {
if (hasGainControl()) {
return m_gainControl.getMinimum();
}
else {
return 0.0F;
}
}
/*----------------------------------------------*/
/*-- Pan Control --*/
/*----------------------------------------------*/
/**
* Returns true if Pan control is supported.
*/
public boolean hasPanControl() {
return m_panControl != null;
}
/**
* Returns Pan precision.
*/
public float getPrecision() {
if (hasPanControl()) {
return m_panControl.getPrecision();
}
else {
return 0.0F;
}
}
/**
* Returns Pan value.
*/
public float getPan() {
if (hasPanControl()) {
return m_panControl.getValue();
}
else {
return 0.0F;
}
}
/**
* Sets Pan value.
* Linear scale : -1.0 <--> +1.0
*/
public void setPan(float fPan) {
if (hasPanControl()) {
//trace(1,getClass().getName(), "Pan : "+fPan);
m_panControl.setValue(fPan);
}
}
/*----------------------------------------------*/
/*-- Seek --*/
/*----------------------------------------------*/
/**
* Sets Seek value.
* Linear scale : 0.0 <--> +1.0
*/
public void setSeek(double seek) throws IOException {
double length = -1;
if ( (m_audioFileFormat != null) &&
(m_audioFileFormat.getByteLength() != AudioSystem.NOT_SPECIFIED)) {
length = (double) m_audioFileFormat.getByteLength();
}
long newPos = (long) Math.round(seek * length);
doSeek = newPos;
}
/*----------------------------------------------*/
/*-- Audio Format --*/
/*----------------------------------------------*/
/**
* Returns AudioFormat.
*/
public AudioFormat getAudioFormat() {
if (m_audioInputStream != null) {
return m_audioInputStream.getFormat();
}
else {
return null;
}
}
/**
* Returns AudioFileFormat.
*/
public AudioFileFormat getAudioFileFormat() {
if (m_audioFileFormat != null) {
return m_audioFileFormat;
}
else {
return null;
}
}
/**
* Gets an InputStream from File.
*/
protected InputStream openInput(File file) throws IOException {
InputStream fileIn = new FileInputStream(file);
BufferedInputStream bufIn = new BufferedInputStream(fileIn);
return bufIn;
}
public void ready(File f){
try {
openInput(f);
setDataSource(f);
}
catch (IOException ex1) {
}
catch (LineUnavailableException ex1) {
}
catch (UnsupportedAudioFileException ex1) {
}
}
public boolean ifPaused(){
return ifPaused;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -