Repository: nvaccess/nvda

Issue:
Freeze while using VSCode and OneCore
<!--
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
-->

### Steps to reproduce:

1. Open a VSCode project
1. Use the OneCore synth
2. Write and navigate a project.

### Actual behavior:

NVDA Freezes.
From comment: https://github.com/nvaccess/nvda/issues/11591#issuecomment-717955004
```
Python stack for thread 3128 (Dummy-82):
  File "synthDrivers\oneCore.pyc", line 365, in _callback
  File "nvwave.pyc", line 326, in feed
  File "nvwave.pyc", line 341, in _feedUnbuffered_handleErrors
  File "nvwave.pyc", line 369, in _feedUnbuffered
  File "nvwave.pyc", line 386, in sync
  File "winKernel.pyc", line 225, in waitForSingleObject

Python stack for thread 9300 (MainThread):
  File "nvda.pyw", line 215, in <module>
  File "core.pyc", line 550, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1050, in Notify
  File "core.pyc", line 520, in run
  File "queueHandler.pyc", line 88, in pumpAll
  File "queueHandler.pyc", line 55, in flushQueue
  File "speech\__init__.pyc", line 146, in cancelSpeech
  File "speech\manager.pyc", line 737, in cancel
  File "synthDrivers\oneCore.pyc", line 209, in cancel
  File "nvwave.pyc", line 473, in stop
  File "nvwave.pyc", line 435, in _idleUnbuffered
```

### Expected behavior:

I can successfully use VSCode for as long as needed.

### System configuration
#### NVDA installed/portable/running from source:

NVDA installed

#### NVDA version:

2020.2

#### Windows version:

Version 2004 (OS Build 19041.508)

#### Name and version of other software in use when reproducing the issue:

VSCode 1.49

#### Other information about your system:

Fairly new Windows install. I disabled all add-ons in case they were at fault--they aren't.

### Other questions

#### Does the issue still occur after restarting your computer?

Yes.

#### Have you tried any other versions of NVDA? If so, please report their behaviors.

No.

#### If addons are disabled, is your problem still occuring?

Yes.

#### Did you try to run the COM registry fixing tool in NVDA menu / tools?

No. 


Discussion:
Could you try it with the Espeak Synth selected instead of  the microsoft 
one?
 I'm sure I've seen this before somewhere, but not in the software you 
mention.
 
Sure, here's the crash with all profile synths set to Espeak. It's pretty reliably triggered with the Rust-analyzer extension running. I set out to get this report, and it took about 10 minutes with a couple small Rust projects open. Not sure what's special about this extension other than that Rust is a bit of a beast to compile, but my system is pretty beefy.

Let me know if I can provide anything else. This is unfortunately a bit of a painful issue for me to keep hitting, so happy to help track it down any way I can. Thanks.

```
IO - inputCore.InputManager.executeGesture (07:15:18.218) - winInputHook (604):
Input: kb(desktop):alt+tab
DEBUGWARNING - watchdog._watcher (07:15:23.910) - watchdog (2608):
Trying to recover from freeze, core stack:
  File "nvda.pyw", line 215, in <module>
  File "core.pyc", line 545, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1052, in Notify
  File "core.pyc", line 515, in run
  File "queueHandler.pyc", line 83, in pumpAll
  File "queueHandler.pyc", line 50, in flushQueue
  File "speech\__init__.pyc", line 146, in cancelSpeech
  File "speech\manager.pyc", line 737, in cancel
  File "synthDrivers\espeak.pyc", line 146, in cancel
  File "synthDrivers\_espeak.pyc", line 244, in stop
  File "nvwave.pyc", line 311, in stop
  File "nvwave.pyc", line 289, in _idleUnbuffered
  File "nvwave.pyc", line 326, in _close

WARNING - watchdog._watcher (07:15:38.917) - watchdog (2608):
Core frozen in stack:
  File "nvda.pyw", line 215, in <module>
  File "core.pyc", line 545, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1052, in Notify
  File "core.pyc", line 515, in run
  File "queueHandler.pyc", line 83, in pumpAll
  File "queueHandler.pyc", line 50, in flushQueue
  File "speech\__init__.pyc", line 146, in cancelSpeech
  File "speech\manager.pyc", line 737, in cancel
  File "synthDrivers\espeak.pyc", line 146, in cancel
  File "synthDrivers\_espeak.pyc", line 244, in stop
  File "nvwave.pyc", line 311, in stop
  File "nvwave.pyc", line 289, in _idleUnbuffered
  File "nvwave.pyc", line 326, in _close
```
cc: @isidorn 
This might be related to #11533.
@ndarilek please also test this try build, as portable copy.
https://ci.appveyor.com/api/buildjobs/csyh1ku00rkkpaut/artifacts/output%2Fnvda_snapshot_pr11437-20648%2C5707e0e4.exe

