Skip to content

Commit eddb1f2

Browse files
authored
Merge 60fd288 into 61704ff
2 parents 61704ff + 60fd288 commit eddb1f2

7 files changed

Lines changed: 76 additions & 47 deletions

File tree

source/config/configSpec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
# Audio settings
5858
[audio]
5959
audioDuckingMode = integer(default=0)
60-
wasapi = boolean(default=true)
60+
WASAPI = featureFlag(optionsEnum="BoolFlag", behaviorOfDefault="disabled")
6161
soundVolumeFollowsVoice = boolean(default=false)
6262
soundVolume = integer(default=100, min=0, max=100)
6363

source/config/profileUpgradeSteps.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
ReportTableHeaders,
2424
ReportCellBorders,
2525
)
26-
from typing import (
27-
Dict,
28-
)
2926
import configobj.validate
3027
from configobj import ConfigObj
3128

source/gui/nvdaControls.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ def __init__(
459459
name=name,
460460
)
461461

462-
self.SetSelection(self._getChoiceIndex(self._getConfigValue().value))
462+
self.SetSelection(self._getChoiceIndex(configValue.value))
463463
self.defaultValue = self._getConfSpecDefaultValue()
464464
"""The default value of the config spec. Not the "behavior of default".
465465
This is provided to maintain compatibility with other controls in the
@@ -499,10 +499,18 @@ def resetToConfigSpecDefault(self) -> None:
499499
"""
500500
self.SetSelection(self._getChoiceIndex(self.defaultValue))
501501

502+
def _getControlCurrentValue(self) -> enum.Enum:
503+
return list(self._translatedOptions.keys())[self.GetSelection()]
504+
505+
def _getControlCurrentFlag(self) -> FeatureFlag:
506+
flagValue = self._getControlCurrentValue()
507+
currentFlag = self._getConfigValue()
508+
return FeatureFlag(flagValue, currentFlag.behaviorOfDefault)
509+
502510
def saveCurrentValueToConf(self) -> None:
503511
""" Set the config value to the current value of the control.
504512
"""
505-
flagValue: enum.Enum = list(self._translatedOptions.keys())[self.GetSelection()]
513+
flagValue = self._getControlCurrentValue()
506514
keyPath = self._confPath
507515
if not keyPath or len(keyPath) < 1:
508516
raise ValueError("Key path not provided")

source/gui/settingsDialogs.py

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
List,
5656
Optional,
5757
Set,
58+
cast,
5859
)
5960
import core
6061
import keyboardHandler
@@ -976,28 +977,26 @@ def postSave(self):
976977
LanguageRestartDialog(self).ShowModal()
977978

978979

979-
class LanguageRestartDialog(
980+
class _RestartDialog(
980981
gui.contextHelp.ContextHelpMixin,
981982
wx.Dialog, # wxPython does not seem to call base class initializer, put last in MRO
982983
):
984+
_title: str
985+
_message: str
983986

984-
helpId = "GeneralSettingsLanguage"
985-
986-
def __init__(self, parent):
987-
# Translators: The title of the dialog which appears when the user changed NVDA's interface language.
988-
super(LanguageRestartDialog, self).__init__(parent, title=_("Language Configuration Change"))
987+
def __init__(self, parent: wx.Window):
988+
super().__init__(parent, title=self._title)
989989
mainSizer = wx.BoxSizer(wx.VERTICAL)
990990
sHelper = guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL)
991-
# Translators: The message displayed after NVDA interface language has been changed.
992-
sHelper.addItem(wx.StaticText(self, label=_("NVDA must be restarted for the new language to take effect.")))
991+
sHelper.addItem(wx.StaticText(self, label=self._message))
993992

994993
bHelper = sHelper.addDialogDismissButtons(guiHelper.ButtonHelper(wx.HORIZONTAL))
995-
# Translators: The label for a button in the dialog which appears when the user changed NVDA's interface language.
994+
# Translators: The label for a button in a dialog
996995
restartNowButton = bHelper.addButton(self, label=_("Restart &now"))
997996
restartNowButton.Bind(wx.EVT_BUTTON, self.onRestartNowButton)
998997
restartNowButton.SetFocus()
999998

