簡體   English   中英

允許Java應用程序在錄制音頻時繼續運行

[英]Allow Java application to continue running while recording audio

我正在嘗試嵌入一些我發現的代碼( 在此原始),用於記錄音頻輸入並將其保存到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();
    }
}

繪畫方法是繪畫! 永遠不要在paint方法內執行任何其他操作,這是不適當的,而且是一個非常非常糟糕的主意。

創建一個JButton (或JToggleButton ),並使用它來開始/停止錄制。

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

Swing是一個單線程環境,在事件調度線程的上下文中執行的任何長時間運行或阻塞的代碼都將阻止它處理事件隊列,從而使其看起來像您的程序已掛起。

您可以使用SwingWorker ,但是由於您在錄制時不嘗試更新UI,因此使用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:我無法對其進行測試,因為我顯然沒有可用的線路來支持錄音...)

您正在AWT事件調度線程上調用start ,從而阻止了其他任何事情的發生。 您需要在其他線程上調用音頻呼叫代碼。

除非要面對死亡的灰屏,否則切勿在Swing線程上運行長時間運行的任務

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM