长时间执行期间Java Sound中出现意外延迟

时间:2018-05-03 14:49:53

标签: java javasound

我正在用Java编写音频聊天应用程序,并且我遇到了一些延迟/延迟,如果应用程序暂停运行一段时间,这些延迟/延迟通常会显示出来。

我在下面的示例应用程序中重新创建了该问题。它只是将声音从麦克风循环到扬声器。最初它的行为与预期一致。当您按下按钮并对着麦克风说话时,您会在扬声器中听到一声微小的延迟。但是,如果程序保持运行一段时间(一周),那么该延迟将增加到几秒钟。

我测试了不同的耳机。我使用Java 8,9,10进行了测试,它始终显示相同的行为。我还尝试了drain()和flush()等等,但唯一摆脱延迟的是关闭并重新创建TargetDataLine。但是重新创建该行不是我的应用程序的选项,因为它需要很长时间,并且在重新创建该行时音频不可用。

这是一个已知的限制还是我做错了什么?非常感谢任何见解或想法!

import javax.sound.sampled.*;
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * Created by asa on 2018-04-03.
 */
public class Main {


   public static void main(String[] args) throws LineUnavailableException {
      String title = "";
      if (args.length > 0) {
         title = args[0];
      }
      String mixerName = "USB”; // Part of the name of my headset
      if (args.length > 1) {
         mixerName = args[1];
      }
      AudioFormat format = new AudioFormat(8000f,
                                           16,
                                           1,
                                           true,
                                           false);
      DataLine.Info targetInfo = new TargetDataLine.Info(TargetDataLine.class, format);
      TargetDataLine mic = null;
      for (Mixer.Info info : AudioSystem.getMixerInfo()) {
         if (info.getName().contains(mixerName) && !info.getName().contains("Port")) {
            Mixer m = AudioSystem.getMixer(info);
            if (m.isLineSupported(targetInfo)) {
               mic = (TargetDataLine) m.getLine(targetInfo);
               break;
            }
         }
      }
      mic.open(format, 1280);
      mic.start();

      DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format);
      SourceDataLine speaker = null;
      for (Mixer.Info info : AudioSystem.getMixerInfo()) {
         if (info.getName().contains(mixerName) && !info.getName().contains("Port")) {
            Mixer m = AudioSystem.getMixer(info);
            if (m.isLineSupported(sourceInfo)) {
               speaker = (SourceDataLine) m.getLine(sourceInfo);
               break;
            }
         }
      }
      speaker.open(format, 8000);
      speaker.start();

      MicRunnable micRunnable = new MicRunnable(mic, speaker);
      new Thread(micRunnable).start();

      Frame.show(title, new Frame.PttListener() {
         @Override
         public void press() {
            micRunnable.start();
         }

         @Override
         public void release() {
            micRunnable.stop();
         }
      });
   }

   private static class MicRunnable implements Runnable {
      private final TargetDataLine _mic;
      private final SourceDataLine _speaker;

      private final Object runLock = new Object();
      private volatile boolean running = false;

      public MicRunnable(TargetDataLine mic, SourceDataLine speaker) {
         _mic = mic;
         _speaker = speaker;
      }

      public void start() {
         synchronized (runLock) {
            running = true;
            runLock.notify();
         }
      }

      public void stop() {
         synchronized (runLock) {
            running = false;
         }
      }

      @Override
      public void run() {
         while (true) {
            byte[] bytes = new byte[640];
            _mic.read(bytes, 0, bytes.length);
            if (running) {//tPeakGain(bytes) > 300) {
               _speaker.write(bytes, 0, bytes.length);
            }
         }
      }
   }

   private static class Frame extends JFrame {

      interface PttListener {
         void press();
         void release();
      }

      private Frame(String title, PttListener listener) {
         setTitle(title);
         JPanel content = new JPanel();

         JButton pttButton = new JButton("PTT");
         pttButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
               listener.press();
            }

            @Override
            public void mouseReleased(MouseEvent e) {
               listener.release();
            }
         });

         content.add(pttButton);

         setContentPane(content);
         setSize(300, 100);
      }

      public static void show(String title, Frame.PttListener pttListener) {
         new Frame(title, pttListener).setVisible(true);
      }
   }
}

0 个答案:

没有答案