因此,我發現了一大堆代碼here,可以完成我所需要的操作。但是,我通過Jconsole
注意到它只是記錄和記錄數據,而不是釋放它。顯然沒有line.close()
的電話。這個問題是爲了確定數據是否傳遞良好(必須足夠大聲)線路必須不斷地記錄,因此關閉它不會允許進行這種決定。如果沒有line.close()
,有沒有辦法釋放line.read()
佔用的所有內存?我注意到我能夠在內存選項卡中從Jconsole
執行GC,但它在方式中調用的方式是System.gc()
。我知道的是你不應該調用的東西,但它似乎能夠清除緩衝區正在使用的內存,所以line.close()
似乎不是唯一的方法。如何清除`TargetDatatLine`讀取緩衝區
這裏是鏈接代碼,除了我掏出了GUI元素,並添加了我覺得應該執行GC的地方。
import javax.swing.SwingUtilities;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.TargetDataLine;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Control.Type;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.DataLine.Info;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class LevelMeter {
private float amp = 0f;
private float peak = 0f;
public void setAmplitude(float amp) {
this.amp = Math.abs(amp);
}
public void setPeak(float peak) {
this.peak = Math.abs(peak);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
LevelMeter meter = new LevelMeter();
new Thread(new Recorder(meter)).start();
}
});
}
static class Recorder implements Runnable {
final LevelMeter meter;
Recorder(final LevelMeter meter) {
this.meter = meter;
}
@Override
public void run() {
AudioFormat fmt = new AudioFormat(44100f, 16, 1, true, false);
final DataLine.Info info = new DataLine.Info(SourceDataLine.class, fmt, 1);
final SourceDataLine soundLine = (SourceDataLine) AudioSystem.getLine(info);
final int bufferByteSize = 2048;
TargetDataLine line;
try {
line = AudioSystem.getTargetDataLine(fmt);
line.open(fmt, bufferByteSize);
soundLine.open(fmt);
} catch(LineUnavailableException e) {
System.err.println(e);
return;
}
byte[] buf = new byte[bufferByteSize];
float[] samples = new float[bufferByteSize/2];
float lastPeak = 0f;
line.start();
for(int b; (b = line.read(buf, 0, buf.length)) > -1;) {
// convert bytes to samples here
for(int i = 0, s = 0; i < b;) {
int sample = 0;
sample |= buf[i++] & 0xFF; // (reverse these two lines
sample |= buf[i++] << 8; // if the format is big endian)
// normalize to range of +/-1.0f
samples[s++] = sample/32768f;
}
float rms = 0f;
float peak = 0f;
for(float sample : samples) {
float abs = Math.abs(sample);
if(abs > peak) {
peak = abs;
}
rms += sample * sample;
}
rms = (float)Math.sqrt(rms/samples.length);
if(lastPeak > peak) {
peak = lastPeak * 0.875f;
}
if(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory() > 7000000){
System.gc();
System.gc();
}
if(peak > 0.20){
sourceLine.start();
}
lastPeak = peak;
System.out.println(peak);
setMeterOnEDT(rms, peak);
}
}
void setMeterOnEDT(final float rms, final float peak) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
meter.setAmplitude(rms);
meter.setPeak(peak);
}
});
}
}
}
編輯:沒有,我意識到,這是因爲我不收線了就是爲什麼內存沒有釋放出來的原因。問題是我無法關閉線路,因爲我只需要抓住表示某人實際上正在對着麥克風說話的字節。如果我關閉了線路,那麼它就會有效地靜音,或者至少這是我的理解。但是,我已經設置了一個骯髒的方式來在上面更新的代碼中不時擦除緩衝區。我目前正試圖獲取這些字節,並在超過某個閾值時將它們播放出去。我可以從緩衝區中寫出另一行正在讀取的內容嗎?或者我必須設置第二個緩衝區來寫出來?
音頻代碼的絕大多數時間通常處於阻塞狀態,允許其他線程運行。除非有特定的問題,否則只要讓循環在自己的線程中運行,同時繼續監控就可能了。 –
這看起來像Java內存系統的正常操作。垃圾收集器將在必要時自動運行,無需調用它。 –