【问题标题】:java Capture sound and hear it and record it to WAV simultaneouslyjava捕获声音并听到它并将其同时录制到WAV
【发布时间】:2017-11-17 01:11:37
【问题描述】:

我正在制作一个从麦克风捕获声音的程序,在扬声器上听到它(已经完成)并将其同时保存到 wav 文件。我正在寻找这个问题三四天。我相信,Stackoverflow 可以帮助我。

我需要做的就是将来自麦克风的声音写入一个 wav 文件,同时用户正在现场收听它。请帮助或指出正确的方向。我认为我可以以某种方式直接将字节写入文件,但由于缺少标头,这将是一团糟。

这是我的课:

public class RadioListener {
private Runnable mRunnable, mFounderR;
private Thread mThread, mFounderT;

private SourceDataLine mSourceLine;
private TargetDataLine mTargetLine;
private DataLine.Info mTargetInfo;
private DataLine.Info mSourceInfo;
private static final AudioFormat mFormat = new AudioFormat(44100, 16, 2, true, false);

private Mixer.Info[] mixers;
private Mixer mFoundMixer = null;

private Config mConfig;

private boolean isCommunicating = false;
private boolean isRetranslating = false;

File wavFile = null;
AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
AudioInputStream ais;

public RadioListener (Config cfg) {
    mConfig = cfg;

    mixers = AudioSystem.getMixerInfo();
    mSourceInfo = new DataLine.Info(SourceDataLine.class, mFormat);
    mTargetInfo = new DataLine.Info(TargetDataLine.class, mFormat);
    try {mSourceLine = (SourceDataLine) AudioSystem.getLine(mSourceInfo);}
    catch (LineUnavailableException e) {System.out.println("RadioListener output error");}

    wavFile = new File("E:/RecordAudio.wav");
}

public void Start() {
    if (Defines.strToIntDef(mConfig.getProperty("debugOut"), 0) == 1)
        showMixers();

    if (mFoundMixer == null) searchDevice();
    else startCommunication();
}

public void Stop() {
    if (mFoundMixer == null) return;

    try {
        mSourceLine.stop();
        mSourceLine.close();

        mTargetLine.stop();
        mTargetLine.close();
    } catch (Exception e) {}
    finally {
        isCommunicating = false;
    }
}

public void Mute() {
    isRetranslating = false;
}

private void searchDevice() {
    mFounderR = new RadioFinder();
    mFounderT = new Thread(mFounderR);
    mFounderT.start();
}

private void startThread() {
    startCommunication();
    mRunnable = new Communicator();
    mThread = new Thread(mRunnable);
    mThread.start();
}

private void startCommunication() {
    if (isCommunicating) {
        isRetranslating = true;
        return;
    }
    try {
        mTargetLine.open(mFormat);
        mTargetLine.start();

        mSourceLine.open(mFormat);
        mSourceLine.start();

        //Line line = mFoundMixer.getLine(mSourceInfo);
        //FloatControl control = (FloatControl)line.getControl(FloatControl.Type.MASTER_GAIN);
        //control.setValue(limit(control,10000));
        //control.setValue(-10);

        isCommunicating = true;
        isRetranslating = true;

        //When I'm uncommenting this two lines sound is writing to file, but I don't hear it.
        //ais = new AudioInputStream(mTargetLine);
        //AudioSystem.write(ais, fileType, wavFile);
    } catch (Exception e) {
        isCommunicating = false;
        isRetranslating = false;
    }
}

private class RadioFinder implements Runnable {
    @Override
    public void run() {
        Line.Info targetDLInfo = new Line.Info(TargetDataLine.class);
        for (Mixer.Info info : mixers) {
            Mixer tmp = AudioSystem.getMixer(info);
            //if (myMixer.isLineSupported(Port.Info.LINE_IN) || myMixer.isLineSupported(Port.Info.MICROPHONE)) {
            if (tmp.isLineSupported(targetDLInfo)) {
                String s = tmp.getMixerInfo().getName();
                if (s.toLowerCase().contains(mConfig.getProperty("radioName").toLowerCase())) {
                    mFoundMixer = tmp;
                    try {
                        mTargetInfo = new DataLine.Info(TargetDataLine.class, mFormat);
                        mTargetLine = (TargetDataLine) mFoundMixer.getLine(mTargetInfo);

                        System.out.println("Found radio device: " + mFoundMixer.getMixerInfo().getName());

                        startThread();
                    } catch (Exception e) {
                        System.out.println("RadioListener input error");
                        mFoundMixer = null;
                    }
                    break;
                }
            }
        }
    }
}

private static void showMixers() {
    ArrayList<Mixer.Info> mixInfos = new ArrayList<Mixer.Info>(Arrays.asList(AudioSystem.getMixerInfo()));

    Line.Info sourceDLInfo = new Line.Info(SourceDataLine.class);
    Line.Info targetDLInfo = new Line.Info(TargetDataLine.class);
    Line.Info clipInfo = new Line.Info(Clip.class);
    Line.Info portInfo = new Line.Info(Port.class);

    String support;

    for (Mixer.Info mixInfo: mixInfos) {
        Mixer mixer = AudioSystem.getMixer(mixInfo);

        support = ", supports ";
        if (mixer.isLineSupported(sourceDLInfo))
            support += "SourceDataLine ";
        if (mixer.isLineSupported(clipInfo))
            support += "Clip ";
        if (mixer.isLineSupported(targetDLInfo))
            support += "TargetDataLine ";
        if (mixer.isLineSupported(portInfo))
            support += "Port ";

        System.out.println("Mixer: " + mixInfo.getName() + support + ", " + mixInfo.getDescription());
    }
}

private class Communicator implements Runnable {
    @Override
    public void run() {
        int numBytesRead;
        byte[] targetData = new byte[mTargetLine.getBufferSize() / 5];

        while (isCommunicating) {
            numBytesRead = mTargetLine.read(targetData, 0, targetData.length);
            System.out.println(numBytesRead);

            if (numBytesRead == -1) break;

            if (isRetranslating)
                mSourceLine.write(targetData, 0, numBytesRead);
        }
    }
}
}}