Please enable "process only MSAA and IA2 events" in the advanced settings on this NVDA try build. Is this issue then still reproducible?

Hmm, seems so many VS Code issues are coming up eventually,
I.E:
#11533 
#11601 
And this too.
Was away for the weekend and taking today off, but I'm now running the 
portable build with the settings tweak in place. Tomorrow I'll put it 
through its paces and report back.


Thanks.


Still experiencing the crash. Here's the new log:

```
IO - inputCore.InputManager.executeGesture (19:42:52.683) - winInputHook 
(20624):
Input: kb(desktop):downArrow
DEBUGWARNING - watchdog._watcher (19:42:56.056) - watchdog (18192):
Trying to recover from freeze. Listing stacks for Python threads:
Python stack for thread 18332 (Dummy-30):
   File "synthDrivers\oneCore.pyc", line 362, in _callback
   File "nvwave.pyc", line 194, in feed
   File "nvwave.pyc", line 219, in _feedUnbuffered
   File "nvwave.pyc", line 236, in sync
   File "winKernel.pyc", line 225, in waitForSingleObject

Python stack for thread 18192 (watchdog):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "watchdog.pyc", line 112, in _watcher
   File "watchdog.pyc", line 62, in getFormattedStacksForAllThreads

Python stack for thread 20624 (winInputHook):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "winInputHook.pyc", line 79, in hookThreadFunc

Python stack for thread 19532 (_UIAHandler.UIAHandler.MTAThread):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "_UIAHandler.pyc", line 310, in MTAThreadFunc
   File "queue.pyc", line 170, in get
   File "threading.pyc", line 296, in wait

Python stack for thread 12456 (braille._BgThread):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "braille.pyc", line 2185, in func

Python stack for thread 8284 (MainThread):
   File "nvda.pyw", line 215, in <module>
   File "core.pyc", line 545, in main
   File "wx\core.pyc", line 2134, in MainLoop
   File "gui\__init__.pyc", line 1049, in Notify
   File "core.pyc", line 515, in run
   File "queueHandler.pyc", line 88, in pumpAll
   File "queueHandler.pyc", line 55, in flushQueue
   File "speech\manager.pyc", line 669, in _handleIndex
   File "speech\commands.pyc", line 345, in run
   File "tones.pyc", line 60, in beep
   File "nvwave.pyc", line 194, in feed
   File "nvwave.pyc", line 210, in _feedUnbuffered
   File "nvwave.pyc", line 178, in open

DEBUG - synthDrivers.oneCore.SynthDriver.cancel (19:43:00.463) - 
MainThread (8284):
Cancelling
DEBUGWARNING - watchdog._watcher (19:43:00.969) - watchdog (18192):
Trying to recover from freeze. Listing stacks for Python threads:
Python stack for thread 18332 (Dummy-30):
   File "synthDrivers\oneCore.pyc", line 362, in _callback
   File "nvwave.pyc", line 194, in feed
   File "nvwave.pyc", line 219, in _feedUnbuffered
   File "nvwave.pyc", line 236, in sync
   File "winKernel.pyc", line 225, in waitForSingleObject

Python stack for thread 18192 (watchdog):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "watchdog.pyc", line 112, in _watcher
   File "watchdog.pyc", line 62, in getFormattedStacksForAllThreads

Python stack for thread 20624 (winInputHook):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "winInputHook.pyc", line 79, in hookThreadFunc

Python stack for thread 19532 (_UIAHandler.UIAHandler.MTAThread):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "_UIAHandler.pyc", line 310, in MTAThreadFunc
   File "queue.pyc", line 170, in get
   File "threading.pyc", line 296, in wait

Python stack for thread 12456 (braille._BgThread):
   File "threading.pyc", line 890, in _bootstrap
   File "threading.pyc", line 926, in _bootstrap_inner
   File "threading.pyc", line 870, in run
   File "braille.pyc", line 2185, in func

Python stack for thread 8284 (MainThread):
   File "nvda.pyw", line 215, in <module>
   File "core.pyc", line 545, in main
   File "wx\core.pyc", line 2134, in MainLoop
   File "gui\__init__.pyc", line 1049, in Notify
   File "core.pyc", line 515, in run
   File "queueHandler.pyc", line 88, in pumpAll
   File "queueHandler.pyc", line 55, in flushQueue
   File "speech\__init__.pyc", line 146, in cancelSpeech
   File "speech\manager.pyc", line 737, in cancel
   File "synthDrivers\oneCore.pyc", line 206, in cancel
   File "nvwave.pyc", line 305, in stop

```
Is there any value in me trying to duplicate this at this juncture?  if so, I'll do so in the next week or so.  I'm not sure if this is in the "we only have one user" limbo or not but I'll want Rust working at some point as well, and if this is widespread it seems like kind of a big deal.
Because there has been some work in this area recently it would be helpful to have a fresh log with a recent alpha build. Please include the build number with the log.
So the Rust Analyzer thing may be a red herring. I'm hitting this just editing some Powershell and YAML files now.

