【问题标题】:Allow Java application to continue running while recording audio允许 Java 应用程序在录制音频时继续运行
【发布时间】:2015-01-19 21:33:18
【问题描述】:

我正在尝试嵌入一些我找到的代码(原始 here),用于录制音频输入并将其保存到 Java swing 应用程序中。我的问题是我希望录音与应用程序正在执行的其他操作同时运行,但实际上,应用程序会暂停,直到录音完成。我怎样才能防止这种情况发生?

这是产生问题的我的代码的简化版本。直到录音完成后才会出现显示“正在录音”的行。

import javax.sound.sampled.*;

import java.io.*;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.File;

import javafx.embed.swing.JFXPanel;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Example extends JPanel {

    protected static final long serialVersionUID = 1L;

    // whether we've started recording
    private boolean startedRecording;

    // record duration, in milliseconds
    static final long RECORD_TIME = 5000;  // 5 seconds

    // format of audio file
    AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;

    // path of the wav file
    File wavFile;

    // the line from which audio data is captured
    TargetDataLine line;

    public Example( String output_fn ) {
        wavFile = new File(output_fn);
        startedRecording = false;
        setPreferredSize(new Dimension(100,100));
        createPanel();
    }

    public static JFXPanel createPanel() {
        return new JFXPanel();
    }

    /**
     * Defines an audio format
     */
    AudioFormat getAudioFormat() {
        float sampleRate = 16000;
        int sampleSizeInBits = 8;
        int channels = 2;
        boolean signed = true;
        boolean bigEndian = true;
        AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits,
                                             channels, signed, bigEndian);
        return format;
    }

    /**
     * Captures the sound and record into a WAV file
     */
    public void start() {
        try {
            AudioFormat format = getAudioFormat();
            DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);

            // checks if system supports the data line
            if (!AudioSystem.isLineSupported(info)) {
                System.out.println("Line not supported");
                System.exit(0);
            }
            line = (TargetDataLine) AudioSystem.getLine(info);
            line.open(format);
            line.start();   // start capturing

            System.out.println("In utils.Recorder: Start capturing...");

            AudioInputStream ais = new AudioInputStream(line);

            System.out.println("In utils.Recorder: Start recording...");

            // start recording
            AudioSystem.write(ais, fileType, wavFile);

        } catch (LineUnavailableException ex) {
            ex.printStackTrace();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        repaint();
    }

    /**
     * Closes the target data line to finish capturing and recording
     */
    public void finish() {
        line.stop();
        line.close();
        System.out.println("In utils.Recorder: Finished");
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2   = (Graphics2D)g;
        // start recording
        if ( !startedRecording ) {
            startedRecording = true;
            Thread stopper = new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(RECORD_TIME);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    Example.this.finish();
                }
            });
            stopper.start();
            this.start();
        }
        // display message
        g2.drawString("Now recording", 50, 50);
    }

    public static void main(String[] args) {
        final Example eg = new Example("TestRecordAudio.wav");
        JFrame f    = new JFrame();
        f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        f.add(eg, BorderLayout.CENTER);
        f.pack();
        f.setVisible(true);
        f.repaint();
    }
}

【问题讨论】:

    标签: java swing audio recording


    【解决方案1】:

    绘画方法是为了绘画!永远不要在paint方法中执行任何其他操作,这是不合适的,而且是一个非常非常糟糕的主意。

    创建一个JButton(或JToggleButton)并使用它来开始/停止录制。

    使用line.stop()line.close() 停止录制。

    Swing 是一个单线程环境,在事件调度线程的上下文中执行的任何长时间运行或阻塞的代码都会阻止它处理事件队列,使它看起来像你的程序已经挂起,因为它已经挂起。

    您可以使用SwingWorker,但由于您不会在录制时尝试更新用户界面,因此使用Thread 会更容易

    看看

    更多详情

    更新示例

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.File;
    import java.io.IOException;
    import javax.sound.sampled.AudioFileFormat;
    import javax.sound.sampled.AudioFormat;
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.DataLine;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.TargetDataLine;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JToggleButton;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class TestRecord {
    
        public static void main(String[] args) {
            new TestRecord();
        }
    
        public TestRecord() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public static class TestPane extends JPanel {
    
            private JToggleButton recordButton;
    
            protected static final AudioFileFormat.Type FILE_TYPE = AudioFileFormat.Type.WAVE;
            private TargetDataLine line;
    
            public TestPane() {
                setLayout(new GridBagLayout());
                recordButton = new JToggleButton("Record");
                recordButton.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (recordButton.isSelected()) {
                            startRecording();
                            recordButton.setText("Stop");
                        } else {
                            stopRecording();
                            recordButton.setText("Record");
                        }
                    }
                });
                add(recordButton);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            protected void stopRecording() {
    
                if (line != null) {
    
                    line.stop();
                    line.close();
                    line = null;
    
                }
    
            }
    
            protected void startRecording() {
                if (line == null) {
                    Thread t = new Thread(new Runnable() {
    
                        @Override
                        public void run() {
                            try {
                                AudioFormat format = getAudioFormat();
                                DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
    
                                // checks if system supports the data line
                                if (!AudioSystem.isLineSupported(info)) {
                                    System.out.println("Line not supported");
                                    System.exit(0);
                                }
                                line = (TargetDataLine) AudioSystem.getLine(info);
                                line.open(format);
                                line.start();   // start capturing
    
                                System.out.println("In utils.Recorder: Start capturing...");
    
                                AudioInputStream ais = new AudioInputStream(line);
    
                                System.out.println("In utils.Recorder: Start recording...");
    
                                // start recording
                                System.out.println("Is recoding");
                                AudioSystem.write(ais, FILE_TYPE, new File("Test.wav"));
    
                            } catch (LineUnavailableException ex) {
                                ex.printStackTrace();
                            } catch (IOException ioe) {
                                ioe.printStackTrace();
                            }
    
                            System.out.println("Recording is done");
                        }
                    });
                    t.start();
                }
            }
    
            protected AudioFormat getAudioFormat() {
                float sampleRate = 16000;
                int sampleSizeInBits = 8;
                int channels = 2;
                boolean signed = true;
                boolean bigEndian = true;
                AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits,
                                channels, signed, bigEndian);
                return format;
            }
        }
    
    }
    

    (nb:我无法测试它,因为我没有可用于支持录制的线路......显然)

    【讨论】:

    • 您能否详细说明如何使用线程解决我的问题?
    【解决方案2】:

    您在AWT Event Dispatch Thread 上调用start,从而阻止了其他任何事情的发生。您需要在不同的线程上调用您的音频调用代码。

    你不应该在 Swing 线程上运行长时间运行的任务,除非你想面对死机的灰屏

    【讨论】:

    • 谢谢。您能否提供有关如何执行您推荐的操作的代码或参考?我对与线程相关的问题有所了解,但即使在尝试阅读了一堆有关它的内容(包括您链接的有关事件调度​​线程的参考文献)之后,我对线程管理的了解也很少。
    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多