【发布时间】:2012-07-13 07:14:12
【问题描述】:
前段时间,我发现playEarcon()never producesonUtteranceCompleted()。
当时我只是将“当话语合成时调用”的文档解释为 onUtteranceCompleted() 不适用于耳标,因为耳标并不是 TTS 的结果合成。
但是再次查看 Android 的源代码,我根本找不到可以证明我的解释合理的解释。
关于my test jig的一些事实:
-
onUtteranceCompleted()总是在 earcon 之前到达话语 ID。该话语是普通的 TTS 话语,而不是耳标。 - 之后的耳标确实播放(即完全按预期播放)。
-
onUtteranceCompleted()表示那个耳标从不出现。这是非常一致且可重现的行为。
深入研究 TtsService 源代码,似乎只有 2 种方法会影响onUtteranceCompleted() 的到达(或不存在):
如果您检查该代码,您将看到第三个候选者 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():
- currentSpeechItemCopy == null
- utteranceId.length() == 0
但我确信可以排除条件 #2,因为我记录了所有 utteranceIds,并且 earcon 肯定存在。
另外,检查整个系统日志:
Log.v(SERVICE_TAG, "TTS callback: dispatch started");
缺少的onUtteranceCompleted() 可能是dispatchUtteranceCompletedCallback() 未被调用的结果,但也可能是mCallbacksMap.get(packageName) 返回null 的结果。
所以,我们又留下了两种可能性,这两种可能性对我来说都没有多大意义:
- 在调用 earcon 的 onCompletion() 时,earcon 的
mCurrentSpeechItem为空。但是为什么? - mCallbacksMap 为空。它是什么,什么时候出现?
对于解开这个谜团有什么建议或其他解释吗?
【问题讨论】:
-
我们也有同样的问题,解决方法是在earcon后面加一个空的话语。看起来较新的 API 版本 (16) 确实 为耳标生成回调,对此进行调查。
-
TextToSpeech构造函数中还有一个令人讨厌的竞争条件,导致您的onInit处理程序访问 TTS 引擎的 NULL(大约 1% 的机会),因为它不在回调参数!它实际上在构造函数完成执行之前调用您的onInit。这很严重,因为他们希望您在onInit中进行初始化(setOnUtteranceComplete,addEarcon)。 -
已在模拟器中签入,
playEarcon现在在播放完毕后会发送回调。这是在 API 15 及更高版本上。对于较低的 API,您可以使用我在之前评论中提到的解决方法。 -
@escape-llc 谢谢++。这正是我为低于 15 的 API 使用的解决方法,但我不明白为什么会发生这种情况的事实让我抓狂。有什么想法吗?
-
顺便说一句,您的分析很好,感谢您抽出宝贵的时间。但请注意,在原始
TextToSpeech调用中传递的Map在onCompletion处理程序中找不到;它事先被转换为ArrayList,也许缺陷在那个代码中?也许playEarcon不会传播?此外,该服务与Engine服务对话,因此这也可能是某些东西不会传播的地方,我没有详细检查实现。看看设置mCurrentSpeechItem。
标签: android text-to-speech android-mediaplayer onutterancecompleted