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:
关于我的测试夹具的一些事实:
-
onUtteranceCompleted()
always arrives for utterance ID preceding the earcon. That utterance is an ordinary TTS utterance, not an earcon. - onUtteranceCompleted()总是到达earcon之前的话语ID。这种话语是普通的TTS话语,而不是一种耳语。
- The earcon after that does play out (i.e. exactly as intended).
- 之后的耳塞确实发挥出来(即完全符合预期)。
-
onUtteranceCompleted()
for that earcon never shows up. This is very consistent and reproducible behavior. - 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()的到达(或不存在):
- TtsService.processSpeechQueue()
- TtsService.processSpeechQueue()
- TtsService.onCompletion()
- 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():
- currentSpeechItemCopy == null
- currentSpeechItemCopy == null
- utteranceId.length() == 0
- 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:
所以,我们又有两种可能性,这两种可能性对我来说都没有多大意义:
- By the time an earcon's onCompletion() is called, earcon's
mCurrentSpeechItem
is null. But why? - 当调用earcon的onCompletion()时,earcon的mCurrentSpeechItem为null。但为什么?
- mCallbacksMap is empty. What is it and when does it ever get populated?
- 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);
}
...
}