Я открываю targetdataline, чтобы принимать аудиовход для заданного формата. Я запускаю и открываю строку, и у меня есть буфер, который заполняется байтами. Это выполняется в постоянном цикле до тех пор, пока не будет изменен внешний параметр.
Теперь, для фиксированной частоты дискретизации и размера буфера, я ожидал бы, что это всегда будет занимать одинаковое количество времени для заполнения, т.е. если мой размер буфера был 48000 для 8-битного потока, а моя частота дискретизации была 48 кГц, я бы ожидал, что мой буфер чтобы заполнение всегда занимало 1 секунду. Однако я считаю, что это сильно различается.
Вот код, который я использовал:
DataLine.Info info1 = new DataLine.Info(TargetDataLine.class, format1);
try (TargetDataLine line = (TargetDataLine) m1.getLine(info1)) {
line.open(format1);
line.start();
while (!pauseInput){
long time1 = System.currentTimeMillis();
int numBytesRead1 = line.read(buffer1, 0, buffer1.length);
//chan1double = deinterleaveAudio(buffer1, chan1selectedchannel, chan1totalchannels);
long time2 = System.currentTimeMillis();
System.out.println(threadName + " Capture time = " + (time2-time1));
}
line.stop();
}
Прокомментированная строка - это процесс, который я хочу запускать каждый раз, когда буфер заполняется. Я понимаю, что не могу разместить это здесь, так как это прервет поток, поэтому мне нужно найти другой способ вызвать это, поэтому я закомментировал.
Для целей тестирования у меня размер буфера 4096. Мой аудиоформат 48 кГц 16 бит, поэтому я ожидаю, что мой байтовый буфер будет заполнен за 42,6 мс. ((1/48000) * 2048). (это умножается на половину размера буфера, поскольку каждая выборка составляет два байта). Однако, используя currentTimeMillies для измерения каждого прохода, он возвращается с 123 мс и 250 мс и варьируется между этими временами.
Есть ли здесь что-то, что я не сделал?
Обновлено: Я скопировал только код в совершенно новое приложение, у которого даже нет графического интерфейса или чего-либо, прикрепленного к нему. Чисто для вывода на консоль и наблюдения за происходящим, чтобы убедиться, что нет фоновых потоков, которые могли бы помешать, и, конечно же, происходит то же самое. В 95% случаев буфер с прогнозируемым временем заполнения 250 мс заполняется в пределах 255–259 мс. Однако иногда это падает до 127 мс (что физически невозможно, если не происходит какой-то странный буфер. Это ошибка где-то в java?




Я не думаю, что такая регулировка времени - хорошая идея. Это зависит от многих вещей, например, размера буфера, микшера и т. д. Более того, ваше приложение совместно с микшером использует буфер строки. Если у вас есть обработка в реальном времени, сохраните ваши данные в кольцевой буфер с длиной, достаточной для хранения необходимого вам количества данных. В другом потоке считайте желаемый объем данных из кольцевой буфер и выполняйте обработку с постоянным интервалом времени. Таким образом, иногда вы можете перекрывать или пропускать некоторые байты между двумя последовательными обработками, но у вас всегда есть ожидаемое количество байтов.
Когда вы открываете строку, вы можете указать размер буфера строки, используя open(format, bufferSize), или вы можете проверить фактический размер буфера с помощью
вызов DataLine.getBufferSize(). Затем вам нужно указать размер вашего короткого буфера, который вы предоставляете при извлечении данных через TargetDataLine.read(). Ваш короткий размер буфера должен быть меньше размера буфера строки. Я бы рассмотрел короткий размер буфера как 1/4, 1/8, 1/16 или около того от размера буфера строки. Другая идея - проверить доступные байты DataLine.available() перед вызовом read(). Обратите внимание, что read() - это блокирующий вызов (но он не блокирует буфер строки), т.е. он будет зависать до тех пор, пока не будет прочитано запрошенное количество байтов.
Для прямой связи с малой задержкой между вашим приложением и аудиоинтерфейсом вы можете рассмотреть ASIO.
Для тех, кто рассматривает ту же проблему, я получил ответ, половина которого объясняет, что происходит.
Планировщик потоков решает, когда код может быть запущен, и это может привести к изменению этого значения на 10-20 мс. Раньше это было 70 мс. Это не означает, что в потоке отсутствуют сэмплы, это просто означает, что этот буфер не будет обеспечивать непрерывный поток. Таким образом, любое приложение, которое рассматривает обработку этих данных в реальном времени и передачу их для записи в выходной аудиопоток, должно учитывать эту дополнительную потенциальную задержку.
Я все еще ищу причину короткого времени заполнения буфера, каждые четыре или пять проходов. Мне сказали, что это может быть связано с тем, что размер буфера targetDataLine отличается от моего размера буфера, и на этом проходе записывается только остаток этого буфера, однако я изменил его, чтобы он был точно таким же, и все равно не повезло.
Спасибо за ваш ответ. Но я сбит с толку. Я не собираюсь регулировать время. Меня больше смущает, почему время, необходимое для заполнения буфера, варьируется. Для заполнения буфера того же размера должно потребоваться такое же количество миллисекунд, если время меняется, это приводит к проблемам с дрожанием или изменениям высоты тона. Я бы очень хотел реализовать кольцевой буфер, как было предложено. Но если аудиопоток подвержен колебаниям времени с использованием звука Java, возможно, мне лучше использовать другой интерфейс для оборудования. Я читал о нескольких реализациях C, которые обернуты с помощью JNI.