Anyhow, here's a crash with NVDA Alpha 21112,1c2598e0: 
```
DEBUG - synthDrivers.oneCore.SynthDriver._processQueue (13:38:50.589) - Dummy-5 (20768):
Calling idle on audio player
DEBUG - synthDrivers.oneCore.SynthDriver._processQueue (13:38:50.589) - Dummy-5 (20768):
Queue empty, done processing
DEBUG - autoSettingsUtils.autoSettings.AutoSettings._saveSpecificSettings (13:38:50.590) - MainThread (1320):
Saved settings for SynthDriver
DEBUG - autoSettingsUtils.autoSettings.AutoSettings._registerConfigSaveAction (13:38:50.594) - MainThread (1320):
registering pre_configSave action: <class 'synthDrivers.oneCore.SynthDriver'>
DEBUGWARNING - watchdog._watcher (13:38:51.087) - watchdog (2868):
Trying to recover from freeze. Listing stacks for Python threads:
Python stack for thread 15060 (watchdog.CancellableCallThread.execute(<CFunctionType object at 0x06ECFE40>)):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "watchdog.pyc", line 332, in run
  File "threading.pyc", line 552, in wait
  File "threading.pyc", line 296, in wait

Python stack for thread 2868 (watchdog):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "watchdog.pyc", line 127, in _watcher
  File "watchdog.pyc", line 63, in getFormattedStacksForAllThreads

Python stack for thread 3536 (winInputHook):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "winInputHook.pyc", line 79, in hookThreadFunc

Python stack for thread 18792 (_UIAHandler.UIAHandler.MTAThread):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "_UIAHandler.pyc", line 310, in MTAThreadFunc
  File "queue.pyc", line 170, in get
  File "threading.pyc", line 296, in wait

Python stack for thread 20744 (braille._BgThread):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "braille.pyc", line 2187, in func

Python stack for thread 1320 (MainThread):
  File "nvda.pyw", line 236, in <module>
  File "core.pyc", line 553, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1062, in Notify
  File "core.pyc", line 523, in run
  File "queueHandler.pyc", line 88, in pumpAll
  File "queueHandler.pyc", line 55, in flushQueue
  File "eventHandler.pyc", line 65, in _queueEventCallback
  File "eventHandler.pyc", line 215, in executeEvent
  File "eventHandler.pyc", line 228, in doPreGainFocus
  File "api.pyc", line 140, in setFocusObject
  File "appModuleHandler.pyc", line 293, in handleAppSwitch
  File "contextlib.pyc", line 119, in __exit__
  File "config\__init__.pyc", line 766, in atomicProfileSwitch
  File "config\__init__.pyc", line 410, in _handleProfileSwitch
  File "extensionPoints\__init__.pyc", line 47, in notify
  File "extensionPoints\util.pyc", line 170, in callWithSupportedKwargs
  File "synthDriverHandler.pyc", line 488, in handlePostConfigProfileSwitch
  File "synthDriverHandler.pyc", line 448, in setSynth
  File "synthDriverHandler.pyc", line 420, in getSynthInstance
  File "synthDriverHandler.pyc", line 314, in initSettings
  File "synthDriverHandler.pyc", line 323, in loadSettings
  File "synthDriverHandler.pyc", line 376, in changeVoice
  File "synthSettingsRing.pyc", line 153, in updateSupportedSettings
  File "nvwave.pyc", line 499, in __del__
  File "nvwave.pyc", line 484, in close
  File "nvwave.pyc", line 493, in _close
```

