Понимание Java ByteArrayOutputStream и ByteArrayInputStream

Я читал эту статью: http://www.java-tips.org/java-se-tips-100019/120-javax-sound/917-capturing-audio-with-java-sound-api..html Я не хочу писать весь код из предыдущей статьи...

Мне нужно уточнить мое понимание, и мне нужно объяснить использование ByteArrayInputStream и ByteArrayOutputStream...

На основе полного кода:

В методе captureAudio(), фокусируясь на цикле во время

while (running) {
  int count = line.read(buffer, 0, buffer.length);
    if (count > 0) {
      out.write(buffer, 0, count);
    }
}
out.close();

По определению (проверьте строки 64 и 65):

final TargetDataLine line = (TargetDataLine)
    AudioSystem.getLine(info);

на строке 79: линия является микрофоном и // считывает аудиоданные из входного буфера строки данных. Другими словами, байты, поступающие от микрофона, размещаются или сохраняются в байтах buffer.

В строке 81:

      out.write(buffer, 0, count);

out — это объект ByteArrayOutputStream.

Класс ByteArrayOutputStream API Java IO позволяет захватывать данные, записанные в поток, в виде массива. Вы записываете свои данные в ByteArrayOutputStream, и когда вы закончите, вы вызываете метод ByteArrayOutputStream toByteArray() для получения всех записанных данных в массиве байтов. Буфер автоматически увеличивается по мере записи в него данных.

Другими словами: ByteArrayOutputStream будет расти, беря байты из буфера, определенного в количестве count

С другой стороны:

В методе playAudio().

Я вижу, что первая строка (строка 101 полного кода) занята всеми байтами!!!

byte audio[] = out.toByteArray();

https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayOutputStream.html#toByteArray()

Создает вновь выделенный массив байтов. Его размер равен текущему размеру этого выходного потока, и в него было скопировано действительное содержимое буфера.

Теперь в строках (102 и 103)

InputStream input = 
    new ByteArrayInputStream(audio);

В строках (от 105 до 107) байты передаются:

  final AudioInputStream ais = 
    new AudioInputStream(input, format, 
    audio.length / format.getFrameSize());

фокусировка в цикле while и рядом с линиями

int count;
while ((count = ais.read(
  buffer, 0, buffer.length)) != -1) {
    if (count > 0) {
      line.write(buffer, 0, count);
    }
  }
line.drain();
line.close();

Байты берутся из ais

А линия (строки 110 и 111) представляет динамики

  final SourceDataLine line = (SourceDataLine)
    AudioSystem.getLine(info);

Вопрос 1:

out из метода captureAudio будет принимать байты бесконечно, но как input из метода playAudio берет ровно столько байтов, сколько требуется для последовательного звучания?

Помните: out.toByteArray(); берут все байты, но динамики не повторяют одни и те же байты...

Вопрос 2:

Могу ли я справиться с этой ситуацией, читая с микрофона (TargetDataLine) и записывая в динамик (SourceDataLine), не используя эти два объекта (ByteArrayOutputStream и ByteArrayInputStream), как в соответствующей статье?

Как следующий код:

while (running) {
  int count = microphone.read(buffer, 0, buffer.length);
    if (count > 0) {
      speaker.write(buffer, 0, count);
    }
}
speaker.drain();
speaker.close();

Вопрос 3:

Как я могу реализовать повторитель (захватывать звук с микрофона и воспроизводить его на динамиках, бесконечно, 1 или 2 часа)?

Примечание: не беспокоясь о проблемах с хранением байтов в памяти (без сохранения в файл) без задержек воспроизведения.


person QA_Col    schedule 20.02.2016    source источник
comment
сначала мы должны понять вас! - это непонятно - может быть, вам лучше опубликовать это на испанском или другом языке   -  person gpasch    schedule 20.02.2016
comment
@gpasch, какой текст, по-вашему, непонятен?   -  person QA_Col    schedule 21.02.2016


Ответы (1)


Я не знаком с Sound API.

Но нет особой причины, по которой ваш последний фрагмент кода не должен работать, предполагая, что ввод можно бесконечно читать, а вывод можно бесконечно подавать. Единственная проблема заключается в том, «зависает» ли один конец или другой (здесь играет роль мое отсутствие знаний о звуковом API).

Если выходная сторона по какой-то причине останавливается, то входная сторона потенциально может переполнить некоторый внутренний буфер, что приведет к потере информации. Если вход останавливается, это не такая уж проблема. Я не знаю, является ли это реальной проблемой с Sound API. Напротив, если бы было два потока (или с использованием асинхронного ввода-вывода), один управляющий вводом, а другой управляющий выводом, сторона ввода даст вашей программе возможность кэшировать входящие данные, используя вашу семантику, а не API-интерфейсы. семантики, в то время как выходной канал остановлен.

Проблемы с ByteArrayStreams — это просто механизмы для заполнения и расширения каждого массива байтов без самостоятельного управления им и, аналогично, добавления семантики потока к базовому массиву байтов (который имеет всевозможные полезные возможности).

person Will Hartung    schedule 20.02.2016
comment
Спасибо, я думаю, что ByteArrayOutputStream и ByteArrayInputStream будут расти, но оба должны сокращаться (с одной стороны будут вводиться байты, а с другой — удаляться). Как bytearrayoutputstream будет уменьшать свой размер (или снова будет пустым)?, потому что каждый out.write(buffer, 0, count); вызывается, bytearrayoutputstream будет расти, и как передается (точные последние прочитанные байты) в ByteArrayInputStream? или Как ByteArrayInputStream(audio); прочитать именно последние непрочитанные байты? out.toByteArray() здесь все байты (даже от первого до последнего байта) - person QA_Col; 22.02.2016