34

前段时间,我发现playEarcon() 永远不会产生 onUtteranceCompleted().

当时,我只是将“在合成话语时调用”的文档解释为onUtteranceCompleted()不适用于耳控,因为耳控并不是 TTS 合成的真正结果。

但是再次查看 Android 的源代码,我根本找不到可以证明我的解释合理的解释。

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

  1. onUtteranceCompleted()总是在 earcon 之前到达话语 ID。该话语是普通的 TTS 话语,而不是耳标。
  2. 之后的earcon确实发挥了作用(即完全符合预期)。
  3. onUtteranceCompleted()因为那个耳标永远不会出现。这是非常一致且可重现的行为。

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

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

如果您检查该代码,您将看到第三个候选者 TtsService.getSoundResource()被排除在外(因为我的earcon 缺少 onUtteranceComplete 负责),因为上面的事实#2:earcon 总是播放,因此getSoundResource()不可能返回空值。

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

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

所以,我们只剩下第二个候选者,TtsService.onCompletion(),作为为什么 aplayEarcon() 从不产生 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();
}

在那里,只有 2 个条件无法产生dispatchUtteranceCompletedCallback()

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

但我确信可以排除条件 #2,因为我记录了所有 utteranceIds 并且耳标肯定存在。

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

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

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

所以,我们再次留下了两种可能性,这两种可能性对我来说都没有多大意义:

  1. 在调用 earcon 的onCompletion()时,earcon 的mCurrentSpeechItem值为空。但是为什么?
  2. mCallbacksMap为空。它是什么,它什么时候被填充?

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

4

1 回答 1

1

检查android.speech.tts.TextToSpeech#playEarcon()在第807行。传递给 text-to-speech 服务绑定器的 params 参数为 null,这意味着该服务永远不会收到您的话语 ID。

 public int playEarcon(String earcon, int queueMode,
         HashMap<String,String> params) {
     synchronized (mStartLock) {
         ...
         result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
     }
     ...
 }
于 2012-09-12T07:29:28.270 回答