What happens in the log after this? What was the behavior of NVDA? It looks like changing config profiles was taking too long. Can you try starting nvda with a different config directory (temporarily) to ensure this isn't config specific? To do so:
- press the windows key + r
- type `nvda -c %temp%/tempNVDAconfig/`
- press enter, then use NVDA with vsCode and see if you can reproduce the problem again.

Note, NVDA will run with a fresh, default config, but your normal config will not be affected. Running NVDA as usual will return to your standard config.
I had some pretty awful luck running the alphas, so apologies for not getting updated logs.

However, I upgraded to 2020.3, and it does seem a lot more stable, even above and beyond the RCs which also behaved badly for me. I've got a couple larger Rust projects open and things seem fine now.

I don't know what happened, and am literally knocking on wood, doing anything I can to not return to the days of restarting NVDA every couple minutes. :) If I make it to the weekend with no crashes, I'll come back and close this.
Please add your current vs code version number so we have a record. If problems occur again, it will help us to confirm what has changed.
Unfortunately it's still here, and has nothing to do with Rust Analyzer. Hit it in VSCode over an SSH connection. I had to do a repair installation of Windows this morning, and just applied the H2 update, so I'm probably pristine. NVDA 20202.3:

```
IO - inputCore.InputManager.executeGesture (11:54:58.061) - winInputHook (5616):
Input: kb(desktop):downArrow
IO - inputCore.InputManager.executeGesture (11:54:58.621) - winInputHook (5616):
Input: kb(desktop):downArrow
IO - inputCore.InputManager.executeGesture (11:54:58.821) - winInputHook (5616):
Input: kb(desktop):downArrow
IO - inputCore.InputManager.executeGesture (11:54:59.365) - winInputHook (5616):
Input: kb(desktop):alt+tab
IO - inputCore.InputManager.executeGesture (11:55:00.037) - winInputHook (5616):
Input: kb(desktop):alt+shift+tab
DEBUGWARNING - watchdog._watcher (11:55:06.760) - watchdog (9712):
Trying to recover from freeze. Listing stacks for Python threads:
Python stack for thread 3128 (Dummy-82):
  File "synthDrivers\oneCore.pyc", line 365, in _callback
  File "nvwave.pyc", line 326, in feed
  File "nvwave.pyc", line 341, in _feedUnbuffered_handleErrors
  File "nvwave.pyc", line 369, in _feedUnbuffered
  File "nvwave.pyc", line 386, in sync
  File "winKernel.pyc", line 225, in waitForSingleObject

Python stack for thread 6632 (watchdog.CancellableCallThread.execute(<_FuncPtr object at 0x01434BE8>)):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "watchdog.pyc", line 317, in run
  File "threading.pyc", line 552, in wait
  File "threading.pyc", line 296, in wait

Python stack for thread 9712 (watchdog):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "watchdog.pyc", line 112, in _watcher
  File "watchdog.pyc", line 62, in getFormattedStacksForAllThreads

Python stack for thread 5616 (winInputHook):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "winInputHook.pyc", line 79, in hookThreadFunc

Python stack for thread 6728 (_UIAHandler.UIAHandler.MTAThread):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "_UIAHandler.pyc", line 310, in MTAThreadFunc
  File "queue.pyc", line 170, in get
  File "threading.pyc", line 296, in wait

Python stack for thread 7788 (braille._BgThread):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "braille.pyc", line 2187, in func

Python stack for thread 9300 (MainThread):
  File "nvda.pyw", line 215, in <module>
  File "core.pyc", line 550, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1050, in Notify
  File "core.pyc", line 520, in run
  File "queueHandler.pyc", line 88, in pumpAll
  File "queueHandler.pyc", line 55, in flushQueue
  File "speech\__init__.pyc", line 146, in cancelSpeech
  File "speech\manager.pyc", line 737, in cancel
  File "synthDrivers\oneCore.pyc", line 209, in cancel
  File "nvwave.pyc", line 473, in stop
  File "nvwave.pyc", line 435, in _idleUnbuffered

ERROR - watchdog._watcher (11:55:21.809) - watchdog (9712):
Core frozen in stack!
INFO - watchdog._watcher (11:55:21.820) - watchdog (9712):
Listing stacks for Python threads:
Python stack for thread 3128 (Dummy-82):
  File "synthDrivers\oneCore.pyc", line 365, in _callback
  File "nvwave.pyc", line 326, in feed
  File "nvwave.pyc", line 341, in _feedUnbuffered_handleErrors
  File "nvwave.pyc", line 369, in _feedUnbuffered
  File "nvwave.pyc", line 386, in sync
  File "winKernel.pyc", line 225, in waitForSingleObject

Python stack for thread 6632 (watchdog.CancellableCallThread.execute(<_FuncPtr object at 0x01434BE8>)):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "watchdog.pyc", line 317, in run
  File "threading.pyc", line 552, in wait
  File "threading.pyc", line 296, in wait

Python stack for thread 9712 (watchdog):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "watchdog.pyc", line 127, in _watcher
  File "watchdog.pyc", line 62, in getFormattedStacksForAllThreads

Python stack for thread 5616 (winInputHook):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "winInputHook.pyc", line 79, in hookThreadFunc

Python stack for thread 6728 (_UIAHandler.UIAHandler.MTAThread):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "_UIAHandler.pyc", line 310, in MTAThreadFunc
  File "queue.pyc", line 170, in get
  File "threading.pyc", line 296, in wait

Python stack for thread 7788 (braille._BgThread):
  File "threading.pyc", line 890, in _bootstrap
  File "threading.pyc", line 926, in _bootstrap_inner
  File "threading.pyc", line 870, in run
  File "braille.pyc", line 2187, in func

Python stack for thread 9300 (MainThread):
  File "nvda.pyw", line 215, in <module>
  File "core.pyc", line 550, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1050, in Notify
  File "core.pyc", line 520, in run
  File "queueHandler.pyc", line 88, in pumpAll
  File "queueHandler.pyc", line 55, in flushQueue
  File "speech\__init__.pyc", line 146, in cancelSpeech
  File "speech\manager.pyc", line 737, in cancel
  File "synthDrivers\oneCore.pyc", line 209, in cancel
  File "nvwave.pyc", line 473, in stop
  File "nvwave.pyc", line 435, in _idleUnbuffered

```

