【问题标题】:How to pause android.speech.tts.TextToSpeech?如何暂停 android.speech.tts.TextToSpeech?
【发布时间】:2011-06-25 14:34:08
【问题描述】:

我正在使用 android TTS 播放文本 - android.speech.tts.TextToSpeech

我使用:TextToSpeech.speak 说话,.stop 停止。有没有办法暂停文本?

【问题讨论】:

    标签: android text-to-speech


    【解决方案1】:

    据我所知,TTS SDK 没有任何暂停功能。但是您可以使用synthesizeToFile() 创建一个包含 TTS 输出的音频文件。然后,您将使用MediaPlayer 对象来播放、暂停和停止播放文件。根据文本字符串的长度,生成音频可能需要更长的时间,因为synthesizeToFile() 函数必须在播放之前完成整个文件,但这种延迟对于大多数应用程序来说应该是可以接受的。

    【讨论】:

    • 请告诉我我们如何知道何时暂停 mediaPlayer?例如:如果字符串在 50 个字符后暂停,我们如何知道我们需要在什么位置暂停 mediaPlayer?
    • 这是公认的答案?似乎要复杂得多。你怎么知道具体什么时候暂停?
    【解决方案2】:

    我使用了字符串拆分并使用了如下所示的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);
        }
    }
    

    【讨论】:

    • 非常感谢.. 它对我有用.. 但我面临的问题是将我传递给 Speech.split("xyz") 的单词留下。例如,我将句子设为“Android 和 Java”,然后 Speech.split(“and”) 然后它首先播放“Android”,然后暂停给定时间,然后播放“Java”。它的离开和没有玩
    • 空间分割,即speech.split("\\s+")
    • 在要暂停的字符串中添加 \n
    【解决方案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();
                        }
                    }
                }
    
            }
        }
    };
    

    如果您在最后一个句点之后省略空格,它将(或可能)无法按预期工作。

    【讨论】:

    • 这在不同的 TTS 上有所不同
    【解决方案4】:

    在没有暂停选项的情况下,您可以在想要延迟 TTS 引擎讲话期间添加静音。这当然必须是预先确定的“暂停”,例如,包括暂停按钮的功能也无济于事。

    对于 API public int playSilence (long durationInMs, int queueMode, HashMap params)

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

    记得使用TextToSpeech.QUEUE_ADD而不是TextToSpeech.QUEUE_FLUSH,否则会清除之前启动的语音。

    【讨论】:

      【解决方案5】:

      我使用了不同的方法。

      1. 将文本分成句子
      2. 逐句说出每个句子,并跟踪说出的句子
      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()
              }
          }
      }
      

      【讨论】:

      • 嗨 @rm -rf,你能不能分享一下 utteranceId 是什么?
      【解决方案6】:

      我还没有尝试过,但我需要做同样的事情。我的想法是首先将您的语音文本拆分为一组单词。

      然后创建一个递归函数,在当前单词完成后播放下一个单词,同时保留当前单词的计数器。

      【讨论】:

        【解决方案7】:

        messages 分成多个部分,并使用onutteranceprogress 侦听器侦听最后一个utterance

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

        【讨论】:

          【解决方案8】:

          似乎如果你在一个单词后面加上一个句点,并且下一个单词以大写字母开头,就像一个新句子一样,像这样:

          我们回家后。我们吃了晚饭。

          “家。我们”将在其中暂停。

          • 这变成了一种语法上奇怪的写法。
          • 到目前为止,我只用我自己的语言瑞典语对此进行了测试。
          • 那里的空间可能很重要。

          【讨论】:

            【解决方案9】:

            此外,转义的引号 (\") 似乎也会暂停 - 至少,如果你将它放在单词周围,它会在单词周围增加空格。

            【讨论】:

              【解决方案10】:

              这个解决方案并不完美,但@Aaron C 的解决方案的替代方案可能是创建一个自定义文本到语音类,如下所示。如果您的文本相对较短并且每分钟的口语对于您使用的语言来说足够准确,则此解决方案可能会运行良好。

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

              【讨论】:

              • tts 参考在哪里?
              • 什么是 TTS_INTERVAL_MS 和 TTS_SETUP_TIME_MS ?
              • TTS_INTERVAL_MS 将在此定义的时间间隔内重复语音文本。如果不需要,您可以更改为 .post 而不是 .postDelayed (仅有助于测试 pause&resume 与您的文本)。 TTS_SETUP_TIME_MS 是您想要等待的时间延迟量,直到说出文本。
              猜你喜欢
              • 2021-02-03
              • 2016-01-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-09-20
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多