2016-12-13 12 views
0

Я думаю, что у меня проблема с производительностью (латентностью) с Java Sound API.API Java Sound: попытка мониторинга входного микрофона в реальном времени Slow

аудиомонитора

Следующий код действительно работает для меня. Он правильно открывает микрофон и выводит аудиосигнал через мои динамики в реальном времени (т. Е. Мониторинг). Но мое беспокойство - это скорость, с которой происходит воспроизведение ... это на полсекунды сзади, когда я говорю в своем микрофоне до воспроизведения через мои динамики.

Как увеличить производительность? Как снизить задержку?

private void initForLiveMonitor() { 

    AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false); 

    try { 

     //Speaker 
     DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 
     SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(info); 
     sourceLine.open(); 

     //Microphone 
     info = new DataLine.Info(TargetDataLine.class, format); 
     TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info); 
     targetLine.open(); 

     Thread monitorThread = new Thread() { 
      @Override 
      public void run() { 
       targetLine.start(); 
       sourceLine.start(); 

       byte[] data = new byte[targetLine.getBufferSize()/5]; 
       int readBytes; 

       while (true) { 
        readBytes = targetLine.read(data, 0, data.length); 
        sourceLine.write(data, 0, readBytes); 
       } 
      } 
     }; 

     System.out.println("Start LIVE Monitor for 15 seconds"); 
     monitorThread.start(); 

     Thread.sleep(15000); 
     targetLine.stop(); 
     targetLine.close(); 
     System.out.println("End LIVE Monitor"); 

    } 
    catch(LineUnavailableException lue) { lue.printStackTrace(); } 
    catch(InterruptedException ie) { ie.printStackTrace(); } 


} 

Дополнительные примечания

  • С помощью этого кода, воспроизведение не является гладкой (не выскакивает ни испуг), только половина второго замедленные.
  • Я также знаю, что мой компьютер и интерфейс USB Audio способны обрабатывать мониторинг в реальном времени через компьютер, потому что, когда я сравниваю бок о бок с Logic Pro X, есть минимальные задержки - я не вижу задержки вообще.
  • Мои попытки уменьшить размер/размер байта [] не помогли.

Мое заключение заключается в том, что это проблема Java-кода, которая у меня есть. Заранее спасибо.

+0

Казалось бы, дело доходит до того, насколько велика 'targetLine.getBufferSize()'. Сколько байтов это? –

+0

@AndrewThompson Метод 'targetLine.getBufferSize()' возвращает 88200 байт. Я уже играл с делителем 'byte []' с небольшими изменениями. Когда я вывел 'byte []' явно до 4 байтов, это действительно помогло, но я все еще ощущаю задержку в четверть секунды (с более чем половины второй задержки). –

+0

Размер байта [], который вы установили, не относится к буфере в DataLine. Вы должны указать размер в методах open() для установки размеров буфера DataLine, например. .Open (размер). 88200 байт с 4 байтами на кадр и 44100 кадров в секунду учитывает задержку в полсекунды. Сокращение слишком сильно может привести к выпадениям, но я уверен, что есть безопасные значения, которые вы можете установить с меньшей задержкой. См. Мой ответ ниже. –

ответ

1

Существует более одного буфера!

Когда вы открываете SourceDataLine и TargetDataLine, я бы рекомендовал использовать форму, в которой вы указываете размер буфера. Но я не знаю, какой размер рекомендовать. Я не играл с этим достаточно, чтобы узнать, какой оптимальный размер для безопасного ввода микрофона - мой опыт больше связан с синтезом в реальном времени.

В любом случае, как насчет этого: определите длину данных [] и используйте ту же длину в методах открытия линии. Попробуйте цифры, такие как 1024 или несколько (при том, что количество байтов может быть равномерно разделено на количество кадров в байтах, которое выглядит 4 в соответствии с используемым вами форматом).

int bufferLen = 1024 * 4; // experiment with buffer size here 

byte[] data = new byte[bufferLen]; 
sourceLine.open(bufferLen); 
targetLine.open(bufferLen); 

Кроме того, возможно, код в бегах() был бы лучше поместить в другом месте, чтобы не добавить к требуемой обработке, прежде чем трубопровод может даже начать. Данные массива [] и int readBytes могут быть переменными экземпляра и готовы к свертке, а не быть помеченными в run(), потенциально добавляя к задержке.

Это все, что я бы попробовал.

+0

«Данные массива [] и int readBytes могут быть переменными экземпляра и готовы к качке, а не быть помеченными в run(), потенциально добавляя к задержке». это мелкие чипсы в большом картофеле; если он говорит, что он пробовал разные размеры буфера, то вот он! - «В нем задействовано более одного буфера!»: Где? Я хотел бы узнать, где именно? и это повлияет на его производительность. – gpasch

+0

API явно говорит об установке размера буфера для DataLines. http://docs.oracle.com/javase/8/docs/api/javax/sound/sampled/SourceDataLine.html#open-javax.sound.sampled.AudioFormat-int- Существует также один для TargetDataLine. –

+0

Спасибо, Фил. Да, латентность действительно снизилась с установкой bufferSize для обоих методов open(). Я бы оценил, что латентность теперь улучшается до 10-й секунды (лучше от четверти секунды). И эксперимент с размером буфера 1024 * 2 работал без проблем с искажениями. Идти ниже, что вызвало слышимые проблемы. –

 Смежные вопросы

  • Нет связанных вопросов^_^