That's where the log ends. After 30 seconds or so of inactivity I restart NVDA.
This seems to be caused by a deadlock in `nvwave` the main thread blocked waiting on `_idleUnbuffered`, meanwhile `thread 3128 (Dummy-82)` is waiting in a blocking call waiting for audio data to be finished playing. The question is now, why is the playing of the audio blocked. 

Given that the main thread is trying to stop the synthesizer, perhaps there is another way to break the deadlock and cancel the `waitForSingleObject` call. 
This is just a hunch, but are you set to indicate indentation with tones?

Also, iirc you were having trouble with your bluetooth audio device and needed to get something playing silent audio.  Any chance this is audio device specific?  I could see indentation with tones + weird audio device  = weirder bugs.

But I don't know the code, so maybe I'm entirely off base.
I am using tones. The audio device is standard and shouldn't be an 
issue--the problem I had was after the card, in the sound bar itself.


I'll disable tones and report back any changes next week. I'm also using 
beeps for capitalization, so maybe there's some weird interaction 
between tone generation, One Core voices and something VSCode/Electron 
is doing.


Still happening. Only editing HTML and Hugo templates today, so no Rust in sight. I wouldn't know to blame VSCode if this didn't happen all last weekend, when I never worked with VSCode, and today when I did. :(
Looking at the [stacks for the different threads](https://github.com/nvaccess/nvda/issues/11591#issuecomment-714629177), I think this can be [blamed on a deadlock between threads](https://github.com/nvaccess/nvda/issues/11591#issuecomment-715268411), likely specific to onecore. I doubt it is related to VS Code at all. I'm going to mutate this issue to make it more generic. If the problem still occurs after we fix this deadlock I think it would be best to open a new issue.

Stacks to note, from [log](https://github.com/nvaccess/nvda/issues/11591#issuecomment-714629177):
```
Python stack for thread 3128 (Dummy-82):
  File "synthDrivers\oneCore.pyc", line 365, in _callback
  File "nvwave.pyc", line 326, in feed
  File "nvwave.pyc", line 341, in _feedUnbuffered_handleErrors
  File "nvwave.pyc", line 369, in _feedUnbuffered
  File "nvwave.pyc", line 386, in sync
  File "winKernel.pyc", line 225, in waitForSingleObject

Python stack for thread 9300 (MainThread):
  File "nvda.pyw", line 215, in <module>
  File "core.pyc", line 550, in main
  File "wx\core.pyc", line 2134, in MainLoop
  File "gui\__init__.pyc", line 1050, in Notify
  File "core.pyc", line 520, in run
  File "queueHandler.pyc", line 88, in pumpAll
  File "queueHandler.pyc", line 55, in flushQueue
  File "speech\__init__.pyc", line 146, in cancelSpeech
  File "speech\manager.pyc", line 737, in cancel
  File "synthDrivers\oneCore.pyc", line 209, in cancel
  File "nvwave.pyc", line 473, in stop
  File "nvwave.pyc", line 435, in _idleUnbuffered
```
Not sure if this is useful data or just noise, but figured I'd include it anyway.

In addition to the VSCode freeze, I'd experience an almost daily slowdown of my system, to the point where the only remedy was to hard reset. I couldn't narrow it down to any specific behavior on my end, nor did anything seem to reliably fix it. Sometimes killing Firefox or VSCode would do it, others not. Debugging the issue was made significantly more difficult by me not being able to use my system to do said debugging.

Out of desperation, I've switched all of my config profiles to use Espeak. The daily slowdowns are gone, and have been for the past few days.

There are still occasional VSCode freezes, and I'm working to get a log. But it does seem like there should be some major performance profiling work done around the One Core TTS code. If anyone has tips on how to recover a system so bogged down that NVDA can't even be restarted reliably, and where restarting it doesn't seem to always get performance back, I'm willing to wade back into that mess and try getting more useful data. :)
@ndarilek I want to keep this issue focused on Freeze. The slow down you are describing should be created as a new issue, however you'll need to dig a little deeper on the investigation side. You may wish to discuss this on the mailing lists to get some ides on how to investigate. I'm going to mark these comments as off-topic.

Resolving patch:
diff --git a/source/nvwave.py b/source/nvwave.py
--- a/source/nvwave.py
+++ b/source/nvwave.py
@@ -122,6 +122,19 @@ def _winmm_errcheck(res, func, args):
 def _isDebugForNvWave():
 	return config.conf["debugLog"]["nvwave"]
 
+
+def safe_winmm_waveOutReset(_waveout) -> bool:
+	""" Wrap waveOutReset in try block and log exceptions,
+	it seems to fail randomly on some systems.
+	@return True on success.
+	"""
+	try:
+		winmm.waveOutReset(_waveout)
+		return True
+	except WindowsError:
+		log.debug("Exception while resetting wave out device.", exc_info=True)
+		return False
+
 class WavePlayer(garbageHandler.TrackedObject):
 	"""Synchronously play a stream of audio.
 	To use, construct an instance and feed it waveform audio using L{feed}.
@@ -137,6 +150,16 @@ class WavePlayer(garbageHandler.TrackedObject):
 	#: A lock to prevent WaveOut* functions from being called simultaneously,
 	# as this can cause problems even if they are for different HWAVEOUTs.
 	_global_waveout_lock = threading.RLock()
+
+	#: A signal handle, used by the winmm device to signal whenever the state of the waveform buffer changes.
+	# Use WaitForSingleObject or WaitForMultipleObjects to wait for the event.
+	# When the event is signaled, you can get the current state of the waveform buffer by checking the
+	# dwFlags member of the WAVEHDR structure.
+	_waveout_event: HANDLE = None
+
+	#: The number of milliseconds that we should wait on the _waveout_event to be signaled. This
+	# is a fallback, when audio is cancelled (via self.stop) the signal is triggered.
+	_waveout_event_wait_ms = 100
 	_audioDucker=None
 	#: Used to allow the device to temporarily be changed and return
 	# to the preferred device when it becomes available
@@ -362,11 +385,14 @@ def _feedUnbuffered(self, data, onDone=None):
 		whdr.dwBufferLength = len(data)
 		with self._lock:
 			with self._waveout_lock:
-				self.open()  # required of close on idle see _idleUnbuffered
-				with self._global_waveout_lock:
-					winmm.waveOutPrepareHeader(self._waveout, LPWAVEHDR(whdr), sizeof(WAVEHDR))
-					winmm.waveOutWrite(self._waveout, LPWAVEHDR(whdr), sizeof(WAVEHDR))
-			self.sync()
+				self.open()  # required if close on idle see _idleUnbuffered
+				if self._prevOnDone is not self.STOPPING:
+					# If we are stopping, waveOutReset has already been called.
+					# Pushing more data confuses the state of nvWave
+					with self._global_waveout_lock:
+						winmm.waveOutPrepareHeader(self._waveout, LPWAVEHDR(whdr), sizeof(WAVEHDR))
+						winmm.waveOutWrite(self._waveout, LPWAVEHDR(whdr), sizeof(WAVEHDR))
+			self.sync()  # sync must still be called even if stopping, so that waveOutUnprepareHeader can be called
 			self._prev_whdr = whdr
 			# Don't call onDone if stop was called,
 			# as this chunk has been truncated in that case.
@@ -377,19 +403,28 @@ def sync(self):
 		"""Synchronise with playback.
 		This method blocks until the previously fed chunk of audio has finished playing.
 		It is called automatically by L{feed}, so usually need not be called directly by the user.
+
+		Note: it must be possible to call stop concurrently with sync, sync should be considered to be blocking
+		the synth driver thread most of the time (ie sync waiting for the last pushed block of audio to
+		complete, via the 'winKernal.waitForSingleObject' mechanism)
 		"""
 		with self._lock:
 			if not self._prev_whdr:
 				return
 			assert self._waveout, "waveOut None before wait"
-			while not (self._prev_whdr.dwFlags & WHDR_DONE):
-				winKernel.waitForSingleObject(self._waveout_event, winKernel.INFINITE)
+			while (
+				not (self._prev_whdr.dwFlags & WHDR_DONE)
+				# In case some sound driver can not keep track of the whdr from previous buffers, ensure that
+				# 'waitForSingleObject' can not block for long, and exit this loop if stopping.
+				and self._prevOnDone is not self.STOPPING
+			):
+				winKernel.waitForSingleObject(self._waveout_event, self._waveout_event_wait_ms)
 			with self._waveout_lock:
 				assert self._waveout, "waveOut None after wait"
 				with self._global_waveout_lock:
 					winmm.waveOutUnprepareHeader(self._waveout, LPWAVEHDR(self._prev_whdr), sizeof(WAVEHDR))
 			self._prev_whdr = None
-			if self._prevOnDone is not None and self._prevOnDone is not self.STOPPING:
+			if self._prevOnDone not in (None, self.STOPPING):
 				try:
 					self._prevOnDone()
 				except:
@@ -461,14 +496,13 @@ def stop(self):
 			if not self._waveout:
 				return
 			self._prevOnDone = self.STOPPING
-			try:
-				with self._global_waveout_lock:
-					# Pausing first seems to make waveOutReset respond faster on some systems.
-					winmm.waveOutPause(self._waveout)
-					winmm.waveOutReset(self._waveout)
-			except WindowsError:
-				# waveOutReset seems to fail randomly on some systems.
-				pass
+			with self._global_waveout_lock:
+				# Pausing first seems to make waveOutReset respond faster on some systems.
+				winmm.waveOutPause(self._waveout)
+				safe_winmm_waveOutReset(self._waveout)
+				# The documentation is not explicit about whether waveOutReset will signal the event,
+				# so trigger it to be sure that sync isn't blocking on 'waitForSingleObject'.
+				windll.kernel32.SetEvent(self._waveout_event)
 		# Unprepare the previous buffer and close the output device if appropriate.
 		self._idleUnbuffered()
 		self._prevOnDone = None


Test patch: