簡體   English   中英

等待聲音結束后再繼續

[英]Wait for sound to finish before continuing

我正在創建一個循環遍歷字符串的循環,並根據顯示的字符播放不同的聲音。 不幸的是,它不會等待聲音結束才繼續播放,這會導致媒體播放器出錯。 我的循環看起來像這樣:

for (char ch : morsechars) {
            if (Character.toString(ch).equals(".") ) {
                Log.d("play: ", "dot");
                try {
                    startPlayback();
                } catch (Exception e){
                    e.printStackTrace();
                }
            } else if (Character.toString(ch).equals("-")){
                Log.d("play: ", "dash");
                try {
                    startPlayback();
                } catch (Exception e){
                    e.printStackTrace();
                }
            } 
        }

而我的播放器如下所示:

public void startPlayback() throws Exception{
        play = MediaPlayer.create(this, dotFILE);
        play.start();
        isplaying = true;
        while (isplaying == true){

        }


        play.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            public void onCompletion(MediaPlayer play) {
                isplaying = false;
                play.stop();
                play.reset();
                play.release();
            }
        });
    }

我不確定如何在繼續到循環中的下一個字符之前等待完成偵聽器。

1) MediaPlayer不是適合此工作的工具。 看一下SoundPool 它適用於反復播放的短聲音。

2)對於您的情況,您想要的並不是真正的循環。 聲音將異步播放,因此您遇到了這樣的情況:要播放的呼叫相互疊加。 這將導致MediaPlayer的本機代碼耗盡可用資源。

您想要的是一系列回調。 MediaPlayer具有您已經在使用的完成回調,但是,盡管這看起來確實是需要的,但它不足以滿足您的用例。 MediaPlayer本機代碼將無法足夠快地釋放其資源以供隨后的每個播放調用使用,並且將發生相同的資源耗盡。 對於MediaPlayer工作方式,這只是一個不幸的現實。

SoundPool沒有方便的完成回調,但是在這種情況下,您可能只有兩個聲音樣本,並且知道它們有多長時間。 一個簡單的計時器延遲可能就足夠了。 您可以使用Handler.postDelayed實現此效果。 在每個回調事件中,只需播放下一個聲音,前進用於跟蹤當前聲音的任何變量,然后再次發布相同的回調以播放所有剩余聲音。 這是一種異步循環。

UPDATE

為了幫助您了解發生了什么,這里有一些關於Handler Android文檔:

處理程序使您可以發送和處理與線程的MessageQueue關聯的Message和Runnable對象。 每個Handler實例都與一個線程和該線程的消息隊列關聯。 創建新的Handler時,它將綁定到正在創建它的線程的線程/消息隊列中-從那時起,它將把消息和可運行對象傳遞到該消息隊列,並在它們從消息中出來時執行它們隊列。

因此,如果我對您的代碼結構的猜測接近正確,則可以創建一個Handler對象作為Activity類的成員。 這會將其綁定到GUI線程,這應該沒問題,因為在那里您不會做很多工作。 您還需要一個Runnable來充當要發布的任務。 也使其成為班上的一員。 並且您將需要包含字符的String成為成員。 並且您將需要一個int來跟蹤當前使用的字符。

private Handler playMorseHandler = new Handler();
private String morseChars = ".--...---"; // I don't know where you set this
private int charIndex = 0;
private Runnable playMorseTask = new Runnable() {
    if (morseChars == null ||
        charIndex < 0 ||
        charIndex >= morseChars.length()) {
        Log.w("whateverTag", "Basic assumptions failed");
        return;
    }
    char ch = morseChars.charAt(charIndex);
    long lengthOfClip = 0L;
    boolean postAgain = true;
    if (ch == '.') {
        Log.d("play: ", "dot");
        lengthOfClip = 300L; // I don't know how long your clips are
        try {
            startPlayback();
        } catch (Exception e){
            e.printStackTrace();
        }
    } else if (ch == '-') {
        Log.d("play: ", "dash");
        lengthOfClip = 500L; // I don't know how long your clips are
        try {
            startPlayback();
        } catch (Exception e){
            e.printStackTrace();
        }
    } else {
        Log.d("whateverTag", "unexpected input");
        postAgain = false;
    }
    ++charIndex;
    if (postAgain && charIndex < morseChars.length()) {
        playMorseHandler.postDelayed(this, lengthOfClip);
    }
};

無論您想在哪里開始播放聲音,只需調用:

charIndex = 0;
playMorseHandler.post(playMorseTask);

剩下的唯一事情就是讓您的startPlayback()方法做正確的事情,那就是使用SoundPool而不是MediaPlayer 這是因為,正如我前面提到的那樣, MediaPlayer不可避免地會導致系統耗盡所有資源,因此很快地播放這些短聲音。

暫無
暫無

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

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