谢谢!

【问题讨论】:

    标签: java audio


    【解决方案1】:

    好吧,我来到了以下工作代码。

    我用

    创建了新的“空”wav文件
    ais = new AudioInputStream(mTargetLine);
    AudioSystem.write(ais, fileType, wavFile);
    

    我得到了 44 字节的 wav 文件,其中存储了标头。

    当我需要录制一个 wav 文件时,当我在现场收听它时,我需要执行以下操作:创建一个空 wav 文件,写入该文件头(存储在 jar 中),在链接线程中附加字节。 (在我的例子中,Communicator 类)它将字节从 SourceLine 引导到 TargetLine(基本上从麦克风到扬声器)。这是我的问题中更新课程的代码。

    P.S.:标头仅适用于指定的 AudioFormat。如果您需要另一个,则可以单独“生成”它们。 P.S.S:对不起我的英语不好:)

    代码:

    public class RadioListener {
    private Runnable mRunnable, mFounderR;
    private Thread mThread = null, mFounderT = null;
    
    private SourceDataLine mSourceLine;
    private TargetDataLine mTargetLine;
    private DataLine.Info mTargetInfo;
    private DataLine.Info mSourceInfo;
    private static final AudioFormat mFormat = new AudioFormat(44100, 16, 2, true, false);
    
    private Mixer.Info[] mixers;
    private Mixer mFoundMixer = null;
    
    private Config mConfig;
    
    private boolean isCommunicating = false;
    private boolean isRetranslating = false;
    
    private static final String mHeader = "header.wav";
    //private File wavFile = null;
    AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
    AudioInputStream ais;
    private FileOutputStream fos;
    private boolean isRecording = false;
    
    public RadioListener (Config cfg) {
        mConfig = cfg;
    
        mixers = AudioSystem.getMixerInfo();
        mSourceInfo = new DataLine.Info(SourceDataLine.class, mFormat);
        mTargetInfo = new DataLine.Info(TargetDataLine.class, mFormat);
        try {mSourceLine = (SourceDataLine) AudioSystem.getLine(mSourceInfo);}
        catch (LineUnavailableException e) {System.out.println("RadioListener output error");}
    
        //wavFile = new File("E:/RecordAudio.wav");
    }
    
    public void Start() {
        if (Defines.strToIntDef(mConfig.getProperty("debugOut"), 0) == 1)
            showMixers();
    
        if (mFoundMixer == null) searchDevice();
        else startCommunication();
    }
    
    public void Stop() {
        if (mFoundMixer == null) return;
    
        try {
            mSourceLine.stop();
            mSourceLine.close();
    
            mTargetLine.stop();
            mTargetLine.close();
        } catch (Exception e) {}
        finally {
            isCommunicating = false;
        }
    }
    
    public void disposeListener() {
        if (isRecording) stopRecording();
    
        Stop();
    
        if (mFounderT != null)
            if (mFounderT.isAlive())
                mFounderT.interrupt();
    
        if (mThread != null)
            if (mThread.isAlive())
                mThread.interrupt();
    }
    
    public void Mute() {
        isRetranslating = false;
    }
    
    public void enableRecording (boolean f) {
        if (f) startRecording();
        else stopRecording();
    }
    
    public boolean isRecording() {
        return isRecording;
    }
    
    private void startRecording() {
        final DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        Date date = new Date(System.currentTimeMillis());
        String dt = formatter.format(date);
        final InputStream stream = this.getClass().getResourceAsStream("/" + mHeader);
        byte b[] = new byte[44];
        try {
            fos = new FileOutputStream(Defines.getCurrentFolder() + File.separator + dt + ".wav", true);
            try {
                stream.read(b, 0, 44);
                fos.write(b);
            } catch (IOException e) {
                try {fos.close();}
                catch (IOException e1) {;}
                isRecording = false;
                return;
            }
    
        } catch (FileNotFoundException e) {
            isRecording = false;
        }
        isRecording = true;
    }
    
    private void stopRecording() {
        isRecording = false;
    
        try {fos.close();}
        catch (IOException e) {;}
        isRecording = false;
    }
    
    private void searchDevice() {
        mFounderR = new RadioFinder();
        mFounderT = new Thread(mFounderR);
        mFounderT.start();
    }
    
    private void startThread() {
        startCommunication();
        mRunnable = new Communicator();
        mThread = new Thread(mRunnable);
        mThread.start();
    }
    
    private void startCommunication() {
        if (isCommunicating) {
            isRetranslating = true;
            return;
        }
        try {
            mTargetLine.open(mFormat);
            mTargetLine.start();
    
            mSourceLine.open(mFormat);
            mSourceLine.start();
    
            //Line line = mFoundMixer.getLine(mSourceInfo);
            //FloatControl control = (FloatControl)line.getControl(FloatControl.Type.MASTER_GAIN);
            //control.setValue(limit(control,10000));
            //control.setValue(-10);
    
            isCommunicating = true;
            isRetranslating = true;
    
            //ais = new AudioInputStream(mTargetLine); //ok
            //AudioSystem.write(ais, fileType, wavFile); //ok
        } catch (Exception e) {
            isCommunicating = false;
            isRetranslating = false;
        }
    }
    
    private class RadioFinder implements Runnable {
        @Override
        public void run() {
            Line.Info targetDLInfo = new Line.Info(TargetDataLine.class);
            for (Mixer.Info info : mixers) {
                Mixer tmp = AudioSystem.getMixer(info);
                //if (myMixer.isLineSupported(Port.Info.LINE_IN) || myMixer.isLineSupported(Port.Info.MICROPHONE)) {
                if (tmp.isLineSupported(targetDLInfo)) {
                    String s = tmp.getMixerInfo().getName();
                    if (s.toLowerCase().contains(mConfig.getProperty("radioName").toLowerCase())) {
                        mFoundMixer = tmp;
                        try {
                            mTargetInfo = new DataLine.Info(TargetDataLine.class, mFormat);
                            mTargetLine = (TargetDataLine) mFoundMixer.getLine(mTargetInfo);
    
                            System.out.println("Found radio device: " + mFoundMixer.getMixerInfo().getName());
    
                            startThread();
                        } catch (Exception e) {
                            System.out.println("RadioListener input error");
                            mFoundMixer = null;
                        }
                        break;
                    }
                }
            }
        }
    }
    
    private static void showMixers() {
        ArrayList<Mixer.Info> mixInfos = new ArrayList<Mixer.Info>(Arrays.asList(AudioSystem.getMixerInfo()));
    
        Line.Info sourceDLInfo = new Line.Info(SourceDataLine.class);
        Line.Info targetDLInfo = new Line.Info(TargetDataLine.class);
        Line.Info clipInfo = new Line.Info(Clip.class);
        Line.Info portInfo = new Line.Info(Port.class);
    
        String support;
    
        for (Mixer.Info mixInfo: mixInfos) {
            Mixer mixer = AudioSystem.getMixer(mixInfo);
    
            support = ", supports ";
            if (mixer.isLineSupported(sourceDLInfo))
                support += "SourceDataLine ";
            if (mixer.isLineSupported(clipInfo))
                support += "Clip ";
            if (mixer.isLineSupported(targetDLInfo))
                support += "TargetDataLine ";
            if (mixer.isLineSupported(portInfo))
                support += "Port ";
    
            System.out.println("Mixer: " + mixInfo.getName() + support + ", " + mixInfo.getDescription());
        }
    }
    
    private class Communicator implements Runnable {
        @Override
        public void run() {
            int numBytesRead;
            byte[] targetData = new byte[mTargetLine.getBufferSize() / 5];
    
            while (isCommunicating) {
                numBytesRead = mTargetLine.read(targetData, 0, targetData.length);
    
                if (numBytesRead == -1) break;
    
                if (isRetranslating)
                    mSourceLine.write(targetData, 0, numBytesRead);
    
                if (isRecording) {
                    try {fos.write(targetData);}
                    catch (IOException e) {stopRecording();}
                }
            }
        }
    }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-15
      • 2014-11-06
      • 2020-04-12
      • 2010-10-08
      • 1970-01-01
      相关资源
      最近更新 更多