Я учусь использовать звуковой API Java. Я смотрел учебник на YouTube, где инструктор просто создает экземпляры SourceDataLine и TargetDataLine и использует их в отдельных потоках. Он вызывает потоки один за другим с промежуточным методом Thread.sleep (). В течение этого периода сна улавливается требуемый звук, а затем слышен звук.
Теперь, в программе ниже, я попытался расширить идею и попытался добиться непрерывного потока звука. То есть я буду говорить, и звук будет слышен автоматически. Но этого нельзя добиться. Я знаю, что ошибаюсь, поскольку я все еще новичок в этом отношении ie. Какие изменения нужно внести и где? Это не будет проблемой, если есть удовлетворительная задержка между записью и воспроизведением звука.
PS Я попробую использовать это с обменом видео OpenCV в другой программе. Если вы что-то знаете об этом, пожалуйста, поделитесь этим. Спасибо!
import javax.sound.sampled.*;
import java.io.ByteArrayOutputStream;
public class Main {
public boolean recording = true;
public int rate = 0;
public static void main(String[] args) throws Exception{
AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
final ByteArrayOutputStream out = new ByteArrayOutputStream();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
final TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info);
info = new DataLine.Info(SourceDataLine.class, format);
final SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(info);
Main m = new Main();
new record(m, format, out, targetLine);
new play(m, format, out, sourceLine);
}
synchronized public void record(TargetDataLine targetLine, ByteArrayOutputStream out){
while(!recording){
try{
wait();
}catch(Exception e){
System.out.println(e);
}
}
byte[] data = new byte[targetLine.getBufferSize()/5];
int readBytes;
readBytes = targetLine.read(data, 0, data.length);
out.write(data, 0, readBytes);
}
synchronized public void play(SourceDataLine sourceLine, ByteArrayOutputStream out){
while(recording){
try{
wait();
}catch(Exception e){
System.out.println(e);
}
}
sourceLine.write(out.toByteArray(), 0, out.size());
}
synchronized public int change(){
rate++;
if(rate > 6000 && recording){
rate = 0;
recording = false;
notifyAll();
return 1;
}
else if(rate > 6000 && !recording){
rate = 0;
recording = true;
notifyAll();
return 1;
}
return 0;
}
}
class record implements Runnable{
private Main m;
private AudioFormat format;
private ByteArrayOutputStream out;
final TargetDataLine targetLine;
public record(Main m, AudioFormat format, ByteArrayOutputStream out, TargetDataLine targetLine) throws Exception{
this.m = m;
this.format = format;
this.out = out;
this.targetLine = targetLine;
targetLine.open();
System.out.println("Started recording...");
new Thread(this).start();
}
@Override
public void run() {
targetLine.start();
while(true){
m.record(targetLine, out);
while(m.change() == 1) targetLine.stop();
targetLine.start();
}
}
}
class play implements Runnable{
private Main m;
private AudioFormat format;
private ByteArrayOutputStream out;
final SourceDataLine sourceLine;
public play(Main m, AudioFormat format, ByteArrayOutputStream out, SourceDataLine sourceLine) throws Exception{
this.m = m;
this.format = format;
this.out = out;
this.sourceLine = sourceLine;
sourceLine.open();
System.out.println("Started playing...");
new Thread(this).start();
}
@Override
public void run() {
sourceLine.start();
while(true){
m.play(sourceLine, out);
while(m.change() == 1) sourceLine.stop();
sourceLine.start();
}
}
}
Изменить:
Я могу запустить два потока один за другим, как показано ниже, но мне нужно жестко запрограммировать потоки. Я написал четыре темы индивидуально. Как я могу написать эффективный код, т.е. использовать два предыдущих потока и непрерывно записывать и воспроизводить звук? Моя синхронизация не работает.
import javax.sound.sampled.*;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) throws Exception{
AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
final SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open();
info = new DataLine.Info(TargetDataLine.class, format);
final TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(info);
targetLine.open();
final ByteArrayOutputStream out = new ByteArrayOutputStream();
Thread record = new Thread(){
@Override
public void run(){
targetLine.start();
byte[] data = new byte[targetLine.getBufferSize()/5];
int readBytes;
while(true){
readBytes = targetLine.read(data, 0, data.length);
out.write(data, 0, readBytes);
}
}
};
Thread play = new Thread(){
@Override
public void run(){
sourceLine.start();
while(true){
sourceLine.write(out.toByteArray(), 0, out.toByteArray().length);
}
}
};
final ByteArrayOutputStream out1 = new ByteArrayOutputStream();
Thread record1 = new Thread(() -> {
targetLine.start();
byte[] data = new byte[targetLine.getBufferSize()/5];
int readBytes;
while(true){
readBytes = targetLine.read(data, 0, data.length);
out1.write(data, 0, readBytes);
}
});
Thread play1 = new Thread(() -> {
sourceLine.start();
while(true){
sourceLine.write(out1.toByteArray(), 0, out1.toByteArray().length);
}
});
record.start();
System.out.println("Recording...");
Thread.sleep(4000);
targetLine.stop();
targetLine.drain();
targetLine.close();
play.start();
Thread.sleep(4000);
System.out.println("Playing...");
sourceLine.stop();
sourceLine.drain();
sourceLine.close();
targetLine.open();
sourceLine.open();
record1.start();
System.out.println("Recording...");
Thread.sleep(4000);
targetLine.stop();
targetLine.close();
play1.start();
Thread.sleep(4000);
System.out.println("Playing...");
sourceLine.stop();
sourceLine.close();
}
}