1000-
# Translators: The label for a button in the dialog which appears when the user changed NVDA's interface language.
999+
# Translators: The label for a button in a dialog
10011000
restartLaterButton = bHelper.addButton(self, wx.ID_CLOSE, label=_("Restart &later"))
10021001
restartLaterButton.Bind(wx.EVT_BUTTON, lambda evt: self.Close())
10031002
self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy())
@@ -1011,7 +1010,28 @@ def __init__(self, parent):
10111010
def onRestartNowButton(self, evt):
10121011
self.Destroy()
10131012
config.conf.save()
1014-
queueHandler.queueFunction(queueHandler.eventQueue,core.restart)
1013+
queueHandler.queueFunction(queueHandler.eventQueue, core.restart)
1014+
1015+
1016+
class _WASAPIRestartDialog(_RestartDialog):
1017+
helpId = "WASAPI"
1018+
1019+
# Translators: The title of the dialog which appears when the user updated a setting for audio output
1020+
_title = _("Audio output change")
1021+
1022+
# Translators: The message displayed when the user updated a setting for audio output
1023+
_message = _("NVDA must be restarted for the new audio settings to take effect.")
1024+
1025+
1026+
class LanguageRestartDialog(_RestartDialog):
1027+
helpId = "GeneralSettingsLanguage"
1028+
1029+
# Translators: The title of the dialog which appears when the user changed NVDA's interface language.
1030+
_title = _("Language Configuration Change")
1031+
1032+
# Translators: The message displayed after NVDA interface language has been changed.
1033+
_message = _("NVDA must be restarted for the new language to take effect.")
1034+
10151035

10161036
class SpeechSettingsPanel(SettingsPanel):
10171037
# Translators: This is the label for the speech panel
@@ -3074,27 +3094,26 @@ def __init__(self, parent):
30743094
audioGroup = guiHelper.BoxSizerHelper(self, sizer=audio)
30753095
sHelper.addItem(audioGroup)
30763096

3077-
# Translators: This is the label for a checkbox control in the
3078-
# Advanced settings panel.
3097+
# Translators: This is the label for a checkbox control in the Advanced settings panel.
30793098
label = _("Use WASAPI for audio output (requires restart)")
3080-
self.wasapiCheckBox: wx.CheckBox = audioGroup.addItem(
3081-
wx.CheckBox(audioBox, label=label)
3082-
)
3083-
self.bindHelpEvent("WASAPI", self.wasapiCheckBox)
3084-
self.wasapiCheckBox.Bind(wx.EVT_CHECKBOX, self.onAudioCheckBoxChange)
3085-
self.wasapiCheckBox.SetValue(
3086-
config.conf["audio"]["wasapi"]
3087-
)
3088-
self.wasapiCheckBox.defaultValue = self._getDefaultValue(
3089-
["audio", "wasapi"])
3099+
self.wasapiComboBox = cast(nvdaControls.FeatureFlagCombo, audioGroup.addLabeledControl(
3100+
labelText=label,
3101+
wxCtrlClass=nvdaControls.FeatureFlagCombo,
3102+
keyPath=["audio", "WASAPI"],
3103+
conf=config.conf,
3104+
))
3105+
self.bindHelpEvent("WASAPI", self.wasapiComboBox)
3106+
self.wasapiComboBox.Bind(wx.EVT_CHOICE, self._onWASAPIChange)
3107+
self._oldWASAPIValue: bool = self.wasapiComboBox._getConfigValue().calculated()
3108+
30903109
# Translators: This is the label for a checkbox control in the
30913110
# Advanced settings panel.
30923111
label = _("Volume of NVDA sounds follows voice volume (requires WASAPI)")
30933112
self.soundVolFollowCheckBox: wx.CheckBox = audioGroup.addItem(
30943113
wx.CheckBox(audioBox, label=label)
30953114
)
30963115
self.bindHelpEvent("SoundVolumeFollowsVoice", self.soundVolFollowCheckBox)
3097-
self.soundVolFollowCheckBox.Bind(wx.EVT_CHECKBOX, self.onAudioCheckBoxChange)
3116+
self.soundVolFollowCheckBox.Bind(wx.EVT_CHECKBOX, self._onWASAPIChange)
30983117
self.soundVolFollowCheckBox.SetValue(
30993118
config.conf["audio"]["soundVolumeFollowsVoice"]
31003119
)
@@ -3115,7 +3134,7 @@ def __init__(self, parent):
31153134
)
31163135
self.soundVolSlider.defaultValue = self._getDefaultValue(
31173136
["audio", "soundVolume"])
3118-
self.onAudioCheckBoxChange()
3137+
self._onWASAPIChange()
31193138

