Skip to content

Commit

Permalink
Merge branch 'master' into launcherSound
Browse files Browse the repository at this point in the history
# Conflicts:
#	user_docs/en/changes.md
  • Loading branch information
SaschaCowley committed Dec 13, 2024
2 parents 6aa94ad + 6d02759 commit 3c6ac4e
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 710 deletions.
2 changes: 1 addition & 1 deletion appveyor/scripts/pushPackagingInfo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ $ErrorActionPreference = "Stop";
.\venvUtils\exportPackageList.bat installed_python_packages.txt
Push-AppveyorArtifact installed_python_packages.txt
$appVeyorUrl = "https://ci.appveyor.com"
$exe = Get-ChildItem -Name output\*.exe
$exe = Get-ChildItem -Name output\nvda_*.exe
if($?){
$exeUrl="$appVeyorUrl/api/buildjobs/$env:APPVEYOR_JOB_ID/artifacts/output/$exe"
if ($env:APPVEYOR_PULL_REQUEST_NUMBER -ne $null) {
Expand Down
32 changes: 13 additions & 19 deletions source/audio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
)
from . import appsVolume, soundSplit, utils
import atexit
import nvwave
from pycaw.utils import AudioUtilities
from comtypes import COMError
from logHandler import log
Expand All @@ -25,30 +24,25 @@


def initialize() -> None:
if nvwave.usingWasapiWavePlayer():
try:
AudioUtilities.GetAudioSessionManager()
except COMError:
log.exception("Could not initialize audio session manager")
return
log.debug("Initializing utils")
utils.initialize()
log.debug("Initializing appsVolume")
appsVolume.initialize()
log.debug("Initializing soundSplit")
soundSplit.initialize()
global audioUtilitiesInitialized
audioUtilitiesInitialized = True
else:
log.debug("Cannot initialize audio utilities as WASAPI is disabled")
try:
AudioUtilities.GetAudioSessionManager()
except COMError:
log.exception("Could not initialize audio session manager")
return
log.debug("Initializing utils")
utils.initialize()
log.debug("Initializing appsVolume")
appsVolume.initialize()
log.debug("Initializing soundSplit")
soundSplit.initialize()
global audioUtilitiesInitialized
audioUtilitiesInitialized = True


@atexit.register
def terminate():
if not audioUtilitiesInitialized:
log.debug("Skipping terminating audio utilities as initialization was skipped.")
elif not nvwave.usingWasapiWavePlayer():
log.debug("Skipping terminating audio utilites as WASAPI is disabled.")
else:
soundSplit.terminate()
appsVolume.terminate()
Expand Down
17 changes: 0 additions & 17 deletions source/audio/appsVolume.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import config
import globalVars
from logHandler import log
import nvwave
from pycaw.utils import AudioSession
import ui
from dataclasses import dataclass
Expand Down Expand Up @@ -105,13 +104,6 @@ def _updateAppsVolumeImpl(
_activeCallback.register()


_WASAPI_DISABLED_MESSAGE: str = _(
# Translators: error message when wasapi is turned off.
"Application volume cannot be controlled by NVDA when WASAPI is disabled. "
"Please enable it in the advanced settings panel.",
)


_VOLUME_ADJUSTMENT_DISABLED_MESSAGE: str = _(
# Translators: error message when applications' volume is disabled
"Application volume control disabled",
Expand All @@ -121,9 +113,6 @@ def _updateAppsVolumeImpl(
def _adjustAppsVolume(
volumeAdjustment: int | None = None,
):
if not nvwave.usingWasapiWavePlayer():
ui.message(_WASAPI_DISABLED_MESSAGE)
return
volume: int = config.conf["audio"]["applicationsSoundVolume"]
muted: bool = config.conf["audio"]["applicationsSoundMuted"]
state = config.conf["audio"]["applicationsVolumeMode"]
Expand All @@ -149,9 +138,6 @@ def _adjustAppsVolume(


def _toggleAppsVolumeState():
if not nvwave.usingWasapiWavePlayer():
ui.message(_WASAPI_DISABLED_MESSAGE)
return
state = config.conf["audio"]["applicationsVolumeMode"]
volume: int = config.conf["audio"]["applicationsSoundVolume"]
muted: bool = config.conf["audio"]["applicationsSoundMuted"]
Expand All @@ -175,9 +161,6 @@ def _toggleAppsVolumeState():


def _toggleAppsVolumeMute():
if not nvwave.usingWasapiWavePlayer():
ui.message(_WASAPI_DISABLED_MESSAGE)
return
state = config.conf["audio"]["applicationsVolumeMode"]
volume: int = config.conf["audio"]["applicationsSoundVolume"]
muted: bool = config.conf["audio"]["applicationsSoundMuted"]
Expand Down
9 changes: 0 additions & 9 deletions source/audio/soundSplit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from enum import IntEnum, unique
import globalVars
from logHandler import log
import nvwave
from pycaw.utils import AudioSession
import ui
from utils.displayString import DisplayStringIntEnum
Expand Down Expand Up @@ -163,14 +162,6 @@ def _setSoundSplitState(state: SoundSplitState) -> dict:


def _toggleSoundSplitState() -> None:
if not nvwave.usingWasapiWavePlayer():
message = _(
# Translators: error message when wasapi is turned off.
"Sound split cannot be used. "
"Please enable WASAPI in the Advanced category in NVDA Settings to use it.",
)
ui.message(message)
return
state = SoundSplitState(config.conf["audio"]["soundSplitState"])
allowedStates: list[int] = config.conf["audio"]["includedSoundSplitModes"]
try:
Expand Down
6 changes: 6 additions & 0 deletions source/browseMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -1999,6 +1999,12 @@ def event_gainFocus(self, obj, nextHandler):
# and this was the last non-root node with focus, so ignore this focus event.
# Otherwise, if the user switches away and back to this document, the cursor will jump to this node.
# This is not ideal if the user was positioned over a node which cannot receive focus.
# #17501: Even though we're ignoring this event, we still need to call
# _postGainFocus. This does things such as initialize auto select detection
# for editable text controls. Without this, the focus object might not
# behave correctly (e.g. text selection changes might not be reported) if the
# user switches to focus mode with this object still focused.
self._postGainFocus(obj)
return
if obj == self.rootNVDAObject:
if self.passThrough:
Expand Down
1 change: 0 additions & 1 deletion source/config/configSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
# Audio settings
[audio]
audioDuckingMode = integer(default=0)
WASAPI = featureFlag(optionsEnum="BoolFlag", behaviorOfDefault="enabled")
soundVolumeFollowsVoice = boolean(default=false)
soundVolume = integer(default=100, min=0, max=100)
audioAwakeTime = integer(default=30, min=0, max=3600)
Expand Down
68 changes: 20 additions & 48 deletions source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3048,17 +3048,19 @@ def makeSettings(self, settingsSizer: wx.BoxSizer) -> None:
# Translators: This is the label for the select output device combo in NVDA audio settings.
# Examples of an output device are default soundcard, usb headphones, etc.
deviceListLabelText = _("Audio output &device:")
deviceNames = nvwave.getOutputDeviceNames()
# #11349: On Windows 10 20H1 and 20H2, Microsoft Sound Mapper returns an empty string.
if deviceNames[0] in ("", "Microsoft Sound Mapper"):
# Translators: name for default (Microsoft Sound Mapper) audio output device.
deviceNames[0] = _("Microsoft Sound Mapper")
# The Windows Core Audio device enumeration does not have the concept of an ID for the default output device, so we have to insert something ourselves instead.
# Translators: Value to show when choosing to use the default audio output device.
deviceNames = (_("Default output device"), *nvwave.getOutputDeviceNames())
self.deviceList = sHelper.addLabeledControl(deviceListLabelText, wx.Choice, choices=deviceNames)
self.bindHelpEvent("SelectSynthesizerOutputDevice", self.deviceList)
try:
selection = deviceNames.index(config.conf["speech"]["outputDevice"])
except ValueError:
selectedOutputDevice = config.conf["speech"]["outputDevice"]
if selectedOutputDevice == "default":
selection = 0
else:
try:
selection = deviceNames.index(selectedOutputDevice)
except ValueError:
selection = 0
self.deviceList.SetSelection(selection)

# Translators: This is a label for the audio ducking combo box in the Audio Settings dialog.
Expand Down Expand Up @@ -3164,7 +3166,6 @@ def makeSettings(self, settingsSizer: wx.BoxSizer) -> None:
initial=config.conf["audio"]["audioAwakeTime"],
)
self.bindHelpEvent("AudioAwakeTime", self.audioAwakeTimeEdit)
self.audioAwakeTimeEdit.Enable(nvwave.usingWasapiWavePlayer())

def _appendSoundSplitModesList(self, settingsSizerHelper: guiHelper.BoxSizerHelper) -> None:
self._allSoundSplitModes = list(audio.SoundSplitState)
Expand All @@ -3182,9 +3183,13 @@ def _appendSoundSplitModesList(self, settingsSizerHelper: guiHelper.BoxSizerHelp
self.soundSplitModesList.Select(0)

def onSave(self):
if config.conf["speech"]["outputDevice"] != self.deviceList.GetStringSelection():
# We already use "default" as the key in the config spec, so use it here as an alternative to Microsoft Sound Mapper.
selectedOutputDevice = (
"default" if self.deviceList.GetSelection() == 0 else self.deviceList.GetStringSelection()
)
if config.conf["speech"]["outputDevice"] != selectedOutputDevice:
# Synthesizer must be reload if output device changes
config.conf["speech"]["outputDevice"] = self.deviceList.GetStringSelection()
config.conf["speech"]["outputDevice"] = selectedOutputDevice
currentSynth = getSynth()
if not setSynth(currentSynth.name):
_synthWarningDialog(currentSynth.name)
Expand All @@ -3200,8 +3205,7 @@ def onSave(self):

index = self.soundSplitComboBox.GetSelection()
config.conf["audio"]["soundSplitState"] = index
if nvwave.usingWasapiWavePlayer():
audio._setSoundSplitState(audio.SoundSplitState(index))
audio._setSoundSplitState(audio.SoundSplitState(index))
config.conf["audio"]["includedSoundSplitModes"] = [
mIndex
for mIndex in range(len(self._allSoundSplitModes))
Expand Down Expand Up @@ -3229,22 +3233,11 @@ def onPanelActivated(self):

def _onSoundVolChange(self, event: wx.Event) -> None:
"""Called when the sound volume follow checkbox is checked or unchecked."""
wasapi = nvwave.usingWasapiWavePlayer()
self.soundVolFollowCheckBox.Enable(wasapi)
self.soundVolSlider.Enable(
wasapi and not self.soundVolFollowCheckBox.IsChecked(),
)
self.soundSplitComboBox.Enable(wasapi)
self.soundSplitModesList.Enable(wasapi)
self.soundVolSlider.Enable(not self.soundVolFollowCheckBox.IsChecked())

avEnabled = config.featureFlagEnums.AppsVolumeAdjusterFlag.ENABLED
self.appSoundVolSlider.Enable(
wasapi and self.appVolAdjusterCombo._getControlCurrentValue() == avEnabled,
)
self.muteOtherAppsCheckBox.Enable(
wasapi and self.appVolAdjusterCombo._getControlCurrentValue() == avEnabled,
)
self.appVolAdjusterCombo.Enable(wasapi)
self.appSoundVolSlider.Enable(self.appVolAdjusterCombo._getControlCurrentValue() == avEnabled)
self.muteOtherAppsCheckBox.Enable(self.appVolAdjusterCombo._getControlCurrentValue() == avEnabled)

def isValid(self) -> bool:
enabledSoundSplitModes = self.soundSplitModesList.CheckedItems
Expand Down Expand Up @@ -3838,26 +3831,6 @@ def __init__(self, parent):
["documentFormatting", "reportTransparentColor"],
)

# Translators: This is the label for a group of advanced options in the
# Advanced settings panel
label = _("Audio")
audio = wx.StaticBoxSizer(wx.VERTICAL, self, label=label)
audioGroup = guiHelper.BoxSizerHelper(self, sizer=audio)
sHelper.addItem(audioGroup)

# Translators: This is the label for a checkbox control in the Advanced settings panel.
label = _("Use WASAPI for audio output (requires restart)")
self.wasapiComboBox = cast(
nvdaControls.FeatureFlagCombo,
audioGroup.addLabeledControl(
labelText=label,
wxCtrlClass=nvdaControls.FeatureFlagCombo,
keyPath=["audio", "WASAPI"],
conf=config.conf,
),
)
self.bindHelpEvent("WASAPI", self.wasapiComboBox)

# Translators: This is the label for a group of advanced options in the
# Advanced settings panel
label = _("Debug logging")
Expand Down Expand Up @@ -4044,7 +4017,6 @@ def onSave(self):
config.conf["documentFormatting"]["reportTransparentColor"] = (
self.reportTransparentColorCheckBox.IsChecked()
)
self.wasapiComboBox.saveCurrentValueToConf()
config.conf["annotations"]["reportDetails"] = self.annotationsDetailsCheckBox.IsChecked()
config.conf["annotations"]["reportAriaDescription"] = self.ariaDescCheckBox.IsChecked()
self.brailleLiveRegionsCombo.saveCurrentValueToConf()
Expand Down
Loading

0 comments on commit 3c6ac4e

Please sign in to comment.