[英]Delay with voice streams on java
我一直在研究從USB調制解調器撥打電話的Java項目。 該應用程序可以在我的計算機上正常運行,但是當我嘗試在較低規格的計算機上運行該應用程序時,從PC進行呼叫的人的音頻流可以完美輸出,並且可以在所呼叫的電話中完美地聽到。 但是,PC用戶應該聽到的音頻會被延遲(3到5秒),並帶有白噪聲,實際上使進行對話變得不可能。
請注意以下幾點:
關於可能是什么問題或如何解決的任何線索?
啟動新線程后,處理音頻的類:(正在調用音頻)
public class SerialVoiceReader implements Runnable{
/** The running. */
private volatile boolean running = true;
/** The in. */
DataInputStream in;
/** The af. */
AudioFormat af;
/** The samples per frame. */
private int samplesPerFrame = 160;
/** The audio buffer size. */
private int audioBufferSize = samplesPerFrame * 2 ; //20ms delay
private String tel;
private String timestamp;
public SerialVoiceReader ( DataInputStream in, AudioFormat af){
this.in = in;
this.af = af;
}
public void run (){
try
{
Info infos = new Info(SourceDataLine.class, af);
SourceDataLine dataLine = (SourceDataLine) AudioSystem.getLine(infos);
dataLine.open(dataLine.getFormat(),audioBufferSize *2);
dataLine.start();
// set the volume up
if (dataLine.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
FloatControl volume = (FloatControl) dataLine.getControl(FloatControl.Type.MASTER_GAIN);
volume.setValue(volume.getMaximum());
}
// get a field from GUI to set as part of the file name
tel = CallGUI.telField.getText();
timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
// save the stream to a file to later set the header and make it .wav format
FileOutputStream fos = new FileOutputStream("Llamadas/" + timestamp + "-" + tel + "-OUT.raw");
// the audio buffer writing (this is the audio that goes out on the call)
while (running){
byte[] buffer = new byte[audioBufferSize];
int offset = 0;
int numRead = 0;
while (running && (offset < buffer.length && (numRead = this.in.read(buffer, offset, buffer.length - offset)) >= 0))
{
offset += numRead;
}
if(running && offset>=0){
dataLine.write(buffer, 0, offset);
fos.write(buffer);
}
}
dataLine.stop();
dataLine.drain();
dataLine.close();
fos.close();
}
catch ( Exception e )
{
}
}
在啟動新線程后處理音頻的類:(撥出呼叫音頻)
public class SerialVoiceWriter implements Runnable{
/** The running. */
private volatile boolean running = true;
/** The out. */
DataOutputStream out;
/** The af. */
AudioFormat af;
/** The samples per frame. */
private int samplesPerFrame = 160;
/** The audio buffer size. */
private int audioBufferSize = samplesPerFrame * 2; //20ms delay
private String tel;
private String timestamp;
public SerialVoiceWriter ( DataOutputStream out, AudioFormat af, Boolean playMessage)
{
this.out = out;
this.af = af;
}
public void run ()
{
try
{
Info infos = new Info(TargetDataLine.class, af);
TargetDataLine dataLine = (TargetDataLine) AudioSystem.getLine(infos);
dataLine.open(dataLine.getFormat(),audioBufferSize*2 );
dataLine.start();
tel = CallGUI.telField.getText();
timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
FileOutputStream fis = new FileOutputStream("Llamadas/" + timestamp + "-" + tel + "-IN.raw");
while (running){
byte[] audioBuffer = new byte[audioBufferSize];
int offset = 0;
int numRead = 0;
while (running && (offset < audioBuffer.length && (numRead = dataLine.read(audioBuffer, offset, audioBuffer.length - offset)) > 0))
{
offset += numRead;
}
if(running && offset>=0){
this.out.write(audioBuffer);
fis.write(audioBuffer);
}
}
dataLine.flush();
dataLine.stop();
dataLine.close();
fis.close();
dataLine = null;
}
catch (Exception e )
{
}
}
謝謝你的建議
您需要采取的步驟是:
OutputStream fos = new BufferedOutputStream( new FileOutputStream("Llamadas/" + timestamp + "-" + tel + "-OUT.raw"));
您將獲得大大提高的性能。 現在,循環的每次迭代都等待緩沖區完成寫入磁盤的方式。 物理磁盤速度很慢,這會導致大量等待。 這將需要更多的工作:與其並行寫入,而不是依次寫入dataLine和THEN然后依次寫入fos。 他們每個人都花費一定的時間將數據寫入各自的目的地。 如果fos花費X微秒,dataLine花費Y,則當前代碼花費X + Y微秒。 如果並行執行,則最終只能等待max(X,Y)。 `
ExecutorService es = Executors.newFixedThreadPool(2); Callable<Void>[] calls = new Callable[2]; //... your other code here... if (running && offset >= 0) { final int finalOffset = offset; Callable<Void> call1 = new Callable<Void>() { @Override public Void call() throws Exception { dataLine.write(buffer, 0, finalOffset); return null; } }; Callable<Void> call2 = new Callable<Void>() { @Override public Void call() throws Exception { fos.write(buffer); // or however you need to write. return null; } }; calls[0] = call1; calls[1] = call2; List<Callable<Void>> asList = Arrays.asList(calls); es.invokeAll(asList); // invokeAll will block until both callables have completed. }
`
我認為導致接近100%CPU的原因是罪魁禍首。 但這並不能告訴您任何具體的內容。 第一件事是,由於問題出在低端PC上,因此您可能需要檢查該設備上的音頻驅動程序是否最新。 之后,我將着眼於優化處理音頻回傳的部分代碼。 盡管較舊的PC規格較低,但我認為您嘗試實現的PC應該沒有任何問題。 我建議您在應用運行時運行性能分析器,以查看需要花費多長時間。
更新:您可以嘗試增加audioBufferSize來查看它是否有效果,20ms似乎很短。 提供的代碼僅用於從PC發送的音頻。 從電話接收的音頻怎么樣?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.