web-dev-qa-db-ja.com

Android.speech.tts.TextToSpeechを一時停止する方法

Android TTS-Android.speech.tts.TextToSpeech

私が使う: TextToSpeech.speak話すことと.stop 止まる。テキストも一時停止する方法はありますか?

24
Jas

TTS SDKには、私が知っている一時停止機能はありません。ただし、 synthesizeToFile() を使用して、TTS出力を含むオーディオファイルを作成できます。次に、 MediaPlayer オブジェクトを使用して、ファイルの再生、一時停止、および停止を行います。テキスト文字列の長さに応じて、synthesizeToFile()関数はファイル全体を完了してから再生する必要があるため、オーディオが生成されるまでに少し時間がかかる場合がありますが、この遅延は許容できるはずです。ほとんどのアプリケーション。

24
Aaron C

私は文字列の分割を使用し、以下のようにplaysilence()を使用しました:

public void speakSpeech(String speech) {

    HashMap<String, String> myHash = new HashMap<String, String>();

    myHash.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "done");

    String[] splitspeech = speech.split("\\.");

    for (int i = 0; i < splitspeech.length; i++) {

        if (i == 0) { // Use for the first splited text to flush on audio stream

            textToSpeech.speak(splitspeech[i].toString().trim(),TextToSpeech.QUEUE_FLUSH, myHash);

        } else { // add the new test on previous then play the TTS

            textToSpeech.speak(splitspeech[i].toString().trim(), TextToSpeech.QUEUE_ADD,myHash);
        }

        textToSpeech.playSilence(750, TextToSpeech.QUEUE_ADD, null);
    }
}
15
rushi

最大3つのピリオド( "。")を追加し、その後に単一のスペース ""を追加することで、文の間、または任意の場所にTTSを一時停止させることができます。以下の例では、最初とメッセージ本文の前に長い休止があります。それがあなたの目的であるかどうかはわかりません。

    private final BroadcastReceiver SMScatcher = new BroadcastReceiver() {

    @Override
    public void onReceive(final Context context, final Intent intent) {
        if (intent.getAction().equals(
                "Android.provider.Telephony.SMS_RECEIVED")) {
            // if(message starts with SMStretcher recognize BYTE)
            StringBuilder sb = new StringBuilder();

            /*
             * The SMS-Messages are 'hiding' within the extras of the
             * Intent.
             */
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                /* Get all messages contained in the Intent */
                Object[] pdusObj = (Object[]) bundle.get("pdus");
                SmsMessage[] messages = new SmsMessage[pdusObj.length];
                for (int i = 0; i < pdusObj.length; i++) {
                    messages[i] = SmsMessage
                            .createFromPdu((byte[]) pdusObj[i]);
                }
                /* Feed the StringBuilder with all Messages found. */
                for (SmsMessage currentMessage : messages) {
                    // periods are to pause
                    sb.append("... Message From: ");
                    /* Sender-Number */
                    sb.append(currentMessage.getDisplayOriginatingAddress());
                    sb.append(".. ");
                    /* Actual Message-Content */
                    sb.append(currentMessage.getDisplayMessageBody());
                }
                // Toast.makeText(application, sb.toString(),
                // Toast.LENGTH_LONG).show();
                if (mTtsReady) {
                    try {
                        mTts.speak(sb.toString(), TextToSpeech.QUEUE_ADD,
                                null);
                    } catch (Exception e) {
                        Toast.makeText(application, "TTS Not ready",
                                Toast.LENGTH_LONG).show();
                        e.printStackTrace();
                    }
                }
            }

        }
    }
};

最後のピリオドの後にスペースを省略すると、期待どおりに機能しません(または機能しない可能性があります)。

7
jroal

一時停止オプションがない場合は、TTSエンジンの発言を遅らせたい時間の間、無音を追加できます。もちろん、これは事前に定義された「一時停止」である必要があり、たとえば一時停止ボタンの機能を含めるのに役立ちません。

API <21の場合: public int playSilence(long durationInMs、int queueMode、HashMap params)

> 21の場合: public int playSilentUtterance(long durationInMs、int queueMode、String utteranceId)

TextToSpeech.QUEUE_FLUSH ではなく TextToSpeech.QUEUE_ADD を使用することを忘れないでください。そうしないと、以前に開始された音声がクリアされます。

4
brandall

私はまだこれを試していませんが、同じことをする必要があります。私の考えは、最初にあなたのスピーチテキストを単語の配列に分割することです。

次に、現在のWordのカウンターを維持しながら、現在のWordの終了後に次のWordを再生する再帰関数を作成します。

3
SiteKickr

messagesを部分に分割し、utteranceリスナーを使用して最後のonutteranceprogressをリッスンします

 tts.playSilence(1250, TextToSpeech.QUEUE_ADD, null);
2
Dev

私は別のアプローチを使用しました。

  1. テキストを文に分割する
  2. すべての文を1つずつ話して、話された文を追跡する
  3. 一時停止するとすぐにテキストが停止します
  4. 履歴書は最後に話された文の始めから始まります

Kotlinコード:

class VoiceService {

    private lateinit var textToSpeech: TextToSpeech    

