From 56664f4c9921de8e4c6c37c3d5a732d72724c044 Mon Sep 17 00:00:00 2001 From: Mehran Mousavi Date: Thu, 30 Oct 2025 00:26:08 +0330 Subject: [PATCH 1/3] Enhance Windows compatibility by loading 'ole32' with .dll extension fallback; update NumPy buffer handling for modern versions. --- soundcard/mediafoundation.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/soundcard/mediafoundation.py b/soundcard/mediafoundation.py index 9d9bb2e..9b210f7 100644 --- a/soundcard/mediafoundation.py +++ b/soundcard/mediafoundation.py @@ -16,8 +16,12 @@ with open(os.path.join(_package_dir, 'mediafoundation.py.h'), 'rt') as f: _ffi.cdef(f.read()) -_ole32 = _ffi.dlopen('ole32') - +try: + # Attempt to load by generic name first; fall back to the explicit DLL name if that fails. + _ole32 = _ffi.dlopen('ole32') +except OSError: + # On some Windows 11 systems with Python 3.11.x, omitting the ".dll" extension may not work. + _ole32 = _ffi.dlopen('ole32.dll') # use a custom warning subclass that is always shown, instead of once: class SoundcardRuntimeWarning(RuntimeWarning): @@ -758,7 +762,11 @@ def _record_chunk(self): self._idle_start_time = None data_ptr, nframes, flags = self._capture_buffer() if data_ptr != _ffi.NULL: - chunk = numpy.fromstring(_ffi.buffer(data_ptr, nframes*4*len(set(self.channelmap))), dtype='float32') + # Convert the raw CFFI buffer into a standard bytes object to ensure compatibility + # 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() else: raise RuntimeError('Could not create capture buffer') if flags & _ole32.AUDCLNT_BUFFERFLAGS_SILENT: From 596f92ca3fd241d413ca463c0a3e3dfa56736dc4 Mon Sep 17 00:00:00 2001 From: Mehran Mousavi Date: Sat, 1 Nov 2025 05:34:09 +0330 Subject: [PATCH 2/3] Refactor audio format assertions in mediafoundation.py to handle non-WAVEFORMATEXTENSIBLE cases gracefully, allowing WASAPI to manage conversions without crashing. --- soundcard/mediafoundation.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/soundcard/mediafoundation.py b/soundcard/mediafoundation.py index 9b210f7..4ec8ce8 100644 --- a/soundcard/mediafoundation.py +++ b/soundcard/mediafoundation.py @@ -517,17 +517,22 @@ def __init__(self, ptr, samplerate, channels, blocksize, isloopback, exclusive_m _com.check_error(hr) # It's a WAVEFORMATEXTENSIBLE with room for KSDATAFORMAT_SUBTYPE_IEEE_FLOAT: - assert ppMixFormat[0][0].Format.wFormatTag == 0xFFFE - assert ppMixFormat[0][0].Format.cbSize == 22 - - # The data format is float32: - # These values were found empirically, and I don't know why they work. - # The program crashes if these values are different - assert ppMixFormat[0][0].SubFormat.Data1 == 0x100000 - assert ppMixFormat[0][0].SubFormat.Data2 == 0x0080 - assert ppMixFormat[0][0].SubFormat.Data3 == 0xaa00 - assert [int(x) for x in ppMixFormat[0][0].SubFormat.Data4[0:4]] == [0, 56, 155, 113] - # the last four bytes seem to vary randomly + # Note: Some devices may not return 0xFFFE format, but WASAPI should handle conversion + if ppMixFormat[0][0].Format.wFormatTag == 0xFFFE: + assert ppMixFormat[0][0].Format.cbSize == 22 + + # The data format is float32: + # These values were found empirically, and I don't know why they work. + # The program crashes if these values are different + assert ppMixFormat[0][0].SubFormat.Data1 == 0x100000 + assert ppMixFormat[0][0].SubFormat.Data2 == 0x0080 + assert ppMixFormat[0][0].SubFormat.Data3 == 0xaa00 + assert [int(x) for x in ppMixFormat[0][0].SubFormat.Data4[0:4]] == [0, 56, 155, 113] + # 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 + pass channels = len(set(self.channelmap)) channelmask = 0 From 4351c5fb9c9f802315e94fe432d513c3cfa1d0ea Mon Sep 17 00:00:00 2001 From: Mehran Mousavi Date: Sat, 1 Nov 2025 05:43:52 +0330 Subject: [PATCH 3/3] Suppress data discontinuity warnings in mediafoundation.py to reduce noise for certain devices. --- soundcard/mediafoundation.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soundcard/mediafoundation.py b/soundcard/mediafoundation.py index 4ec8ce8..c5f4e9b 100644 --- a/soundcard/mediafoundation.py +++ b/soundcard/mediafoundation.py @@ -782,7 +782,9 @@ def _record_chunk(self): flags &= ~_ole32.AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY self._is_first_frame = False 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) + pass # ignore _ole32.AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR, since we don't use # time stamps. if nframes > 0: