【问题标题】:What in TtsService could explain the lack of onUtteranceCompleted() for playEarcon()?TtsService 中的什么可以解释 playEarcon() 缺少 onUtteranceCompleted() 的原因?
【发布时间】:2012-07-13 07:14:12
【问题描述】:

前段时间,我发现playEarcon()never producesonUtteranceCompleted()

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

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

关于my test jig的一些事实:

  1. onUtteranceCompleted() 总是在 earcon 之前到达话语 ID。该话语是普通的 TTS 话语,而不是耳标。
  2. 之后的耳标确实播放(即完全按预期播放)。
  3. onUtteranceCompleted() 表示那个耳标从不出现。这是非常一致且可重现的行为。

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

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

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

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

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

所以,我们只剩下第二个候选人TtsService.onCompletion(),作为playEarcon()never producesonUtteranceCompleted()的可能解释:

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

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

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

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

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

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

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

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

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

对于解开这个谜团有什么建议或其他解释吗?

【问题讨论】:

  • 我们也有同样的问题,解决方法是在earcon后面加一个空的话语。看起来较新的 API 版本 (16) 确实 为耳标生成回调,对此进行调查。
  • TextToSpeech 构造函数中还有一个令人讨厌的竞争条件,导致您的 onInit 处理程序访问 TTS 引擎的 NULL(大约 1% 的机会),因为它不在回调参数!它实际上在构造函数完成执行之前调用您的onInit。这很严重,因为他们希望您在onInit 中进行初始化(setOnUtteranceCompleteaddEarcon)。
  • 已在模拟器中签入,playEarcon 现在在播放完毕后会发送回调。这是在 API 15 及更高版本上。对于较低的 API,您可以使用我在之前评论中提到的解决方法。
  • @escape-llc 谢谢++。这正是我为低于 15 的 API 使用的解决方法,但我不明白为什么会发生这种情况的事实让我抓狂。有什么想法吗?
  • 顺便说一句,您的分析很好,感谢您抽出宝贵的时间。但请注意,在原始TextToSpeech 调用中传递的MaponCompletion 处理程序中找不到;它事先被转换为ArrayList,也许缺陷在那个代码中?也许playEarcon 不会传播?此外,该服务与Engine 服务对话,因此这也可能是某些东西不会传播的地方,我没有详细检查实现。看看设置mCurrentSpeechItem

标签: android text-to-speech android-mediaplayer onutterancecompleted


【解决方案1】:

807 行检查android.speech.tts.TextToSpeech#playEarcon()。传递给 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-04-25
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2016-06-06
    • 2021-09-12
    • 1970-01-01
    • 2013-03-02
    • 1970-01-01
    相关资源
    最近更新 更多