WASAPI: Recover after the device is reconfigured or leaves exclusive mode. (#15783)
Fixes #15758. Fixes #15775.
Summary of the issue:
When another application takes exclusive control of NVDA's audio output device, NVDA can no longer speak. There's nothing we can do about this and it's reasonable that we log errors in this case. However, previously, when the other application released exclusive control of the device, NVDA would still fail to speak. Similar behaviour has been observed when the sampling rate is changed with certain audio drivers.
Description of user facing changes
NVDA now resumes audio if the configuration of the output device changes or another application releases exclusive control of the device.
Description of development approach
In WasapiPlayer::feed, as well as attempting reopen for AUDCLNT_E_DEVICE_INVALIDATED, reopen also for AUDCLNT_E_NOT_INITIALIZED. This handles the case that we tried to reopen previously due to an invalidated device and failed.
In WasapiPlayer::stop, if either of these error codes is returned by WASAPI, just ignore them. The device is clearly stopped anyway. Previously, these errors got propagated to Python, which broke SpeechManager and stopped speech from being attempted at all. That in turn meant that feed was never called and thus reopen was never attempted.
In WasapiPlayer::feed's reopenUsingNewDev, the hr result code was being accidentally shadowed and thus never returned to the caller. This meant that reopen failures were never raised as exceptions and thus never logged. This has now been fixed.
Previously, due to an oversight, we weren't setting the ctypes restype for wasPlay_open. This meant that errors from this function were silently ignored. This is really a bit of drive-by cleanup and isn't necessary to fix this bug, but should make debugging easier if we hit problems here in future.