2

GUIでトリガーされたアクションの成功とエラー時に短いビープ音(WAVファイル)を再生したい。

私はjavax.sound.sampled.Clipに出くわしましたが、これは機能しているようです。これが私が使用する基本的なコードです:

clip.stop();
clip.setFramePosition(0);
clip.start();

これは、ボタンのクリックがデータベースアクションをトリガーした後に実行されます。成功とエラーの場合、2つの異なるプリロードされたクリップが再生されます。

しかし、本番マシン(Kubuntu 10.4を実行している古いPC)では、しばらくすると(約400回以上の実行または2〜4時間)、クリップの再生が拒否されます。停止方法は終了するのに約3秒かかり、次の開始アクションは音を鳴らしません。その後のコードの呼び出しはすべて、例外やその他のフィードバックをスローせずに失敗します。これを修正する唯一のことは、アプリケーション全体を再起動することです。

私の質問は次のとおりです。これに対する回避策はありますか?他の誰かが同じ問題を抱えていますか?または、少なくとも2つの異なるサウンドを再生するために使用できる別のフレームワークがあります(Toolkit.beep()は1つのサウンドしか再生できません)。

4

2 に答える 2

1

だから私はそれをどのように修正しました:

私は基本的に Charles Goodwin からのヒントに従いましたが、AePlayWave クラスを変更して runnable を実装し、それをスレッド プールで使用しました (常に新しいスレッドを開始することによるオーバーヘッドを回避するため)。また、パックされた JAR ファイル内のリソースを使用するために、ファイルではなく URL を使用します。AePlayWave オブジェクトは、セットアップが完了する (ファイルが選択される) か、設定が変更されると作成されます。アプリケーションで再生するすべてのサウンドのインスタンスがあります。次に、イベントのリスナー メソッドがプールをトリガーして、そのイベント サウンドの特定の AePlayWave インスタンスを実行します。あとは基本的に同じです。

不便な点は次の 2 つだけです。

1.) 弱いマシンでは、WAV のエンディングが常に再生されるとは限りません。サウンドが非常に短い場合 (100 ミリ秒のビープ音など)、サウンドがまったく再生されない可能性があります。そのため、再生したい各サウンドの最後に 500 ミリ秒の無音を追加しました。これは回避策ですが、役に立ちます。今のところ、これが最善かつ最も安定したアプローチのようです。

2.) 2 つ以上のサウンドが再生されると (反復が非常に速いため)、サウンドが重なり合い、曲調と音量が変化するように聞こえます。これは私の場合は問題ありませんが、他の用途では面倒かもしれません。

すでに本稼働システムで実行されています。エラーが報告された場合は、この投稿を編集して最新の状態に保ちます。

ここに(基本的に縮小された)ソースコードがあります:

import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;    
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.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class AudibleListener implements SomeListener {

private Runnable successRunner;
private Runnable failRunner;

ExecutorService pool = Executors.newCachedThreadPool();

/**
 * Call this after initialization and after every change in your config at runtime.
 */
public void reloadSettings() {
    // put your configuration here
    this.successRunner = new WavePlayer(this.getClass().getResource("success.wav"));
    this.failRunner = new WavePlayer(this.getClass().getResource("fail.wav"));
}

/**
 * Call this to savely shutdown the thread pool.
 */
public void shutdown() {
    this.pool.shutdown();
}

/**
 * Listener method called on success. 
 */
public void eventSuccess() {
    this.pool.execute(this.successRunner);
}

/**
 * Listener method called on fail. 
 */
public void eventFailed() {
    this.pool.execute(this.failRunner);
}

private class WavePlayer implements Runnable {

    private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb 

    private URL soundFile;

    public WavePlayer(URL soundFile) {
        this.soundFile = soundFile;
    }

    @Override
    public void run() {

        try {
            // check if the URL is still accessible!
            this.soundFile.openConnection().connect();
            this.soundFile.openStream().close();
        } catch (Exception e) {
            return;
        }

        AudioInputStream audioInputStream = null;
        try {
            audioInputStream = AudioSystem
                    .getAudioInputStream(this.soundFile);
        } catch (UnsupportedAudioFileException e) {
            return;
        } catch (IOException e) {
            return;
        }

        AudioFormat format = audioInputStream.getFormat();
        SourceDataLine auline = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        try {
            auline = (SourceDataLine) AudioSystem.getLine(info);
            auline.open(format);
        } catch (LineUnavailableException e) {
            return;
        } catch (Exception e) {
            return;
        }

        auline.start();
        int nBytesRead = 0;
        byte[] abData = new byte[this.EXTERNAL_BUFFER_SIZE];

        try {
            while (nBytesRead != -1) {
                nBytesRead = audioInputStream
                        .read(abData, 0, abData.length);
                if (nBytesRead >= 0) {
                    auline.write(abData, 0, nBytesRead);
                }
            }
        } catch (IOException e) {
            return;
        } finally {
            auline.drain();
            auline.close();
        }
    }
}
}

歓声とこれまでのすべての助けに感謝します!

P.

アップデート:

これは現在、エラーなしで過去 72 時間実行されています! できたようです!

于 2011-07-12T15:25:09.253 に答える