如何在Java Sound API中重新启动播放音频?

时间:2014-04-12 10:24:43

标签: java swing audio enums

我编写了这两个类来测试我如何使用Java Sound API:

enum SoundEffect:枚举封装了我使用过的所有声音。

Class SoundEffectDemo:在Swing应用程序中测试SoundEffect枚举

当我点击SoundEffectDemo(CALLING,RING,BUSY)的任何按钮时,声音开始播放。当我点击“停止声音”按钮时,声音停止。 但是当我第二次点击SoundEffectDemo(CALLING,RING,BUSY)的任何按钮时,没有任何声音。

import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;

public enum SoundEffect  {

    BUSY("resources/phone-busy.wav"),   
    CALLING("resources/phone-calling.wav"),         
    DISCONNECT("resources/phone-disconnect.wav"),
    RING("resources/telephone-ring.wav");  

    // Each sound effect has its own clip, loaded with its own sound file.
    private Clip clip;
    private URL url;
    private AudioInputStream audioInputStream;

    // Constructor to construct each element of the enum with its own sound file.
    SoundEffect(String soundFileName) {
        try {
            // Use URL (instead of File) to read from disk and JAR.
            this.url = this.getClass().getClassLoader().getResource(soundFileName);
            // Set up an audio input stream piped from the sound file.
            this.audioInputStream = AudioSystem.getAudioInputStream(url);
            // Get a clip resource.
            clip = AudioSystem.getClip();
            // Open audio clip and load samples from the audio input stream.
            clip.open(audioInputStream);
            clip.addLineListener( new LineListener() {
                public void update(LineEvent evt) {
                    if (evt.getType() == LineEvent.Type.STOP) {
                        evt.getLine().close();
                    }
                }
            });
        } catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    // Play or Re-play the sound effect from the beginning, by rewinding.
    public void play() {

        clip.loop(Clip.LOOP_CONTINUOUSLY); 

    }

    public void stop(){

        clip.stop();   // Stop the player if it is still running
    }

    // Optional static method to pre-load all the sound files.
    static void init() {
        values(); // calls the constructor for all the elements
    }

    public boolean isActive(){

        return clip.isActive();
    }

    public boolean isOpen() {

        return clip.isOpen();
    }

    public void setFramePosition() {
        clip.setFramePosition(0);

    }

}




import java.awt.*;
import java.awt.event.*;

import javax.sound.sampled.LineEvent;
import javax.swing.*;

// Testing the SoundEffect enum in a Swing application
@SuppressWarnings("serial")
public class SoundEffectDemo extends JFrame {


    // Constructor
    public SoundEffectDemo() {
        // Pre-load all the sound files


        // Set up UI components
        Container cp = this.getContentPane();
        cp.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));

        JButton btnSound1 = new JButton("CALLING");
        btnSound1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                SoundEffect.CALLING.play(); 
            }
        });
        cp.add(btnSound1);

        JButton btnSound2 = new JButton("RING");
        btnSound2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                SoundEffect.RING.play();
            }
        });
        cp.add(btnSound2);

        JButton btnSound3 = new JButton("BUSY");
        btnSound3.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                SoundEffect.BUSY.play();
            }
        });
        cp.add(btnSound3);

        JButton btnSound4 = new JButton("Stop Sound ");
        btnSound4.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for(SoundEffect value : SoundEffect.values()){
                    if(value.isActive()){
                        value.stop();
                    }
                }

            }
        });
        cp.add(btnSound4);


        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("Test SoundEffct");
        this.pack();
        this.setVisible(true);
    }

    public static void main(String[] args) {
        new SoundEffectDemo();
    }
}

2 个答案:

答案 0 :(得分:1)

clip.addLineListener( new LineListener() {
    public void update(LineEvent evt) {
        if (evt.getType() == LineEvent.Type.STOP) {
            evt.getLine().close();
        }
    }
});

这可能不是您想要做的事情,在收到停止事件时关闭该行。关闭剪辑后,您需要重新打开它才能再次播放。

鉴于你正在做的事情,你可能根本就不需要关闭这条线。呼叫关闭表示您已完成此操作。

请参阅Line#closeAutoCloseable#close

针对您的停止活动的更合适的临时行动将是drainflush。然后,如果要“重置”它,可能将帧位置设置为0.

因此请删除对close的调用并执行类似

的操作
public void stop() {
    clip.stop();
    clip.flush();
    clip.setFramePosition(0);
}

作为旁注,我注意到你没有在Event Dispatch Thread上启动你的Swing应用程序。你应该总是initialize your GUI with a call to invokeLater,例如:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new SoundEffectDemo();
        }
    });
}

使用Swing进行线程安全很重要,因为不这样做会导致难以诊断的细微错误。

答案 1 :(得分:0)

通过重新播放java中的音频,你的意思并不是很清楚。

您的代码不相关,因为从它的外观看,您已将所有内容放在一个代码块中,这使得难以阅读。你错过了几个括号。但回到你的问题。我已经组建了一个简单的课程,可以满足您的要求。

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

