How to pause android.speech.tts.TextToSpeech?

前端 未结 10 949
不知归路
不知归路 2020-12-01 03:47

I\'m playing text with android TTS - android.speech.tts.TextToSpeech

I use: TextToSpeech.speak to speak and .stop to stop. Is

相关标签:
10条回答
  • 2020-12-01 04:15

    You can make the TTS pause between sentences, or anywhere you want by adding up to three periods (".") all followed by a single space " ". The example below has a long pause at the beginning, and again before the message body. I'm not sure that is what you are after though.

        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();
                        }
                    }
                }
    
            }
        }
    };
    

    If you omit the space after the last period it will (or may) not work as expected.

    0 讨论(0)
  • 2020-12-01 04:15

    I used a different approach.

    1. Seperate your text into sentences
    2. Speak every sentence one by one and keep track of the spoken sentence
    3. pause will stop the text instantly
    4. resume will start at the beginning of the last spoken sentence

    Kotlin code:

    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()
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 04:19

    This solution is not perfect, but an alternative to @Aaron C's solution may be to create a custom text to speech class like the below. This solution may work well enough if your text is relatively short and spoken words per minute is accurate enough for the language you are using.

    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 讨论(0)
  • 2020-12-01 04:24

    It seems that if you put a period after a word AND start the next word with a capital letter, just like a new sentence, like this:

    after we came home. We ate dinner.

    the "home. We" will then have a pause in it.

    • This becomes a grammatically strange way of writing it.
    • So far I have only tested this in my own language, Swedish.
    • It might be important that the space is there.
    0 讨论(0)
  • 2020-12-01 04:25

    In the absence of a pause option, you can add silence for the duration of when you want to delay the TTS Engine speaking. This of course would have to be a predetermined 'pause' and wouldn't help to include functionality of a pause button, for example.

    For API < 21 : public int playSilence (long durationInMs, int queueMode, HashMap params)

    For > 21 : public int playSilentUtterance (long durationInMs, int queueMode, String utteranceId)

    Remember to use TextToSpeech.QUEUE_ADD rather than TextToSpeech.QUEUE_FLUSH otherwise it will clear the previously started speech.

    0 讨论(0)
  • 2020-12-01 04:30

    The TTS SDK doesn't have any pause functionality that I know of. But you could use synthesizeToFile() to create an audio file that contains the TTS output. Then, you would use a MediaPlayer object to play, pause, and stop playing the file. Depending on how long the text string is, it might take a little longer for audio to be produced because the synthesizeToFile() function would have to complete the entire file before you could play it, but this delay should be acceptable for most applications.

    0 讨论(0)
提交回复
热议问题