📄 captureplaybackclient.java
字号:
* createAudioInputStream(file, false);
*/
public class Playback
implements Runnable {
SourceDataLine line;
Thread thread;
public void start() {
errStr = null;
thread = new Thread(this);
thread.setName("Playback");
thread.start();
}
public void stop() {
thread = null;
}
private void shutDown(String message) {
if ( (errStr = message) != null) {
System.err.println(errStr);
samplingGraph.repaint();
}
if (thread != null) {
thread = null;
samplingGraph.stop();
captB.setEnabled(true);
pausB.setEnabled(false);
playB.setText("Play");
}
}
//实现播放线程
public void run() {
// 如果audioInputStream由文件载入,我们将重载播放的文件reload the file if loaded by file
if (file != null) {
createAudioInputStream(file, false); //false表示不用更新audioInputStream的格式
}
// audioInputStream不能为空,make sure we have something to play
if (audioInputStream == null) {
shutDown("No loaded audio to play back");
return;
}
// 复位流媒体,reset to the beginnning of the stream
try {
audioInputStream.reset();
}
catch (Exception e) {
shutDown("Unable to reset the stream\n" + e);
return;
}
//得到期望的格式信息!get an AudioInputStream of the desired format for playback
AudioFormat format = formatControls.getFormat();
// !!!将输入的流对象audioInputStream,格式化后得到一个标准的流对象playbackInputStream
AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(
format, audioInputStream);
if (playbackInputStream == null) {
shutDown("Unable to convert stream of format " + audioInputStream +
" to format " + format);
return;
}
// 为我们的line定义需要的属性;define the required attributes for our line,
// 确定一个兼容的line格式;and make sure a compatible line is supported.
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
format);
//判断系统是否支持匹配这个Line.Info的line;
if (!AudioSystem.isLineSupported(info)) {
shutDown("Line matching " + info + " not supported.");
return;
}
//从AudioSystem中得到期望的格式line,类型化为SourceDataLine以用于读取;get and open the source data line for playback.
try {
line = (SourceDataLine) AudioSystem.getLine(info);
//causing the line to acquire any required system resources and become operational
line.open(format, bufSize);
}
catch (LineUnavailableException ex) {
shutDown("Unable to open the line: " + ex);
return;
}
//对line的操作次序:open();getBufferSize();start();write(data,0,num);drain();
/**
* line的最大BufferSize是16384;一个frame大小由AudioFormat决定;frame大小乘上(buffer里的frame数量)=这里line实际用的bufferData大小
*/
// 重放捕获的声音数据 play back the captured audio data
//**frame大小由AudioFormat决定,这里为4字节长;
int frameSizeInBytes = format.getFrameSize();
//For a source data line, this is maximum size of the buffer to which data can be written. For a target data line, it is maximum size of the buffer from which data can be read.
int bufferLengthInFrames = line.getBufferSize() / 8;
//bufferLengthInBytes为8192----bufferLengthInFrames为2048
int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
//在线程里,data被不断初始化!
byte[] data = new byte[bufferLengthInBytes];
int numBytesRead = 0;
// Allows a line to engage in data I/O.(the line must be flushed or stoped)
line.start();
//playbackInputStream->data[]->dataline
while (thread != null) {
try {
//取出playbackInputStream并写到字节流data[byte]中!返回事实读取的量,跳出。
if ( (numBytesRead = playbackInputStream.read(data)) == -1) {
break;
}
int numBytesRemaining = numBytesRead;
while (numBytesRemaining > 0) {
//line.write(data, 0, numBytesRemaining)返回已写入line的数据数量
numBytesRemaining -= line.write(data, 0, numBytesRemaining);
}
}
catch (Exception e) {
shutDown("Error during playback: " + e);
break;
}
}
// 向line写完字节流,结束when reached the end of the stream,let the data play out, then
// stop and close the line.
if (thread != null) {
//排出Drains queued data from the line by continuing data I/O until line's internal buffer has been emptied.
line.drain();
//line.flush()---Flushes queued data from the line.
}
line.stop();
line.close();
line = null;
shutDown(null);
}
} // End class Playback
/**
* 从输入渠道中捕获数据,并写到输出流中;Reads data from the input channel and writes to the output stream
*/
class Capture
implements Runnable {
TargetDataLine line;
Thread thread;
public void start() {
errStr = null;
thread = new Thread(this);
//thread是有名字的;
thread.setName("Capture");
thread.start();
}
public void stop() {
thread = null;
}
private void shutDown(String message) {
if ( (errStr = message) != null && thread != null) {
thread = null;
samplingGraph.stop();
loadB.setEnabled(true);
playB.setEnabled(true);
pausB.setEnabled(false);
auB.setEnabled(true);
aiffB.setEnabled(true);
waveB.setEnabled(true);
captB.setText("Record");
connB.setText("连接");
System.err.println(errStr);
samplingGraph.repaint();
}
}
public void run() {
duration = 0;
//将audioInputStream置空!
audioInputStream = null;
// define the required attributes for our line,
// and make sure a compatible line is supported.
AudioFormat format = formatControls.getFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class,
format);
if (!AudioSystem.isLineSupported(info)) {
shutDown("Line matching " + info + " not supported.");
return;
}
// 获得并打开目标dataline来捕获get and open the target data line for capture.
try {
line = (TargetDataLine) AudioSystem.getLine(info);
//这里将获得声音!!
line.open(format, line.getBufferSize());
}
catch (LineUnavailableException ex) {
shutDown("Unable to open the line: " + ex);
return;
}
catch (SecurityException ex) {
shutDown(ex.toString());
// JavaSound.showInfoDialog();
return;
}
catch (Exception ex) {
shutDown(ex.toString());
return;
}
// line.read(data[])——播放
ByteArrayOutputStream out = new ByteArrayOutputStream();
int frameSizeInBytes = format.getFrameSize();
int bufferLengthInFrames = line.getBufferSize() / 8;
int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
byte[] data = new byte[bufferLengthInBytes];
int numBytesRead;
line.start();
while (thread != null) {
if ( (numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
break;
}
out.write(data, 0, numBytesRead);
}
// we reached the end of the stream. stop and close the line.
line.stop();
line.close();
line = null;
// 停止和关闭输出流stop and close the output stream
try {
out.flush();
out.close();
}
catch (IOException ex) {
ex.printStackTrace();
}
// !!!将输入流载入到audioInputStream对象中!load bytes into the audio input stream for playback
byte audioBytes[] = out.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
audioInputStream = new AudioInputStream(bais, format,
audioBytes.length /
frameSizeInBytes);
long milliseconds = (long) ( (audioInputStream.getFrameLength() * 1000) /
format.getFrameRate());
duration = milliseconds / 1000.0;
try {
audioInputStream.reset();
}
catch (Exception ex) {
ex.printStackTrace();
return;
}
//在捕获的线程里调用画图!hlf //kehu---duankai2---huahua
samplingGraph.createWaveForm(audioBytes);
}
} // End class Capture
/**
* 画波形图.//hlf!!
*/
class SamplingGraph
extends JPanel
implements Runnable {
private Thread thread;
private Font font10 = new Font("serif", Font.PLAIN, 10);
private Font font12 = new Font("serif", Font.PLAIN, 12);
//深色底面
Color jfcBlue = new Color(204, 204, 255);
//粉色画当前位置线
Color pink = new Color(255, 175, 175);
public SamplingGraph() {
setBackground(new Color(20, 20, 20));
}
//画波形图!
public void createWaveForm(byte[] audioBytes) {
lines.removeAllElements(); // clear the old vector
AudioFormat format = audioInputStream.getFormat();
if (audioBytes == null) {
try {
audioBytes = new byte[ (int) (audioInputStream.getFrameLength()
* format.getFrameSize())];
audioInputStream.read(audioBytes);
}
catch (Exception ex) {
reportStatus(ex.toString());
return;
}
}
Dimension d = getSize();
int w = d.width;
int h = d.height - 15;
int[] audioData = null;
if (format.getSampleSizeInBits() == 16) {
int nlengthInSamples = audioBytes.length / 2;
audioData = new int[nlengthInSamples];
if (format.isBigEndian()) {
for (int i = 0; i < nlengthInSamples; i++) {
/* First byte is MSB (high order) */
int MSB = (int) audioBytes[2 * i];
/* Second byte is LSB (low order) */
int LSB = (int) audioBytes[2 * i + 1];
audioData[i] = MSB << 8 | (255 & LSB);
}
}
else {
for (int i = 0; i < nlengthInSamples; i++) {
/* First byte is LSB (low order) */
int LSB = (int) audioBytes[2 * i];
/* Second byte is MSB (high order) */
int MSB = (int) audioBytes[2 * i + 1];
audioData[i] = MSB << 8 | (255 & LSB);
}
}
}
else if (format.getSampleSizeInBits() == 8) {
int nlengthInSamples = audioBytes.length;
audioData = new int[nlengthInSamples];
if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
for (int i = 0; i < audioBytes.length; i++) {
audioData[i] = audioBytes[i];
}
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -