Skip to content

Try next synth if oneCore consistently fails#12647

Merged
seanbudd merged 16 commits into
masterfrom
fix-11544
Jul 29, 2021
Merged

Try next synth if oneCore consistently fails#12647
seanbudd merged 16 commits into
masterfrom
fix-11544

Conversation

@seanbudd

@seanbudd seanbudd commented Jul 15, 2021

Copy link
Copy Markdown
Member

Link to issue number:

Fixes #10451 and fixes #11544

Summary of the issue:

#10451
OneCore voices silently fail when attempting to speak an alphabet they don't support (eg an English voice reading Cyrillic characters). This makes installing NVDA for the first time for the first time inaccessible if someone is using a system with a language that isn't supported by their OneCore installed voices.

#11544
An issue was raised on #11543 where oneCore failed to initialise, causing all speech to fail.
If no speech succeeds, the _player is never set and so a subsequent error is thrown in _processQueue.

Description of how this pull request fixes the issue:

#10451
When picking a synthesizer automatically (using "auto", ie not overriden by a user), fail if the current NVDA language and current system language is not supported by installed OneCore voices.

#11544
If oneCore fails to speak more than N=5 times in a row, try the next synth on the synth priority list.

Testing strategy:

#10451
Manual confirmation that this fixes the issue by installing NVDA:

  • on a fresh config, and
  • with a system language set that OneCore voices doesn't support, or is not installed.
    And having espeak set and read the install dialogs.

Manual confirmation that setting/changing synthesizers works and is respected across restarts.

#11544
Hard to test as it requires a failure external to NVDA, which is unknown how to reproduce. Ensure oneCore works as a synthesizer normally otherwise.

Known issues with pull request:

None

Change log entries:

Bug fixes

- NVDA will default to eSpeak if no installed OneCore voices support the NVDA preferred language. (#10451)
- If OneCore voices consistently fail to speak, revert to eSpeak as a synthesizer. (#11544)

Code Review Checklist:

  • Pull Request description is up to date.
  • Unit tests.
  • System (end to end) tests.
  • Manual testing.
  • User Documentation.
  • Change log entry.
  • Context sensitive help for GUI changes.
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers

@seanbudd seanbudd requested a review from a team as a code owner July 15, 2021 02:03
@seanbudd seanbudd requested a review from feerrenrut July 15, 2021 02:03
@seanbudd seanbudd changed the title move to next synth if oneCore consistently fails Try next synth if oneCore consistently fails Jul 15, 2021
@LeonarddeR

Copy link
Copy Markdown
Collaborator

How is this related to #12646?

Comment thread source/synthDrivers/oneCore.py Outdated
self._consecutiveSpeechFailures += 1
if self._consecutiveSpeechFailures >= self.MAX_CONSECUTIVE_SPEECH_FAILURES:
log.debugWarning("Too many consecutive speech failures, changing synth")
setNextSynth(self.name)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm a bit worried about this implementation, i.e. a synth driver calling a synthDriverHandler function. Could you consider something like the braille handler does, i.e. in _writeCells, it tries to write content to a display. If that fails, it calls handleDisplayUnavailable which performs the fallback.

I think it might be best to use a new exception type for this, e.g. ConsecutiveSPeechFailureException. The OneCore synth can throw that exception in its speak method when it notices the self._consecutiveSpeechFailures limit has been exceeded. Then, the speech manager can catch the exception and perform the fallback.

@seanbudd seanbudd Jul 21, 2021

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Handling failures here is quite tricky. I've opted to queue a synth change instead here

ERROR - unhandled exception (11:22:58.596) - Dummy-3 (20092):
Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 232, in 'calling callback function'
  File "synthDrivers\oneCore.py", line 373, in _callback
    raise AssertionError()
AssertionError

@seanbudd seanbudd marked this pull request as draft July 16, 2021 02:52
@AppVeyorBot

Copy link
Copy Markdown
  • PASS: Translation comments check.
  • PASS: Unit tests.
  • PASS: Lint check.
  • Build execution time has reached the maximum allowed time for your plan (60 minutes).

See test results for failed build of commit 7214a0ed52

Comment thread source/synthDrivers/oneCore.py
Comment thread source/languageHandler.py Outdated
Fetches the locale name of the user's configured language in Windows.
"""
windowsLCID=ctypes.windll.kernel32.GetUserDefaultUILanguage()
windowsLCID = ctypes.windll.kernel32.GetUserDefaultLCID()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ctypes.windll.kernel32.GetUserDefaultUILanguage() returned 'en_GB' when all of my language preferences (including voices) were set to 'en_AU'.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add a comment here to explain the choice of GetUserDefaultLCID over GetUserDefaultUILanguage.

Have you checked the history of this to see if it was previously GetUserDefaultLCID?

@seanbudd seanbudd Jul 28, 2021

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This was changed in a2f0b75, to fix #353. I believe #353 should still be fixed by this change still, or at least improved, as when we try to set the language for the translation service, we now attempt to just use the language code if the country code is not supported.

@LeonarddeR has also made a suggestion to change this to GetUserPreferredUILanguages in #7999, which is another move to consider and probably fix #353 in a more meaningful way. That way we could try multiple preferred languages (with and without country code) and give better internationalisation support.

I think I could revert this change and attempt a fix for that after 2021.2 beta is out

Comment thread source/synthDrivers/oneCore.py
@seanbudd seanbudd marked this pull request as ready for review July 21, 2021 01:24
@seanbudd seanbudd added this to the 2021.3 milestone Jul 21, 2021
@seanbudd seanbudd requested a review from michaelDCurran July 23, 2021 01:01
Comment thread source/speech/manager.py
Comment thread source/synthDriverHandler.py
@seanbudd seanbudd requested a review from feerrenrut July 29, 2021 07:47

@feerrenrut feerrenrut left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add docs to these tests to explain the situations they are testing.

Comment thread tests/unit/test_synthDriverHandler.py Outdated
Comment thread tests/unit/test_synthDriverHandler.py Outdated
self.assertEqual(synthName, synthDriverHandler.getSynth().name)
self.assertEqual(self._oldSynthConfig, config.conf["speech"]["synth"])

def test_setSynth_oneCoreSupportsDefaultLangauge(self):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
def test_setSynth_oneCoreSupportsDefaultLangauge(self):
def test_setSynth_oneCoreSupportsDefaultLanguage(self):

@seanbudd seanbudd requested a review from feerrenrut July 29, 2021 08:43
@seanbudd seanbudd merged commit 8c8e2bb into master Jul 29, 2021
@seanbudd seanbudd deleted the fix-11544 branch July 29, 2021 11:50
seanbudd pushed a commit that referenced this pull request Aug 2, 2021
…oneCore is not supported (#12702)

Some unit tests introduced as part of #12647 were failing under versions of Windows where oneCore was unsupported. Tests which require oneCore being supported are now being skipped on versions of Windows on which oneCore is not supported.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fallback to ESpeak when OneCore fails to initialize Windows OneCore, if a given language isn't installed, speech does not fall back to default voice

6 participants