【问题标题】:Java clip not workingJava 剪辑不起作用
【发布时间】:2014-06-10 01:43:36
【问题描述】:

有人可以帮我理解为什么下面的代码不起作用吗?

我通过调用方法start() 开始剪辑。此方法为要运行的剪辑创建一个新线程。但是,不,它似乎没有播放任何东西。

代码编译没有任何错误...

public class Audio
{
    private Clip clip;

    private Thread thread; 

    public Audio (String audioFile)
    {
        AudioInputStream audioStream = null;

        URL audioURL = this.getClass().getClassLoader().getResource(audioFile);

        // Obtain audio input stream from the audio file and load the information
        // into main memory using the URL path retrieved from above.
        try { audioStream = AudioSystem.getAudioInputStream(audioURL); }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(1);
        }

        try
        {
            // Retrieve the object of class Clip from the Data Line.
            this.clip = AudioSystem.getClip();

            // Load the audio input stream into memory for future play-back.
            this.clip.open(audioStream);
        }
        catch (LineUnavailableException e)
        {
            e.printStackTrace();
            System.exit(1);
        }
        catch (IOException e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public void start()
    {
        Runnable r = new Runnable() {
            public void run()
            {
                loop();
            }
        };
        thread = new Thread(r);
        thread.start();
    }

    public void loop ()
    {       
        // Rewind the media to the beginning of the clip.
        this.clip.setFramePosition(0);

        // Continuously play the clip.
        this.clip.loop(Clip.LOOP_CONTINUOUSLY);

        try
        {
            Thread.sleep(5000);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

更新

我发现了问题!问题是因为音频文件。我使用了不同的音频文件,我可以通过上面的代码听到声音。

编译的代码没有任何错误或警告真的很烦人。我通过获取音频格式检测到问题,然后将其传递给 DataLine.Info 类的对象。然后,从数据线中检索剪辑。

所以,基本上不是通过以下方式获取剪辑:

this.clip = AudioSystem.getClip();

我会通过以下方式获取剪辑:

AudioFormat format = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
this.clip = (Clip) AudioSystem.getLine(info);

当我用这个编译时,Java 抛出以下错误:

无线路匹配接口 Clip 支持格式 PCM_SIGNED 48000.0 Hz, 24 bit

所以,我替换了音频文件,它起作用了!

【问题讨论】:

  • API 显示继承的启动方法,你试过了吗(如this.clip.start)?
  • 如果你在一个线程中全部尝试会发生什么?
  • 回答您的问题: 1. 这不是Applet。我在另一个类中创建了这个类的一个对象。 2. 我试过clip.start(),但是没用。 3.在一个线程上启动剪辑也不起作用。我阅读了几篇关于此的文章,它们都建议在单独的线程上运行 clip.loop()。
  • 我发现了问题。阅读我上面的新 cmets。

标签: java audio javasound clip


【解决方案1】:

clip.loop 是一个非阻塞调用。也就是说,一旦你调用它(它会做它做的事情),它就会返回,这意味着你的线程将退出,除非有另一个非守护线程在运行,否则 JVM 将退出。

我原以为你可以使用 Clip#drain 使其阻塞,直到剪辑完成,但从技术上讲,剪辑不会完成......在正常意义上。

相反,我设置了自己的循环...

public void start() {
    Runnable r = new Runnable() {
    public void run() {
        while (true) {
            clip.setFramePosition(0);
            clip.start();
            clip.drain();
        }
    }
    };
    thread = new Thread(r);
    thread.start();
}

现在,这可能是个问题,因为Thread 是一个非守护线程并且永远不会结束...而不是while (true) {,您应该设置某种volitle 标志,将其设置为false并帮助终止循环...

例如...

import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;

public class Audio {

    private Clip clip;

    private Thread thread;
    private volatile boolean keepPlaying = true;

    public static void main(String[] args) {
        Audio audio = new Audio("Kalimba.wav");
        audio.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException ex) {
        }
        audio.stop();
    }

    public Audio(String audioFile) {
        AudioInputStream audioStream = null;

        URL audioURL = this.getClass().getClassLoader().getResource(audioFile);

        // Obtain audio input stream from the audio file and load the information
        // into main memory using the URL path retrieved from above.
        try {
            audioStream = AudioSystem.getAudioInputStream(audioURL);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        try {
            // Retrieve the object of class Clip from the Data Line.
            this.clip = AudioSystem.getClip();

            // Load the audio input stream into memory for future play-back.
            this.clip.open(audioStream);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public void stop() {
        if (thread != null) {

            keepPlaying = false;
            clip.stop();
            thread.interrupt();

        }
    }

    public void start() {
        Runnable r = new Runnable() {
            public void run() {
                while (keepPlaying) {
                    clip.setFramePosition(0);
                    clip.start();
                    clip.drain();
                }
            }
        };
        thread = new Thread(r);
        thread.start();
    }
}

更新

上面的例子有一些问题(恕我直言),可以用一个简单的对象监视器来解决。

因此,我们可以使用Clip#loop 功能代替volatile 标志和while 循环,并简单地使用Object#wait 和Object#notify,例如

import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;

public class Audio {

    private Clip clip;

    private Thread thread;
    private final Object loopLock = new Object();

    public static void main(String[] args) {
        Audio audio = new Audio("Music.wav");
        audio.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException ex) {
        }
        audio.stop();
    }

    public Audio(String audioFile) {
        AudioInputStream audioStream = null;

        URL audioURL = this.getClass().getClassLoader().getResource(audioFile);

        // Obtain audio input stream from the audio file and load the information
        // into main memory using the URL path retrieved from above.
        try {
            audioStream = AudioSystem.getAudioInputStream(audioURL);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        try {
            // Retrieve the object of class Clip from the Data Line.
            this.clip = AudioSystem.getClip();

            // Load the audio input stream into memory for future play-back.
            this.clip.open(audioStream);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public void stop() {
        synchronized (loopLock) {
            loopLock.notifyAll();
        }
    }

    public void start() {
        Runnable r = new Runnable() {
            public void run() {
                clip.setFramePosition(0);
                clip.loop(Clip.LOOP_CONTINUOUSLY);
                synchronized (loopLock) {
                    try {
                        loopLock.wait();
                    } catch (InterruptedException ex) {
                    }
                }
                clip.stop();
            }
        };
        thread = new Thread(r);
        thread.start();
    }
}

【讨论】:

  • 疯狂程序员,感谢您的回复。我知道 clip.loop() 启动一个守护线程。这就是我输入这个命令的原因:Thread.sleep(5000);在调用 clip.loop() 之后立即使非守护线程保持活动状态。
  • 我尝试了您关于创建 while 循环和使用 clip.drain() 的建议。然而,这也没有奏效。我开始怀疑这是一个环境问题。我在 MacBook Pro 上使用 Eclipse IDE。这有什么区别吗?你能想到我可以尝试的其他方法吗?
  • 如果声音正在播放,我看不出上述代码失败的任何原因(尽管它不是绝对“最佳”的解决方案)
  • 我添加了一个“更好”的解决方案,它使用对象监视器锁而不是while-loop。我用它播放了一个 50 秒的剪辑,并使用了 2 分钟的延迟(而不是 5 秒 ;)),能够听到它播放 2 次和一点时间
  • 我终于找到问题了!!!这是因为音频文件。代码是正确的。但是,我使用了不受支持的音频文件。编译的代码没有任何错误或警告真的很烦人。使用不同的 .wav 文件,我听到了声音。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-02
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-05
相关资源
最近更新 更多