Skip to content

Commit d2b34e4

Browse files
authored
Fix SAPI5 (#18300)
Fixes #18298. Fixes #18301. Summary of the issue: When using SAPI 5 voices, NVDA may be frozen at some point. Seems like the thread was stuck calling WavePlayer.idle. After selecting a SAPI5 Eloquence voice, NVDA would fail to load the same voice and fall back to OneCore voices on next launch. Description of user facing changes: The issue above should be fixed. Description of developer facing changes: Variable isSpeaking is replaced with _isCancelled to make its meaning clearer. SynthDriverAudioStream is renamed to SynthDriverAudio. Description of development approach: SpVoice.Speak() waits for SAPI5's audio thread, and if the audio thread waits for WavePlayer.idle(), SpVoice.Speak() will also block, causing dead-locks if the WavePlayer is being paused. To avoid this, a dedicated thread _speakThread is created to send speak requests to SAPI5 one by one. A separate speech queue, _speakRequests, is maintained. Whenever the synth wants to speak, it places a speak request in the queue. The speak thread handles the requests one by one. Therefore, SAPI5's own queue is bypassed. When nothing is being spoken, it takes the next request and let SAPI5 speak it, then wait for it to finish this utterance. When the queue becomes empty, the speak thread calls WavePlayer.idle. Neither the SAPI5 audio thread nor the main thread will be blocked. As SAPI5 speak is never called in the main thread, it will not be blocked. When cancel is called, WavePlayer.stop is called to break out of pausing or idling. The rest of the cancelling work is done in the thread. SynthDriverAudioStream is renamed to SynthDriverAudio, and now implements the ISpAudio interface, which can get the wave format of the voice directly during format negotiation, making it possible to get rid of the legacy audio system entirely.
1 parent 3f8b197 commit d2b34e4

File tree

3 files changed

+474
-114
lines changed

3 files changed

+474
-114
lines changed

source/synthDrivers/sapi4.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@
8686
from speech.types import SpeechSequence
8787

8888

89+
windll.ole32.CoTaskMemAlloc.restype = c_void_p
90+
91+
8992
class SynthDriverBufSink(COMObject):
9093
_com_interfaces_ = [ITTSBufNotifySink]
9194

0 commit comments

Comments
 (0)