什么TtsService可以解释playEarcon()缺少onUtteranceCompleted()?

时间:2022-02-08 19:00:07

A while ago, I discovered that playEarcon() never produces onUtteranceCompleted().

前段时间,我发现playEarcon()从不生成onUtteranceCompleted()。

At the time I just interpreted the documentation that said "Called when an utterance has been synthesized" as onUtteranceCompleted() being not applicable for earcons because, an earcon isn't really a result of TTS synthesization.

当时我只是解释说“当话语被合成时调用”的文档,因为onUtteranceCompleted()不适用于earcons,因为,earcon实际上并不是TTS合成的结果。

But looking again Android's source code, I simply can't find an explanation that would justify my interpretation.

但是再看看Android的源代码,我根本找不到能够证明我解释的解释。

A few facts about my test jig:

关于我的测试夹具的一些事实:

  1. onUtteranceCompleted() always arrives for utterance ID preceding the earcon. That utterance is an ordinary TTS utterance, not an earcon.
  2. onUtteranceCompleted()总是到达earcon之前的话语ID。这种话语是普通的TTS话语,而不是一种耳语。
  3. The earcon after that does play out (i.e. exactly as intended).
  4. 之后的耳塞确实发挥出来(即完全符合预期)。
  5. onUtteranceCompleted() for that earcon never shows up. This is very consistent and reproducible behavior.
  6. onEtteranceCompleted()为那个earcon永远不会出现。这是非常一致和可重复的行为。

Delving deep into the TtsService source code, there seem to be only 2 methods that could affect the arrival (or absence) of onUtteranceCompleted():

深入研究TtsService源代码,似乎只有2种方法可以影响onUtteranceCompleted()的到达(或不存在):

  1. TtsService.processSpeechQueue()
  2. TtsService.processSpeechQueue()
  3. TtsService.onCompletion()
  4. TtsService.onCompletion()

If you examine that code, you will see that a 3rd candidate, TtsService.getSoundResource() is ruled out (as being responsible for the lack of onUtteranceComplete for my earcon) because of fact #2 above: The earcon always plays, hence getSoundResource() cannot possibly return null.

如果你检查那个代码,你会看到第三个候选者,TtsService.getSoundResource()被排除(由于我的earcon缺乏onUtteranceComplete),因为上面的事实#2:earcon总是在播放,因此getSoundResource( )不可能返回null。

Using the same logic, the 1st candidate, TtsService.processSpeechQueue(), can also be ruled out, for the same fact #2: The earcon always plays, hence the following 2 critical statements are always executed:

使用相同的逻辑,第一个候选者TtsService.processSpeechQueue()也可以被排除,因为相同的事实#2:earcon总是在播放,因此总是执行以下2个关键语句:

1108   mPlayer.setOnCompletionListener(this);
...
1111   mPlayer.start();

So, we are left with the 2nd candidate only, TtsService.onCompletion(), as a possible explanation for why a playEarcon() never produces onUtteranceCompleted():

所以,我们只剩下第二个候选者TtsService.onCompletion(),作为playEarcon()永远不会产生onUtteranceCompleted()的原因的可能解释:

public void onCompletion(MediaPlayer arg0) {
  // mCurrentSpeechItem may become null if it is stopped at the same
  // time it completes.
  SpeechItem currentSpeechItemCopy = mCurrentSpeechItem;
  if (currentSpeechItemCopy != null) {
    String callingApp = currentSpeechItemCopy.mCallingApp;
    ArrayList<String> params = currentSpeechItemCopy.mParams;
    String utteranceId = "";
    if (params != null) {
      for (int i = 0; i < params.size() - 1; i = i + 2) {
        String param = params.get(i);
        if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)) {
          utteranceId = params.get(i + 1);
        }
      }
    }
    if (utteranceId.length() > 0) {
      dispatchUtteranceCompletedCallback(utteranceId, callingApp);
    }
  }
  processSpeechQueue();
}

In there, there are only 2 conditions that would fail to produce dispatchUtteranceCompletedCallback():

在那里,只有两个条件无法生成dispatchUtteranceCompletedCallback():

  1. currentSpeechItemCopy == null
  2. currentSpeechItemCopy == null
  3. utteranceId.length() == 0
  4. utteranceId.length()== 0

But I know for sure that condition #2 can be ruled out because I log all utteranceIds and the earcon's are definitely there.

但我肯定知道条件#2可以排除,因为我记录所有的话语和耳塞肯定在那里。

Also, examining the entire system log:

另外,检查整个系统日志:

Log.v(SERVICE_TAG, "TTS callback: dispatch started");

The missing onUtteranceCompleted() could be the result of dispatchUtteranceCompletedCallback() not being called, but it could also be the result of mCallbacksMap.get(packageName) returning null.

缺少onUtteranceCompleted()可能是dispatchUtteranceCompletedCallback()没有被调用的结果,但它也可能是mCallbacksMap.get(packageName)返回null的结果。

So, we are left again with 2 possibilities, both of which don't make to me much sense:

所以,我们又有两种可能性,这两种可能性对我来说都没有多大意义:

  1. By the time an earcon's onCompletion() is called, earcon's mCurrentSpeechItem is null. But why?
  2. 当调用earcon的onCompletion()时,earcon的mCurrentSpeechItem为null。但为什么?
  3. mCallbacksMap is empty. What is it and when does it ever get populated?
  4. mCallbacksMap为空。什么是它什么时候填充?

Any suggestions or other explanations for solving this mystery?

解决这个谜团的任何建议或其他解释?

1 个解决方案

#1


1  

Check android.speech.tts.TextToSpeech#playEarcon() at line 807. The params argument passed to the text-to-speech service binder is null, which means the service never receives your utterance ID.

检查第807行的android.speech.tts.TextToSpeech#playEarcon()。传递给文本转语音服务活页夹的params参数为null,这意味着该服务永远不会收到您的话语ID。

 public int playEarcon(String earcon, int queueMode,
         HashMap<String,String> params) {
     synchronized (mStartLock) {
         ...
         result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
     }
     ...
 }

#1


1  

Check android.speech.tts.TextToSpeech#playEarcon() at line 807. The params argument passed to the text-to-speech service binder is null, which means the service never receives your utterance ID.

检查第807行的android.speech.tts.TextToSpeech#playEarcon()。传递给文本转语音服务活页夹的params参数为null,这意味着该服务永远不会收到您的话语ID。

 public int playEarcon(String earcon, int queueMode,
         HashMap<String,String> params) {
     synchronized (mStartLock) {
         ...
         result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
     }
     ...
 }