-
Notifications
You must be signed in to change notification settings - Fork 76
Fix Windows ole32 loading and NumPy compatibility in MediaFoundation backend #193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…fallback; update NumPy buffer handling for modern versions.
…WAVEFORMATEXTENSIBLE cases gracefully, allowing WASAPI to manage conversions without crashing.
…noise for certain devices.
bastibe
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for your pull request, and debugging all of these issues. What sound card are you using that triggers these behaviors?
| # with modern NumPy versions (fromstring binary mode was removed). Using frombuffer | ||
| # on bytes plus .copy() guarantees a writable float32 array for downstream processing. | ||
| buf = bytes(_ffi.buffer(data_ptr, nframes * 4 * len(set(self.channelmap)))) | ||
| chunk = numpy.frombuffer(buf, dtype=numpy.float32).copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I remember correctly, frombuffer is supposed to use buffer objects directly, so we can skip the bytes conversion (which also incurs another unnecessary copy).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review. You are right that in principle numpy.frombuffer can consume buffer objects directly without converting to bytes. I initially tried that approach, but in practice it produced corrupted audio on Windows 11 with modern NumPy (≥2.x). The recorded stream would play back with a “robotic” or distorted sound.
After some investigation, the root cause was that the raw ffi.buffer object was not being interpreted consistently as a contiguous float32 array. Converting it explicitly to bytes ensured that NumPy saw a well‑defined, contiguous block of memory. Adding .copy() then guaranteed that the resulting array was writable, which is required because the downstream code modifies the buffer (chunk[:] = 0).
So the combination of bytes(...) + frombuffer(...).copy() was the minimal change that both restored correct audio playback and maintained compatibility with the updated NumPy API. Without the conversion step, the audio artifacts reappeared.
If you prefer to avoid the extra copy for performance reasons, we could explore alternatives (e.g. ensuring the ffi.buffer is exposed as a writable, contiguous memoryview), but the current patch was the most reliable fix we found to resolve the distortion issue across environments.
Audio Adapter:
Intel 5 Series/34x0 Chipset PCH - High Definition Audio Controller [B3]
Audio Controller Hardware ID: PCI\VEN_8086&DEV_3B56&SUBSYS_1520103C&REV_06
Windows 11 Pro 25H2 / OS Build : 26200.7019
| # the last four bytes seem to vary randomly | ||
| else: | ||
| # Device doesn't return WAVEFORMATEXTENSIBLE, but WASAPI will handle conversion | ||
| # Just skip the assertions and let WASAPI convert |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks dubious to me. We probably should at least issue a warning that we're skipping the format checking here.
Unless the whole formatting checks are unnecessary, in which case we can always skip them. But I don't know enough about this API to make that decision, really. Do you know more?
| if flags & _ole32.AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY: | ||
| warnings.warn("data discontinuity in recording", SoundcardRuntimeWarning) | ||
| # Suppressed: data discontinuity warnings are noisy for some devices | ||
| # warnings.warn("data discontinuity in recording", SoundcardRuntimeWarning) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's a data discontinuity, the user must be warned. It means they're losing data, and it usually means they need to reduce their processing or increase buffer sizes. We can't skip this.
Fix Windows
ole32loading and NumPy compatibility in MediaFoundation backendDescription
This pull request introduces two critical fixes to the Windows MediaFoundation backend of soundcard:
Robust
ole32loading_ffi.dlopen('ole32')could fail on certain Windows 11 systems with Python 3.11+, where the generic library name was not resolved correctly.ole32first and falls back toole32.dllif necessary, ensuring consistent behavior across Windows environments.NumPy API compatibility
numpy.fromstring(binary mode) withnumpy.frombuffer(...).copy().float32array for downstream audio processing.Impact
ole32loading previously failed.Notes