Непрерывный аудиопоток в java - PullRequest
1 голос
/ 06 августа 2020

Я учусь использовать звуковой 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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...