31203139
# Translators: This is the label for a group of advanced options in the
31213140
# Advanced settings panel
@@ -3178,8 +3197,8 @@ def onOpenScratchpadDir(self,evt):
31783197
path=config.getScratchpadDir(ensureExists=True)
31793198
os.startfile(path)
31803199

3181-
def onAudioCheckBoxChange(self, evt: Optional[wx.CommandEvent] = None):
3182-
wasapi = self.wasapiCheckBox.IsChecked()
3200+
def _onWASAPIChange(self, evt: Optional[wx.CommandEvent] = None):
3201+
wasapi = bool(self.wasapiComboBox._getControlCurrentFlag())
31833202
self.soundVolFollowCheckBox.Enable(wasapi)
31843203
self.soundVolSlider.Enable(
31853204
wasapi
@@ -3213,7 +3232,7 @@ def haveConfigDefaultsBeenRestored(self):
32133232
and self.loadChromeVBufWhenBusyCombo.isValueConfigSpecDefault()
32143233
and self.caretMoveTimeoutSpinControl.GetValue() == self.caretMoveTimeoutSpinControl.defaultValue
32153234
and self.reportTransparentColorCheckBox.GetValue() == self.reportTransparentColorCheckBox.defaultValue
3216-
and self.wasapiCheckBox.GetValue() == self.wasapiCheckBox.defaultValue
3235+
and self.wasapiComboBox.isValueConfigSpecDefault()
32173236
and self.soundVolFollowCheckBox.GetValue() == self.soundVolFollowCheckBox.defaultValue
32183237
and self.soundVolSlider.GetValue() == self.soundVolSlider.defaultValue
32193238
and set(self.logCategoriesList.CheckedItems) == set(self.logCategoriesList.defaultCheckedItems)
@@ -3242,7 +3261,7 @@ def restoreToDefaults(self):
32423261
self.loadChromeVBufWhenBusyCombo.resetToConfigSpecDefault()
32433262
self.caretMoveTimeoutSpinControl.SetValue(self.caretMoveTimeoutSpinControl.defaultValue)
32443263
self.reportTransparentColorCheckBox.SetValue(self.reportTransparentColorCheckBox.defaultValue)
3245-
self.wasapiCheckBox.SetValue(self.wasapiCheckBox.defaultValue)
3264+
self.wasapiComboBox.resetToConfigSpecDefault()
32463265
self.soundVolFollowCheckBox.SetValue(self.soundVolFollowCheckBox.defaultValue)
32473266
self.soundVolSlider.SetValue(self.soundVolSlider.defaultValue)
32483267
self.logCategoriesList.CheckedItems = self.logCategoriesList.defaultCheckedItems
@@ -3275,7 +3294,7 @@ def onSave(self):
32753294
config.conf["documentFormatting"]["reportTransparentColor"] = (
32763295
self.reportTransparentColorCheckBox.IsChecked()
32773296
)
3278-
config.conf["audio"]["wasapi"] = self.wasapiCheckBox.IsChecked()
3297+
self.wasapiComboBox.saveCurrentValueToConf()
32793298
config.conf["audio"]["soundVolumeFollowsVoice"] = self.soundVolFollowCheckBox.IsChecked()
32803299
config.conf["audio"]["soundVolume"] = self.soundVolSlider.GetValue()
32813300
config.conf["annotations"]["reportDetails"] = self.annotationsDetailsCheckBox.IsChecked()
@@ -3288,6 +3307,7 @@ def onSave(self):
32883307
config.conf['debugLog'][key]=self.logCategoriesList.IsChecked(index)
32893308
config.conf["featureFlag"]["playErrorSound"] = self.playErrorSoundCombo.GetSelection()
32903309

3310+
32913311
class AdvancedPanel(SettingsPanel):
32923312
enableControlsCheckBox = None # type: wx.CheckBox
32933313
# Translators: This is the label for the Advanced settings panel.
@@ -3359,6 +3379,9 @@ def onSave(self):
33593379
):
33603380
self.advancedControls.onSave()
33613381

