Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

speechManager: Ensure handling of skipped indexes #10730

Merged
merged 4 commits into from
Jan 31, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions source/speech/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import queueHandler
import synthDriverHandler
from .commands import *
from .commands import IndexCommand
from .priorities import Spri, SPEECH_PRIORITIES

class ParamChangeTracker(object):
Expand Down Expand Up @@ -147,6 +148,8 @@ def _reset(self):
self._curPriQueue = None
#: Maps indexes to BaseCallbackCommands.
self._indexesToCallbacks = {}
#: a list of indexes currently being spoken by the synthesizer
self._indexesSpeaking = []
#: Whether to push more speech when the synth reports it is done speaking.
self._shouldPushWhenDoneSpeaking = False

Expand Down Expand Up @@ -287,6 +290,11 @@ def _pushNextSpeech(self, doneSpeaking):
return self._pushNextSpeech(True)
seq = self._buildNextUtterance()
if seq:
# Record all indexes that will be sent to the synthesizer
# So that we can handle any accidentally skipped indexes.
for item in seq:
if isinstance(item, IndexCommand):
self._indexesSpeaking.append(item.index)
getSynth().speak(seq)

def _getNextPriority(self):
Expand Down Expand Up @@ -366,16 +374,38 @@ def _removeCompletedFromQueue(self, index):
return True, endOfUtterance

def _handleIndex(self, index):
valid, endOfUtterance = self._removeCompletedFromQueue(index)
if not valid:
return
callbackCommand = self._indexesToCallbacks.pop(index, None)
if callbackCommand:
# A synth (such as OneCore) may skip indexes
# If before another index, with no text content in between.
# Therefore, detect this and ensure we handle all skipped indexes.
handleIndexes = []
for oldIndex in list(self._indexesSpeaking):
if oldIndex < index:
log.debugWarning("Handling skipped index %s" % oldIndex)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message is emitted later as well.

handleIndexes.append(oldIndex)
handleIndexes.append(index)
valid, endOfUtterance = False, False
for i in handleIndexes:
try:
callbackCommand.run()
except:
log.exception("Error running speech callback")
self._indexesSpeaking.remove(i)
except ValueError:
log.debug("Unknown index %s, speech probably cancelled from main thread." % i)
break # try the rest, this is a very unexpected path.
if i != index:
log.debugWarning("Handling skipped index %s" % i)
# we must do the following for each index, any/all of them may be end of utterance, which must
# trigger _pushNextSpeech
_valid, _endOfUtterance = self._removeCompletedFromQueue(i)
valid = valid or _valid
endOfUtterance = endOfUtterance or _endOfUtterance
if _valid:
callbackCommand = self._indexesToCallbacks.pop(i, None)
if callbackCommand:
try:
callbackCommand.run()
except Exception:
log.exception("Error running speech callback")
if endOfUtterance:
# Even if we have many indexes, we should only push next speech once.
self._pushNextSpeech(False)

def _onSynthDoneSpeaking(self, synth=None):
Expand Down