public class PlaybackWAV {
    private final int BUFFER_SIZE = 128000;
    private AudioInputStream audioStream;
    private AudioFormat audioFormat;
    private SourceDataLine sourceLine;
    private boolean running = false;

    /**
     * @param filename
     *            the name of the file that is going to be played
     */
    public synchronized void playSound(final String filename) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    InputStream audioSrc = this.getClass().getResourceAsStream(filename);
                    // add buffer for mark/reset support
                    InputStream bufferedIn = new BufferedInputStream(audioSrc);
                    audioStream = AudioSystem.getAudioInputStream(bufferedIn);

                    audioFormat = audioStream.getFormat();

                    DataLine.Info info = new DataLine.Info(
                            SourceDataLine.class, audioFormat);
                    sourceLine = (SourceDataLine) AudioSystem.getLine(info);
                    sourceLine.open(audioFormat);

                    sourceLine.start();
                    running = true;

                    while (running) {
                        int nBytesRead = 0;
                        byte[] abData = new byte[BUFFER_SIZE];
                        while (nBytesRead != -1) {
                            try {
                                nBytesRead = audioStream.read(abData, 0,
                                        abData.length);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            if (nBytesRead >= 0) {
                                sourceLine.write(abData, 0, nBytesRead);
                            }
                        }
                        if (running)
                            audioStream.reset();
                    }
                    sourceLine.drain();
                    sourceLine.close();
                } catch (Exception e) {
                    System.err
                            .printf("Exception occured while trying to playback file '%s'. (%s)%n",
                                    filename, e.getLocalizedMessage());
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void stopSound() {
        this.running = false;
        if (sourceLine != null) {
            sourceLine.stop();
            sourceLine.drain();
            sourceLine.close();
        }
    }
}

这个类有两种方法,playSound启动一个新的线程并在你的类文件夹中播放一个特定的声音,而stopSound显然会停止当前播放的任何声音。这是一个简单的片段,它将创建三个按钮来播放您示例中的三个声音。

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class Snippet extends JFrame {

    public Snippet(){
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        JPanel panel = new JPanel(new FlowLayout());
        this.getContentPane().add(panel);

        final PlaybackWAV player = new PlaybackWAV();
        JButton play1 = new JButton("CALLING");
        panel.add(play1);
        JButton play2 = new JButton("RING");
        panel.add(play2);
        JButton play3 = new JButton("BUSY");
        panel.add(play3);
        JButton play4 = new JButton("STOP");
        panel.add(play4);
        this.pack();

        play1.setAction(new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                player.stopSound();
                player.playSound("resources/phone-calling.wav");
            }
        });
        play2.setAction(new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                player.stopSound();
                player.playSound("resources/telephone-ring.wav");
            }
        });
        play3.setAction(new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                player.stopSound();
                player.playSound("resources/phone-busy.wav");
            }
        });
        play4.setAction(new AbstractAction(){

            @Override
            public void actionPerformed(ActionEvent arg0) {
                player.stopSound();
            }
        });
    }

    public static void main(String[] args){
        Snippet snippet = new Snippet();
        snippet.setVisible(true);
    }

}

快乐的编码!

修改

道歉,我忘了调用'mark'方法,因此重置方法无法正常工作。这是新代码:

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

public class PlaybackWAV {
    private final int BUFFER_SIZE = 128000;
    private AudioInputStream audioStream;
    private AudioFormat audioFormat;
    private SourceDataLine sourceLine;
    private boolean running = false;

    /**
     * @param filename
     *            the name of the file that is going to be played
     */
    public synchronized void playSound(final String filename) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    InputStream audioSrc = this.getClass().getResourceAsStream(filename);
                    // add buffer for mark/reset support
                    InputStream bufferedIn = new BufferedInputStream(audioSrc);
                    audioStream = AudioSystem.getAudioInputStream(bufferedIn);

                    audioFormat = audioStream.getFormat();

                    DataLine.Info info = new DataLine.Info(
                            SourceDataLine.class, audioFormat);
                    sourceLine = (SourceDataLine) AudioSystem.getLine(info);
                    sourceLine.open(audioFormat);

                    sourceLine.start();
                    running = true;

                    while (running) {
                        audioStream.mark(BUFFER_SIZE);
                        int nBytesRead = 0;
                        byte[] abData = new byte[BUFFER_SIZE];
                        while (nBytesRead != -1) {
                            try {
                                nBytesRead = audioStream.read(abData, 0,
                                        abData.length);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            if (nBytesRead >= 0) {
                                sourceLine.write(abData, 0, nBytesRead);
                            }
                        }
                        if (running)
                            audioStream.reset();
                    }
                    sourceLine.drain();
                    sourceLine.close();
                } catch (Exception e) {
                    System.err
                            .printf("Exception occured while trying to playback file '%s'. (%s)%n",
                                    filename, e.getLocalizedMessage());
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void stopSound() {
        this.running = false;
        if (sourceLine != null) {
            sourceLine.stop();
            sourceLine.drain();
            sourceLine.close();
        }
    }
}