    var sentenceCounter: Int = 0
    var myList: List<String> = ArrayList()

    fun resume() {
        sentenceCounter -= 1
        speakText()
    }

    fun pause() {
        textToSpeech.stop()
    }

    fun stop() {
        sentenceCounter = 0
        textToSpeech.stop()
    }

    fun speakText() {

        var myText = "This is some text to speak. This is more text to speak."

        myList =myText.split(".")

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
        textToSpeech.speak(myList[sentenceCounter], TextToSpeech.QUEUE_FLUSH, null, utteranceId)
            sentenceCounter++
        } else {
            var map: HashMap<String, String> = LinkedHashMap<String, String>()
            map[TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID] = utteranceId
            textToSpeech.speak(myList[sentenceCounter], TextToSpeech.QUEUE_FLUSH, map)
            sentenceCounter++
        }
    }

    override fun onDone(p0: String?) {
        if (sentenceCounter < myList.size) {
            speakText()
        } else {
            speakNextText()
        }
    }
}
2
rm -rf

次のように、単語の後にピリオドを入れて、次の単語を大文字で始めると、新しい文のように見えます。

帰宅後、夕食を食べました。

「家。私たち」はそこで一時停止します。

  • これは文法的に奇妙な書き方になります。
  • これまでのところ、自分の言語であるスウェーデン語でのみテストしました。
  • スペースがあることが重要かもしれません。
2
Magnus

また、エスケープされた引用符(\ ")は、いくらか同様に一時停止しているように見えます。少なくとも、Wordの周りに配置すると、Wordの周りにスペースが追加されます。

0
user655489

このソリューションは完璧ではありませんが、@ Aaron Cのソリューションの代わりに、以下のようなカスタムのテキスト読み上げクラスを作成することもできます。このソリューションは、テキストが比較的短く、1分あたりの話し言葉が、使用している言語に対して十分に正確である場合に、十分に機能する可能性があります。

private class CustomTextToSpeech extends TextToSpeech {
    private static final double WORDS_PER_MS = (double)190/60/1000;

    long startTimestamp = 0;
    long pauseTimestamp = 0;

    private Handler handler;
    private Runnable speakRunnable;

    StringBuilder textToSpeechBuilder;

    private boolean isPaused = false;

    public CustomTextToSpeech(Context context, OnInitListener initListener){
        super(context, initListener);

        setOnUtteranceProgressListener(new UtteranceProgressListener() {
            @Override
            public void onDone(String arg0) {
                Log.d(TAG, "tts done. " + arg0);
                startTimestamp = 0;
                pauseTimestamp = 0;
                handler.postDelayed(speakRunnable, TTS_INTERVAL_MS);
            }

            @Override
            public void onError(String arg0) {
                Log.e(TAG, "tts error. " + arg0);
            }

            @Override
            public void onStart(String arg0) {
                Log.d(TAG, "tts start. " + arg0);
                setStartTimestamp(System.currentTimeMillis());
            }
        });

        handler = new Handler();

        speakRunnable = new Runnable() {
            @Override
            public void run() {
                speak();
            }
        };

        textToSpeechBuilder = new StringBuilder(getResources().getString(R.string.talkback_tips));
    }

    public void setStartTimestamp(long timestamp) {
        startTimestamp = timestamp;
    }
    public void setPauseTimestamp(long timestamp) {
        pauseTimestamp = timestamp;
    }

    public boolean isPaused(){
        return (startTimestamp > 0 && pauseTimestamp > 0);
    }

    public void resume(){
        if(handler != null && isPaused){
            if(startTimestamp > 0 && pauseTimestamp > 0){
                handler.postDelayed(speakRunnable, TTS_SETUP_TIME_MS);
            } else {
                handler.postDelayed(speakRunnable, TTS_INTERVAL_MS);
            }
        }

        isPaused = false;
    }

    public void pause(){
        isPaused = true;

        if (handler != null) {
            handler.removeCallbacks(speakRunnable);
            handler.removeMessages(1);
        }

        if(isSpeaking()){
            setPauseTimestamp(System.currentTimeMillis());
        }

        stop();
    }

    public void utter(){
        if(handler != null){
            handler.postDelayed(speakRunnable, TTS_INTERVAL_MS);
        }
    }

    public void speak(){
        Log.d(TAG, "textToSpeechBuilder: " + textToSpeechBuilder.toString());
        if(isPaused()){
            String[] words = textToSpeechBuilder.toString().split(" ");
            int wordsAlreadySpoken = (int)Math.round((pauseTimestamp - startTimestamp)*WORDS_PER_MS);
            words = Arrays.copyOfRange(words, wordsAlreadySpoken-1, words.length);

            textToSpeechBuilder = new StringBuilder();
            for(String s : words){
                textToSpeechBuilder.append(s);
                textToSpeechBuilder.append(" ");
            }
        } else {
            textToSpeechBuilder = new StringBuilder(getResources().getString(R.string.talkback_tips));
        }

        if (tts != null && languageAvailable)
            speak(textToSpeechBuilder.toString(), TextToSpeech.QUEUE_FLUSH, new Bundle(), "utter");
    }
}
0
gareoke