java中的连续音频流

java中的连续音频流,java,multithreading,synchronization,Java,Multithreading,Synchronization,我正在学习使用Java的声音API。我在YouTube上观看了一段视频,其中讲师只需创建SourceDataLine和TargetDataLine实例,并在单独的线程中使用它们。他使用Thread.sleep()方法一个接一个地调用线程。在这段睡眠时间内,捕捉到所需的声音,然后听到声音 现在,在下面的程序中,我尝试扩展这个想法,并尝试实现连续的音频流。也就是说,我会说话,声音会自动被听到。但这是不可能实现的。我知道我错了,因为我在这方面还是个新手。我应该在哪里做什么更改?如果在录音和播放声音之间

我正在学习使用Java的声音API。我在YouTube上观看了一段视频,其中讲师只需创建SourceDataLine和TargetDataLine实例,并在单独的线程中使用它们。他使用Thread.sleep()方法一个接一个地调用线程。在这段睡眠时间内,捕捉到所需的声音,然后听到声音

现在,在下面的程序中,我尝试扩展这个想法,并尝试实现连续的音频流。也就是说,我会说话,声音会自动被听到。但这是不可能实现的。我知道我错了,因为我在这方面还是个新手。我应该在哪里做什么更改?如果在录音和播放声音之间有令人满意的延迟,这不会是一个问题

p.S.我将在另一个程序中尝试将其与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();
    }
}