Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-sounddevice for openSUSE:Factory checked in at 2025-11-10 19:20:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-sounddevice (Old) and /work/SRC/openSUSE:Factory/.python-sounddevice.new.1980 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-sounddevice" Mon Nov 10 19:20:30 2025 rev:17 rq:1316848 version:0.5.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-sounddevice/python-sounddevice.changes 2025-05-30 17:26:30.778200522 +0200 +++ /work/SRC/openSUSE:Factory/.python-sounddevice.new.1980/python-sounddevice.changes 2025-11-10 19:20:32.284390078 +0100 @@ -1,0 +2,6 @@ +Mon Nov 10 09:11:40 UTC 2025 - Dirk Müller <[email protected]> + +- update to 0.5.3: + * add explicit_sample_format parameter to WasapiSettings + +------------------------------------------------------------------- Old: ---- sounddevice-0.5.2.tar.gz New: ---- sounddevice-0.5.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-sounddevice.spec ++++++ --- /var/tmp/diff_new_pack.oRNJKb/_old 2025-11-10 19:20:33.052422322 +0100 +++ /var/tmp/diff_new_pack.oRNJKb/_new 2025-11-10 19:20:33.052422322 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-sounddevice # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2025 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-sounddevice -Version: 0.5.2 +Version: 0.5.3 Release: 0 Summary: Module to play and record sound with Python License: MIT ++++++ sounddevice-0.5.2.tar.gz -> sounddevice-0.5.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/NEWS.rst new/sounddevice-0.5.3/NEWS.rst --- old/sounddevice-0.5.2/NEWS.rst 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/NEWS.rst 2025-10-19 15:23:02.000000000 +0200 @@ -1,3 +1,6 @@ +0.5.3 (2025-10-19): + * add ``explicit_sample_format`` parameter to `WasapiSettings` + 0.5.2 (2025-05-16): * Better error if frames/channels are non-integers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/PKG-INFO new/sounddevice-0.5.3/PKG-INFO --- old/sounddevice-0.5.2/PKG-INFO 2025-05-16 20:11:53.960229400 +0200 +++ new/sounddevice-0.5.3/PKG-INFO 2025-10-19 15:23:27.825566500 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: sounddevice -Version: 0.5.2 +Version: 0.5.3 Summary: Play and Record Sound with Python Home-page: http://python-sounddevice.readthedocs.io/ Author: Matthias Geier diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/doc/conf.py new/sounddevice-0.5.3/doc/conf.py --- old/sounddevice-0.5.2/doc/conf.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/doc/conf.py 2025-10-19 15:23:02.000000000 +0200 @@ -35,7 +35,7 @@ intersphinx_mapping = { 'python': ('https://docs.python.org/3/', None), - 'numpy': ('https://docs.scipy.org/doc/numpy/', None), + 'numpy': ('https://numpy.org/doc/stable/', None), } master_doc = 'index' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/play_file.py new/sounddevice-0.5.3/examples/play_file.py --- old/sounddevice-0.5.2/examples/play_file.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/play_file.py 2025-10-19 15:23:02.000000000 +0200 @@ -80,6 +80,6 @@ with stream: event.wait() # Wait until playback is finished except KeyboardInterrupt: - parser.exit('\nInterrupted by user') + parser.exit(1, '\nInterrupted by user') except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/play_long_file.py new/sounddevice-0.5.3/examples/play_long_file.py --- old/sounddevice-0.5.2/examples/play_long_file.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/play_long_file.py 2025-10-19 15:23:02.000000000 +0200 @@ -101,9 +101,9 @@ q.put(data, timeout=timeout) event.wait() # Wait until playback is finished except KeyboardInterrupt: - parser.exit('\nInterrupted by user') + parser.exit(1, '\nInterrupted by user') except queue.Full: # A timeout occurred, i.e. there was an error in the callback parser.exit(1) except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/play_long_file_raw.py new/sounddevice-0.5.3/examples/play_long_file_raw.py --- old/sounddevice-0.5.2/examples/play_long_file_raw.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/play_long_file_raw.py 2025-10-19 15:23:02.000000000 +0200 @@ -92,9 +92,9 @@ q.put(data, timeout=timeout) event.wait() # Wait until playback is finished except KeyboardInterrupt: - parser.exit('\nInterrupted by user') + parser.exit(1, '\nInterrupted by user') except queue.Full: # A timeout occurred, i.e. there was an error in the callback parser.exit(1) except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/play_sine.py new/sounddevice-0.5.3/examples/play_sine.py --- old/sounddevice-0.5.2/examples/play_sine.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/play_sine.py 2025-10-19 15:23:02.000000000 +0200 @@ -59,6 +59,6 @@ print('#' * 80) input() except KeyboardInterrupt: - parser.exit('') + parser.exit(1, '\nInterrupted by user') except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/play_stream.py new/sounddevice-0.5.3/examples/play_stream.py --- old/sounddevice-0.5.2/examples/play_stream.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/play_stream.py 2025-10-19 15:23:02.000000000 +0200 @@ -61,16 +61,16 @@ info = ffmpeg.probe(args.url) except ffmpeg.Error as e: sys.stderr.buffer.write(e.stderr) - parser.exit(e) + parser.exit(1, str(e)) streams = info.get('streams', []) if len(streams) != 1: - parser.exit('There must be exactly one stream available') + parser.exit(1, 'There must be exactly one stream available') stream = streams[0] if stream.get('codec_type') != 'audio': - parser.exit('The stream must be an audio stream') + parser.exit(1, 'The stream must be an audio stream') channels = stream['channels'] samplerate = float(stream['sample_rate']) @@ -117,9 +117,9 @@ while True: q.put(process.stdout.read(read_size), timeout=timeout) except KeyboardInterrupt: - parser.exit('\nInterrupted by user') + parser.exit(1, '\nInterrupted by user') except queue.Full: # A timeout occurred, i.e. there was an error in the callback parser.exit(1) except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/plot_input.py new/sounddevice-0.5.3/examples/plot_input.py --- old/sounddevice-0.5.2/examples/plot_input.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/plot_input.py 2025-10-19 15:23:02.000000000 +0200 @@ -116,4 +116,4 @@ with stream: plt.show() except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/rec_gui.py new/sounddevice-0.5.3/examples/rec_gui.py --- old/sounddevice-0.5.2/examples/rec_gui.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/rec_gui.py 2025-10-19 15:23:02.000000000 +0200 @@ -12,7 +12,6 @@ """ import contextlib import queue -import sys import tempfile import threading import tkinter as tk diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/rec_unlimited.py new/sounddevice-0.5.3/examples/rec_unlimited.py --- old/sounddevice-0.5.2/examples/rec_unlimited.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/rec_unlimited.py 2025-10-19 15:23:02.000000000 +0200 @@ -83,4 +83,4 @@ print('\nRecording finished: ' + repr(args.filename)) parser.exit(0) except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/spectrogram.py new/sounddevice-0.5.3/examples/spectrogram.py --- old/sounddevice-0.5.2/examples/spectrogram.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/spectrogram.py 2025-10-19 15:23:02.000000000 +0200 @@ -106,6 +106,6 @@ '\x1b[0m', sep='') break except KeyboardInterrupt: - parser.exit('Interrupted by user') + parser.exit(1, '\nInterrupted by user') except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/examples/wire.py new/sounddevice-0.5.3/examples/wire.py --- old/sounddevice-0.5.2/examples/wire.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/examples/wire.py 2025-10-19 15:23:02.000000000 +0200 @@ -63,6 +63,6 @@ print('#' * 80) input() except KeyboardInterrupt: - parser.exit('') + parser.exit(1, '\nInterrupted by user') except Exception as e: - parser.exit(type(e).__name__ + ': ' + str(e)) + parser.exit(1, type(e).__name__ + ': ' + str(e)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/sounddevice.egg-info/PKG-INFO new/sounddevice-0.5.3/sounddevice.egg-info/PKG-INFO --- old/sounddevice-0.5.2/sounddevice.egg-info/PKG-INFO 2025-05-16 20:11:53.000000000 +0200 +++ new/sounddevice-0.5.3/sounddevice.egg-info/PKG-INFO 2025-10-19 15:23:27.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: sounddevice -Version: 0.5.2 +Version: 0.5.3 Summary: Play and Record Sound with Python Home-page: http://python-sounddevice.readthedocs.io/ Author: Matthias Geier diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/sounddevice.py new/sounddevice-0.5.3/sounddevice.py --- old/sounddevice-0.5.2/sounddevice.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/sounddevice.py 2025-10-19 15:23:02.000000000 +0200 @@ -48,7 +48,7 @@ https://python-sounddevice.readthedocs.io/ """ -__version__ = '0.5.2' +__version__ = '0.5.3' import atexit as _atexit import os as _os @@ -829,11 +829,11 @@ extra_settings, samplerate) self._device = parameters.device self._channels = parameters.channelCount + iparameters = _ffi.NULL + oparameters = _ffi.NULL if kind == 'input': iparameters = parameters - oparameters = _ffi.NULL elif kind == 'output': - iparameters = _ffi.NULL oparameters = parameters ffi_callback = _ffi.callback('PaStreamCallback', error=_lib.paAbort) @@ -1165,45 +1165,8 @@ _check(err, 'Error closing stream') -class RawInputStream(_StreamBase): - """Raw stream for recording only. See __init__() and RawStream.""" - - def __init__(self, samplerate=None, blocksize=None, - device=None, channels=None, dtype=None, latency=None, - extra_settings=None, callback=None, finished_callback=None, - clip_off=None, dither_off=None, never_drop_input=None, - prime_output_buffers_using_stream_callback=None): - """PortAudio input stream (using buffer objects). - - This is the same as `InputStream`, except that the *callback* - function and `~RawStream.read()` work on plain Python buffer - objects instead of on NumPy arrays. - NumPy is not necessary for using this. - - Parameters - ---------- - dtype : str - See `RawStream`. - callback : callable - User-supplied function to consume audio data in response to - requests from an active stream. - The callback must have this signature: - - .. code-block:: text - - callback(indata: buffer, frames: int, - time: CData, status: CallbackFlags) -> None - - The arguments are the same as in the *callback* parameter of - `RawStream`, except that *outdata* is missing. - - See Also - -------- - RawStream, Stream - - """ - _StreamBase.__init__(self, kind='input', wrap_callback='buffer', - **_remove_self(locals())) +class _InputStreamBase(_StreamBase): + """Base class for input stream classes.""" @property def read_available(self): @@ -1215,7 +1178,7 @@ """ return _check(_lib.Pa_GetStreamReadAvailable(self._ptr)) - def read(self, frames): + def _raw_read(self, frames): """Read samples from the stream into a buffer. This is the same as `Stream.read()`, except that it returns @@ -1251,19 +1214,19 @@ return _ffi.buffer(data), overflowed -class RawOutputStream(_StreamBase): - """Raw stream for playback only. See __init__() and RawStream.""" +class RawInputStream(_InputStreamBase): + """Raw stream for recording only. See __init__() and RawStream.""" def __init__(self, samplerate=None, blocksize=None, device=None, channels=None, dtype=None, latency=None, extra_settings=None, callback=None, finished_callback=None, clip_off=None, dither_off=None, never_drop_input=None, prime_output_buffers_using_stream_callback=None): - """PortAudio output stream (using buffer objects). + """PortAudio input stream (using buffer objects). - This is the same as `OutputStream`, except that the *callback* - function and `~RawStream.write()` work on plain Python - buffer objects instead of on NumPy arrays. + This is the same as `InputStream`, except that the *callback* + function and `~RawStream.read()` work on plain Python buffer + objects instead of on NumPy arrays. NumPy is not necessary for using this. Parameters @@ -1271,26 +1234,32 @@ dtype : str See `RawStream`. callback : callable - User-supplied function to generate audio data in response to + User-supplied function to consume audio data in response to requests from an active stream. The callback must have this signature: .. code-block:: text - callback(outdata: buffer, frames: int, + callback(indata: buffer, frames: int, time: CData, status: CallbackFlags) -> None The arguments are the same as in the *callback* parameter of - `RawStream`, except that *indata* is missing. + `RawStream`, except that *outdata* is missing. See Also -------- RawStream, Stream """ - _StreamBase.__init__(self, kind='output', wrap_callback='buffer', + _StreamBase.__init__(self, kind='input', wrap_callback='buffer', **_remove_self(locals())) + read = _InputStreamBase._raw_read + + +class _OutputStreamBase(_StreamBase): + """Base class for output stream classes.""" + @property def write_available(self): """The number of frames that can be written without waiting. @@ -1301,7 +1270,7 @@ """ return _check(_lib.Pa_GetStreamWriteAvailable(self._ptr)) - def write(self, data): + def _raw_write(self, data): """Write samples to the stream. This is the same as `Stream.write()`, except that it expects @@ -1348,6 +1317,49 @@ return underflowed +class RawOutputStream(_OutputStreamBase): + """Raw stream for playback only. See __init__() and RawStream.""" + + def __init__(self, samplerate=None, blocksize=None, + device=None, channels=None, dtype=None, latency=None, + extra_settings=None, callback=None, finished_callback=None, + clip_off=None, dither_off=None, never_drop_input=None, + prime_output_buffers_using_stream_callback=None): + """PortAudio output stream (using buffer objects). + + This is the same as `OutputStream`, except that the *callback* + function and `~RawStream.write()` work on plain Python + buffer objects instead of on NumPy arrays. + NumPy is not necessary for using this. + + Parameters + ---------- + dtype : str + See `RawStream`. + callback : callable + User-supplied function to generate audio data in response to + requests from an active stream. + The callback must have this signature: + + .. code-block:: text + + callback(outdata: buffer, frames: int, + time: CData, status: CallbackFlags) -> None + + The arguments are the same as in the *callback* parameter of + `RawStream`, except that *indata* is missing. + + See Also + -------- + RawStream, Stream + + """ + _StreamBase.__init__(self, kind='output', wrap_callback='buffer', + **_remove_self(locals())) + + write = _OutputStreamBase._raw_write + + class RawStream(RawInputStream, RawOutputStream): """Raw stream for playback and recording. See __init__().""" @@ -1402,7 +1414,7 @@ **_remove_self(locals())) -class InputStream(RawInputStream): +class InputStream(_InputStreamBase): """Stream for input only. See __init__() and Stream.""" def __init__(self, samplerate=None, blocksize=None, @@ -1472,12 +1484,12 @@ """ dtype, _ = _split(self._dtype) channels, _ = _split(self._channels) - data, overflowed = RawInputStream.read(self, frames) + data, overflowed = _InputStreamBase._raw_read(self, frames) data = _array(data, channels, dtype) return data, overflowed -class OutputStream(RawOutputStream): +class OutputStream(_OutputStreamBase): """Stream for output only. See __init__() and Stream.""" def __init__(self, samplerate=None, blocksize=None, @@ -1562,7 +1574,7 @@ data.dtype.name, dtype)) if not data.flags.c_contiguous: raise TypeError('data must be C-contiguous') - return RawOutputStream.write(self, data) + return _OutputStreamBase._raw_write(self, data) class Stream(InputStream, OutputStream): @@ -2104,30 +2116,24 @@ device = None, None """Index or query string of default input/output device. - See the *device* argument of `Stream`. - If not overwritten, this is queried from PortAudio. See Also -------- - `query_devices()` + `default`, `query_devices()`, the *device* argument of `Stream` """ channels = _default_channels = None, None """Default number of input/output channels. - See the *channels* argument of `Stream`. - See Also -------- - `query_devices()` + `default`, `query_devices()`, the *channels* argument of `Stream` """ dtype = _default_dtype = 'float32', 'float32' """Default data type used for input/output samples. - See the *dtype* argument of `Stream`. - The types ``'float32'``, ``'int32'``, ``'int16'``, ``'int8'`` and ``'uint8'`` can be used for all streams and functions. Additionally, `play()`, `rec()` and `playrec()` support @@ -2136,6 +2142,10 @@ `RawStream` support ``'int24'`` (packed 24 bit format, which is *not* supported in NumPy!). + See Also + -------- + `default`, `numpy:numpy.dtype`, the *dtype* argument of `Stream` + """ latency = _default_latency = 'high', 'high' """See the *latency* argument of `Stream`.""" @@ -2152,7 +2162,7 @@ See Also -------- - `query_devices()` + `default`, `query_devices()` """ blocksize = _lib.paFramesPerBufferUnspecified @@ -2436,7 +2446,7 @@ class WasapiSettings: - def __init__(self, exclusive=False, auto_convert=False): + def __init__(self, exclusive=False, auto_convert=False, explicit_sample_format=False): """WASAPI-specific input/output settings. Objects of this class can be used as *extra_settings* argument @@ -2458,6 +2468,13 @@ system mixer sample rate. This only applies in *shared mode* and has no effect when *exclusive* is set to ``True``. + explicit_sample_format : bool + Force explicit sample format and do not allow PortAudio to + select suitable working format. API will fail if provided + sample format is not supported by audio hardware in Exclusive + mode or system mixer in Shared mode. This is required for + accurate native format detection. + Examples -------- Setting exclusive mode when calling `play()`: @@ -2475,8 +2492,10 @@ flags = 0x0 if exclusive: flags |= _lib.paWinWasapiExclusive - elif auto_convert: + if auto_convert: flags |= _lib.paWinWasapiAutoConvert + if explicit_sample_format: + flags |= _lib.paWinWasapiExplicitSampleFormat self._streaminfo = _ffi.new('PaWasapiStreamInfo*', dict( size=_ffi.sizeof('PaWasapiStreamInfo'), hostApiType=_lib.paWASAPI, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sounddevice-0.5.2/sounddevice_build.py new/sounddevice-0.5.3/sounddevice_build.py --- old/sounddevice-0.5.2/sounddevice_build.py 2025-05-16 20:11:24.000000000 +0200 +++ new/sounddevice-0.5.3/sounddevice_build.py 2025-10-19 15:23:02.000000000 +0200 @@ -255,6 +255,7 @@ paWinWasapiUseChannelMask = 4, paWinWasapiPolling = 8, paWinWasapiThreadPriority = 16, + paWinWasapiExplicitSampleFormat = 32, paWinWasapiAutoConvert = 64 } PaWasapiFlags;