3382+
def postSave(self):
3383+
if self.advancedControls._oldWASAPIValue != config.conf["audio"]["WASAPI"].calculated():
3384+
_WASAPIRestartDialog(self).ShowModal()
33623385

33633386
def onEnableControlsCheckBox(self, evt):
33643387
# due to some not very well understood mis ordering of event processing, we force NVDA to

source/nvwave.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
UINT,
3737
LPUINT
3838
)
39-
from comtypes import HRESULT, BSTR, GUID
39+
from comtypes import HRESULT, BSTR
4040
from comtypes.hresult import S_OK
4141
import atexit
4242
import weakref
@@ -1044,7 +1044,7 @@ def _deviceNameToId(name, fallbackToDefault=True):
10441044

10451045
def initialize():
10461046
global WavePlayer
1047-
if not config.conf["audio"]["wasapi"]:
1047+
if not config.conf["audio"]["WASAPI"]:
10481048
return
10491049
WavePlayer = WasapiWavePlayer
10501050
NVDAHelper.localLib.wasPlay_create.restype = c_void_p

user_docs/en/changes.t2t

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,6 @@ What's New in NVDA
1313
- The Add-ons Manager has been removed and replaced by the Add-on Store.
1414
- For more information please read the updated user guide.
1515
-
16-
- Enhanced sound management:
17-
- NVDA now outputs audio via the Windows Audio Session API (WASAPI), which may improve the responsiveness, performance and stability of NVDA speech and sounds.
18-
This can be disabled in Advanced settings if audio problems are encountered. (#14697)
19-
- It is now possible to have the volume of NVDA sounds and beeps follow the volume setting of the voice you are using.
20-
This option can be enabled in Advanced settings. (#1409)
21-
- You can now separately control the volume of NVDA sounds.
22-
This can be configured in Advanced settings. (#1409)
23-
-
2416
- New input gestures:
2517
- An unbound gesture to cycle through the available languages for Windows OCR. (#13036)
2618
- An unbound gesture to cycle through the Braille show messages modes. (#14864)
@@ -57,6 +49,15 @@ What's New in NVDA
5749
- When colors are enabled Document Formatting, background colours are now reported in Microsoft Word. (#5866)
5850
- When using Excel shortcuts to toggle format such as bold, italic, underline and strike through of a cell in Excel, the result is now reported. (#14923)
5951
-
52+
- Experimental enhanced sound management:
53+
- NVDA can now output audio via the Windows Audio Session API (WASAPI), which may improve the responsiveness, performance and stability of NVDA speech and sounds. (#14697)
54+
- WASAPI usage can be enabled in Advanced settings.
55+
Additionally, if WASAPI is enabled, the following Advanced settings can also be configured.
56+
- An option to have the volume of NVDA sounds and beeps follow the volume setting of the voice you are using. (#1409)
57+
- An option to separately configure the volume of NVDA sounds. (#1409, #15038)
58+
-
59+
- There is a known issue with intermittent crashing when WASAPI is enabled. (#15150)
60+
-
6061
- In Mozilla Firefox and Google Chrome, NVDA now reports when a control opens a dialog, grid, list or tree if the author has specified this using aria-haspopup. (#14709)
6162
- It is now possible to use system variables (such as ``%temp%`` or ``%homepath%``) in the path specification while creating portable copies of NVDA. (#14680)
6263
- In Windows 10 May 2019 Update and later, NVDA can announce virtual desktop names when opening, changing, and closing them. (#5641)

user_docs/en/userGuide.t2t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2360,7 +2360,7 @@ With several historically popular GUI APIs, the text may be rendered with a tran
23602360
==== Use WASAPI for audio output ====[WASAPI]
23612361
This option enables audio output via the Windows Audio Session API (WASAPI).
23622362
WASAPI is a more modern audio framework which may improve the responsiveness, performance and stability of NVDA audio output, including both speech and sounds.
2363-
This option is enabled by default.
2363+
This option is disabled by default.
23642364
After changing this option, you will need to restart NVDA for the change to take effect.
23652365

23662366
==== Volume of NVDA sounds follows voice volume ====[SoundVolumeFollowsVoice]

0 commit comments

Comments
 (0)