Hello community,
here is the log from the commit of package python-pulsectl for openSUSE:Factory
checked in at 2020-01-20 22:56:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pulsectl (Old)
and /work/SRC/openSUSE:Factory/.python-pulsectl.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pulsectl"
Mon Jan 20 22:56:28 2020 rev:4 rq:765852 version:20.1.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pulsectl/python-pulsectl.changes
2019-06-06 18:17:20.512685684 +0200
+++
/work/SRC/openSUSE:Factory/.python-pulsectl.new.26092/python-pulsectl.changes
2020-01-20 22:56:31.075368286 +0100
@@ -1,0 +2,7 @@
+Mon Jan 20 13:59:09 UTC 2020 - Ondřej Súkup <[email protected]>
+
+- update to 20.1.2
+ * add pulse.play_sample() - server-side stored sample playback
+ * Add pulse.get_peak_sample() func for getting volume peak within timespan
+
+-------------------------------------------------------------------
Old:
----
pulsectl-18.12.5.tar.gz
New:
----
pulsectl-20.1.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pulsectl.spec ++++++
--- /var/tmp/diff_new_pack.UA1UUY/_old 2020-01-20 22:56:32.411368800 +0100
+++ /var/tmp/diff_new_pack.UA1UUY/_new 2020-01-20 22:56:32.459368818 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-pulsectl
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%bcond_without test
Name: python-pulsectl
-Version: 18.12.5
+Version: 20.1.2
Release: 0
Summary: Python high-level interface and ctypes-based bindings for
PulseAudio (libpulse)
License: MIT
++++++ pulsectl-18.12.5.tar.gz -> pulsectl-20.1.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/CHANGES.rst
new/pulsectl-20.1.2/CHANGES.rst
--- old/pulsectl-18.12.5/CHANGES.rst 2018-12-10 18:48:02.000000000 +0100
+++ new/pulsectl-20.1.2/CHANGES.rst 2020-01-11 17:20:39.000000000 +0100
@@ -8,13 +8,19 @@
Each entry is a package version which change first appears in, followed by
description of the change itself.
-Last synced/updated: 18.12.2
+Last synced/updated: 20.1.2
---------------------------------------------------------------------------
+- 20.1.1: Add pulse.play_sample() - server-side stored sample playback [#36].
+
+ Loading is not implemented, would suggest something like libcanberra for
that.
+
+- 19.9.1: Add pulse.get_peak_sample() func for getting volume peak within
timespan [#33].
+
- 18.10.5: pulse.connect() can now be used to reconnect to same server.
-- 17.12.2: Use pa_card_profile_info2 / profiles2 introspection API.
+- 17.12.2: Use pa_card_profile_info2 / profiles2 introspection API [#19].
Only adds one "available" property to PulseCardProfileInfo.
Requires pulseaudio/libpulse 5.0+.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/PKG-INFO
new/pulsectl-20.1.2/PKG-INFO
--- old/pulsectl-18.12.5/PKG-INFO 2018-12-18 23:49:04.000000000 +0100
+++ new/pulsectl-20.1.2/PKG-INFO 2020-01-11 17:24:10.035188400 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pulsectl
-Version: 18.12.5
+Version: 20.1.2
Summary: Python high-level interface and ctypes-based bindings for PulseAudio
(libpulse)
Home-page: http://github.com/mk-fg/python-pulse-control
Author: George Filipkin, Mike Kazantsev
@@ -323,11 +323,14 @@
issues with pulseaudio (or its daemon.conf) and underlying
dependencies.
There are no "expected" test case failures.
+ All tests can run for up to 10 seconds currently (v19.9.6), due to some
+ involving playback (using paplay from /dev/urandom) being
time-sensitive.
+
Changelog and versioning scheme
```````````````````````````````
- This package uses one-version-per commit scheme (updated by pre-commit
hook)
+ This package uses one-version-per-commit scheme (updated by pre-commit
hook)
and pretty much one release per git commit, unless more immediate
follow-up
commits are planned or too lazy to run ``py setup.py sdist bdist_wheel
upload``
for some trivial README typo fix.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/README.rst
new/pulsectl-20.1.2/README.rst
--- old/pulsectl-18.12.5/README.rst 2018-12-18 23:46:49.000000000 +0100
+++ new/pulsectl-20.1.2/README.rst 2019-09-24 01:03:43.000000000 +0200
@@ -315,11 +315,14 @@
issues with pulseaudio (or its daemon.conf) and underlying dependencies.
There are no "expected" test case failures.
+All tests can run for up to 10 seconds currently (v19.9.6), due to some
+involving playback (using paplay from /dev/urandom) being time-sensitive.
+
Changelog and versioning scheme
```````````````````````````````
-This package uses one-version-per commit scheme (updated by pre-commit hook)
+This package uses one-version-per-commit scheme (updated by pre-commit hook)
and pretty much one release per git commit, unless more immediate follow-up
commits are planned or too lazy to run ``py setup.py sdist bdist_wheel upload``
for some trivial README typo fix.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/pulsectl/_pulsectl.py
new/pulsectl-20.1.2/pulsectl/_pulsectl.py
--- old/pulsectl-18.12.5/pulsectl/_pulsectl.py 2018-12-18 22:26:30.000000000
+0100
+++ new/pulsectl-20.1.2/pulsectl/_pulsectl.py 2020-01-11 17:06:48.000000000
+0100
@@ -4,7 +4,7 @@
# C Bindings
-import os, sys, functools as ft
+import os, sys, ctypes.util, functools as ft
from ctypes import *
@@ -95,6 +95,13 @@
PA_SUBSCRIPTION_EVENT_REMOVE = 0x0020
PA_SUBSCRIPTION_EVENT_TYPE_MASK = 0x0030
+PA_SAMPLE_FLOAT32BE = 5
+
+PA_STREAM_DONT_MOVE = 0x0200
+PA_STREAM_PEAK_DETECT = 0x0800
+PA_STREAM_ADJUST_LATENCY = 0x2000
+PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND = 0x8000
+
def c_enum_map(**values):
return dict((v, force_str(k)) for k,v in values.items())
@@ -340,6 +347,15 @@
('mute', c_int),
]
+class PA_BUFFER_ATTR(Structure):
+ _fields_ = [
+ ('maxlength', c_uint32),
+ ('tlength', c_uint32),
+ ('prebuf', c_uint32),
+ ('minreq', c_uint32),
+ ('fragsize', c_uint32),
+ ]
+
class POLLFD(Structure):
_fields_ = [
@@ -443,6 +459,15 @@
c_int,
c_void_p)
+PA_STREAM_REQUEST_CB_T = CFUNCTYPE(c_void_p,
+ POINTER(PA_STREAM),
+ c_int,
+ c_void_p)
+
+PA_STREAM_NOTIFY_CB_T = CFUNCTYPE(c_void_p,
+ POINTER(PA_STREAM),
+ c_void_p)
+
class LibPulse(object):
@@ -537,7 +562,7 @@
[POINTER(PA_CONTEXT), c_uint32, PA_CLIENT_INFO_CB_T,
c_void_p] ),
pa_context_get_server_info=( 'pa_op',
[POINTER(PA_CONTEXT), PA_SERVER_INFO_CB_T, c_void_p] ),
- pa_operation_unref=([POINTER(PA_OPERATION)], c_int),
+ pa_operation_unref=[POINTER(PA_OPERATION)],
pa_context_get_card_info_by_index=( 'pa_op',
[POINTER(PA_CONTEXT), c_uint32, PA_CARD_INFO_CB_T,
c_void_p] ),
pa_context_get_card_info_list=( 'pa_op',
@@ -572,13 +597,33 @@
[POINTER(PA_CHANNEL_MAP)], (POINTER(PA_CHANNEL_MAP),
'not_null') ),
pa_channel_map_snprint=([c_str_p, c_int,
POINTER(PA_CHANNEL_MAP)], c_str_p),
pa_channel_map_parse=(
- [POINTER(PA_CHANNEL_MAP), c_str_p],
(POINTER(PA_CHANNEL_MAP), 'not_null') ) )
+ [POINTER(PA_CHANNEL_MAP), c_str_p],
(POINTER(PA_CHANNEL_MAP), 'not_null') ),
+ pa_proplist_from_string=([c_str_p], POINTER(PA_PROPLIST)),
+ pa_proplist_free=[POINTER(PA_PROPLIST)],
+ pa_stream_new_with_proplist=(
+ [ POINTER(PA_CONTEXT), c_str_p,
+ POINTER(PA_SAMPLE_SPEC),
POINTER(PA_CHANNEL_MAP), POINTER(PA_PROPLIST) ],
+ POINTER(PA_STREAM) ),
+ pa_stream_set_monitor_stream=([POINTER(PA_STREAM), c_uint32],
'int_check_ge0'),
+ pa_stream_set_read_callback=[POINTER(PA_STREAM),
PA_STREAM_REQUEST_CB_T, c_void_p],
+ pa_stream_connect_record=(
+ [POINTER(PA_STREAM), c_str_p, POINTER(PA_BUFFER_ATTR),
c_int], 'int_check_ge0' ),
+ pa_stream_unref=[POINTER(PA_STREAM)],
+ pa_stream_peek=(
+ [POINTER(PA_STREAM), POINTER(c_void_p),
POINTER(c_int)], 'int_check_ge0' ),
+ pa_stream_drop=([POINTER(PA_STREAM)], 'int_check_ge0'),
+ pa_stream_disconnect=([POINTER(PA_STREAM)], 'int_check_ge0'),
+ pa_context_play_sample=( 'pa_op',
+ [POINTER(PA_CONTEXT), c_str_p, c_str_p, c_uint32,
PA_CONTEXT_SUCCESS_CB_T, c_void_p] ),
+ pa_context_play_sample_with_proplist=( 'pa_op',
+ [ POINTER(PA_CONTEXT), c_str_p, c_str_p, c_uint32,
+ POINTER(PA_PROPLIST), PA_CONTEXT_SUCCESS_CB_T,
c_void_p ] ) )
class CallError(Exception): pass
def __init__(self):
- p = CDLL('libpulse.so.0')
+ p = CDLL(ctypes.util.find_library('libpulse') or
'libpulse.so.0')
self.funcs = dict()
for k, spec in self.func_defs.items():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/pulsectl/pulsectl.py
new/pulsectl-20.1.2/pulsectl/pulsectl.py
--- old/pulsectl-18.12.5/pulsectl/pulsectl.py 2018-10-31 11:58:47.000000000
+0100
+++ new/pulsectl-20.1.2/pulsectl/pulsectl.py 2020-01-11 17:23:05.000000000
+0100
@@ -31,6 +31,10 @@
raise TypeError( 'Pulse<something>Info'
' object is required instead of value: [{}] {}',
type(obj), obj )
+class FakeLock():
+ def __enter__(self): return self
+ def __exit__(self, *err): pass
+
@ft.total_ordering
class EnumValue(object):
@@ -81,10 +85,6 @@
def __repr__(self):
return '<Enum {} [{}]>'.format(self._name, '
'.join(sorted(self._values.keys())))
-class FakeLock():
- def __enter__(self): return self
- def __exit__(self, *err): pass
-
PulseEventTypeEnum = Enum('event-type', c.PA_EVENT_TYPE_MAP)
PulseEventFacilityEnum = Enum('event-facility', c.PA_EVENT_FACILITY_MAP)
@@ -488,7 +488,7 @@
ts = c.mono_time()
ts_deadline = timeout and (ts + timeout)
while True:
- delay = max(0, int((ts_deadline - ts) *
1000000)) if ts_deadline else -1
+ delay = max(0, int((ts_deadline - ts) * 1000))
if ts_deadline else -1
c.pa.mainloop_prepare(loop, delay) # usec
c.pa.mainloop_poll(loop)
if self._loop_closed: break # interrupted by
close() or such
@@ -499,6 +499,14 @@
def _pulse_info_cb(self, info_cls, data_list, done_cb, ctx, info, eof,
userdata):
+ # No idea where callbacks with "userdata != NULL" come from,
+ # but "info" pointer in them is always invalid, so they are
discarded here.
+ # Looks like some kind of mixup or corruption in libpulse
memory?
+ # See also:
https://github.com/mk-fg/python-pulse-control/issues/35
+ if userdata is not None: return
+ # Empty result list and conn issues are checked elsewhere.
+ # Errors here are non-descriptive (errno), so should not be
useful anyway.
+ # if eof < 0: done_cb(s=False)
if eof: done_cb()
else: data_list.append(info_cls(info[0]))
@@ -509,7 +517,9 @@
cb = cb_t(
ft.partial(self._pulse_info_cb,
info_cls, data, cb) if not singleton else
lambda ctx, info, userdata, cb=cb:
data.append(info_cls(info[0])) or cb() )
- pulse_func(self._ctx, *([index, cb, None] if
index is not None else [cb, None]))
+ pa_op = pulse_func( self._ctx,
+ *([index, cb, None] if index is not
None else [cb, None]) )
+ c.pa.operation_unref(pa_op)
data = data or list()
if index is not None or singleton:
if not data: raise PulseIndexError(index)
@@ -815,6 +825,76 @@
c.pa.mainloop_set_poll_func(self._loop, self._pa_poll_cb, None)
+ def get_peak_sample(self, source, timeout, stream_idx=None):
+ '''Returns peak (max) value in 0-1.0 range for samples in
source/stream within timespan.
+ "source" can be either int index of pulseaudio source
+ (i.e. source.index), its name (source.name), or
None to use default source.
+ Resulting value is what pulseaudio returns as
+ PA_SAMPLE_FLOAT32BE float after "timeout"
seconds.
+ If specified source does not exist, 0 should be
returned after timeout.
+ This can be used to detect if there's any sound
+ on the microphone or any sound played through a
sink via its monitor_source index,
+ or same for any specific stream connected to
these (if "stream_idx" is passed).
+ Sample stream masquerades as
+ application.id=org.PulseAudio.pavucontrol to
avoid being listed in various mixer apps.
+ Example - get peak for specific sink input "si" for 0.8
seconds:
+
pulse.get_peak_sample(pulse.sink_info(si.sink).monitor_source, 0.8, si.index)'''
+ samples, proplist = [0],
c.pa.proplist_from_string('application.id=org.PulseAudio.pavucontrol')
+ ss = c.PA_SAMPLE_SPEC(format=c.PA_SAMPLE_FLOAT32BE, rate=25,
channels=1)
+ s = c.pa.stream_new_with_proplist(self._ctx, 'peak detect',
c.byref(ss), None, proplist)
+ c.pa.proplist_free(proplist)
+
+ @c.PA_STREAM_REQUEST_CB_T
+ def read_cb(s, bs, userdata):
+ buff, bs = c.c_void_p(), c.c_int(bs)
+ c.pa.stream_peek(s, buff, c.byref(bs))
+ try:
+ if not buff or bs.value < 4: return
+ # This assumes that native byte order for
floats is BE, same as pavucontrol
+ samples[0] = max(samples[0], c.cast(buff,
c.POINTER(c.c_float))[0])
+ finally:
+ # stream_drop() flushes buffered data (incl.
buff=NULL "hole" data)
+ # stream.h: "should not be called if the buffer
is empty"
+ if bs.value: c.pa.stream_drop(s)
+
+ if stream_idx is not None: c.pa.stream_set_monitor_stream(s,
stream_idx)
+ c.pa.stream_set_read_callback(s, read_cb, None)
+ if source is not None: source = unicode(source).encode('utf-8')
+ try:
+ c.pa.stream_connect_record( s, source,
+ c.PA_BUFFER_ATTR(fragsize=4, maxlength=2**32-1),
+ c.PA_STREAM_DONT_MOVE | c.PA_STREAM_PEAK_DETECT
|
+ c.PA_STREAM_ADJUST_LATENCY |
c.PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND )
+ except c.pa.CallError:
+ c.pa.stream_unref(s)
+ raise
+
+ try: self._pulse_poll(timeout)
+ finally:
+ try: c.pa.stream_disconnect(s)
+ except c.pa.CallError: pass # stream was removed
+
+ return min(1.0, samples[0])
+
+ def play_sample(self, name, sink=None, volume=1.0, proplist_str=None):
+ '''Play specified sound sample,
+ with an optional sink object/name/index, volume
and proplist string parameters.
+ Sample must be stored on the server in advance, see
e.g. "pacmd list-samples".
+ See also libcanberra for an easy XDG theme sample
loading, storage and playback API.'''
+ if isinstance(sink, PulseSinkInfo): sink = sink.index
+ sink = str(sink) if sink is not None else None
+ proplist = c.pa.proplist_from_string(proplist_str) if
proplist_str else None
+ volume = int(round(volume*c.PA_VOLUME_NORM))
+ with self._pulse_op_cb() as cb:
+ try:
+ if not proplist:
+ c.pa.context_play_sample(self._ctx,
name, sink, volume, cb, None)
+ else:
+ c.pa.context_play_sample_with_proplist(
+ self._ctx, name, sink, volume,
proplist, cb, None )
+ except c.pa.CallError as err: raise
PulseOperationInvalid(err.args[-1])
+
+
def connect_to_cli(server=None, as_file=True, socket_timeout=1.0, attempts=5,
retry_delay=0.3):
'''Returns connected CLI interface socket (as file object, unless
as_file=False),
where one can send same commands (as lines) as to
"pacmd" tool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/pulsectl/tests/dummy_instance.py
new/pulsectl-20.1.2/pulsectl/tests/dummy_instance.py
--- old/pulsectl-18.12.5/pulsectl/tests/dummy_instance.py 2018-12-18
23:26:25.000000000 +0100
+++ new/pulsectl-20.1.2/pulsectl/tests/dummy_instance.py 2020-01-11
16:52:54.000000000 +0100
@@ -315,9 +315,13 @@
def test_get_sink_src(self):
with pulsectl.Pulse('t', server=self.sock_unix) as pulse:
- src, sink = pulse.source_list()[0], pulse.sink_list()[0]
+ src, sink = pulse.source_list(), pulse.sink_list()
+ src_nx, sink_nx = max(s.index for s in src)+1,
max(s.index for s in sink)+1
+ src, sink = src[0], sink[0]
self.assertEqual(sink.index,
pulse.get_sink_by_name(sink.name).index)
self.assertEqual(src.index,
pulse.get_source_by_name(src.name).index)
+ with self.assertRaises(pulsectl.PulseIndexError):
pulse.source_info(src_nx)
+ with self.assertRaises(pulsectl.PulseIndexError):
pulse.sink_info(sink_nx)
def test_module_funcs(self):
with pulsectl.Pulse('t', server=self.sock_unix) as pulse:
@@ -371,6 +375,8 @@
if paplay.poll() is None: paplay.kill()
paplay.wait()
+ with self.assertRaises(pulsectl.PulseIndexError):
pulse.sink_input_info(stream.index)
+
def test_ext_stream_restore(self):
sr_name1 = 'sink-input-by-application-name:pulsectl-test-1'
sr_name2 = 'sink-input-by-application-name:pulsectl-test-2'
@@ -459,6 +465,54 @@
finally:
if paplay.poll() is None: paplay.kill()
+ paplay.wait()
+
+ def test_get_peak_sample(self):
+ # Note: this test takes at least multiple seconds to run
+ with pulsectl.Pulse('t', server=self.sock_unix) as pulse:
+ source_any = max(s.index for s in pulse.source_list())
+ source_nx = source_any + 1
+
+ time.sleep(0.3) # make sure previous streams die
+ peak = pulse.get_peak_sample(source_any, 0.3)
+ self.assertEqual(peak, 0)
+
+ stream_started = list()
+ def stream_ev_cb(ev):
+ if ev.t != 'new': return
+ stream_started.append(ev.index)
+ raise pulsectl.PulseLoopStop
+ pulse.event_mask_set('sink_input')
+ pulse.event_callback_set(stream_ev_cb)
+
+ paplay = subprocess.Popen(
+ ['paplay', '--raw', '/dev/urandom'],
env=dict(XDG_RUNTIME_DIR=self.tmp_dir) )
+ try:
+ if not stream_started: pulse.event_listen()
+ stream_idx, = stream_started
+ si = pulse.sink_input_info(stream_idx)
+ sink = pulse.sink_info(si.sink)
+ source = pulse.source_info(sink.monitor_source)
+
+ # First poll can randomly fail if too short,
probably due to latency or such
+ peak =
pulse.get_peak_sample(sink.monitor_source, 3)
+ self.assertGreater(peak, 0)
+
+ peak = pulse.get_peak_sample(source.index, 0.3,
si.index)
+ self.assertGreater(peak, 0)
+ peak = pulse.get_peak_sample(source.name, 0.3,
si.index)
+ self.assertGreater(peak, 0)
+ peak = pulse.get_peak_sample(source_nx, 0.3)
+ self.assertEqual(peak, 0)
+
+ paplay.terminate()
+ paplay.wait()
+
+ peak = pulse.get_peak_sample(source.index, 0.3,
si.index)
+ self.assertEqual(peak, 0)
+
+ finally:
+ if paplay.poll() is None: paplay.kill()
paplay.wait()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/pulsectl.egg-info/PKG-INFO
new/pulsectl-20.1.2/pulsectl.egg-info/PKG-INFO
--- old/pulsectl-18.12.5/pulsectl.egg-info/PKG-INFO 2018-12-18
23:49:03.000000000 +0100
+++ new/pulsectl-20.1.2/pulsectl.egg-info/PKG-INFO 2020-01-11
17:24:09.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pulsectl
-Version: 18.12.5
+Version: 20.1.2
Summary: Python high-level interface and ctypes-based bindings for PulseAudio
(libpulse)
Home-page: http://github.com/mk-fg/python-pulse-control
Author: George Filipkin, Mike Kazantsev
@@ -323,11 +323,14 @@
issues with pulseaudio (or its daemon.conf) and underlying
dependencies.
There are no "expected" test case failures.
+ All tests can run for up to 10 seconds currently (v19.9.6), due to some
+ involving playback (using paplay from /dev/urandom) being
time-sensitive.
+
Changelog and versioning scheme
```````````````````````````````
- This package uses one-version-per commit scheme (updated by pre-commit
hook)
+ This package uses one-version-per-commit scheme (updated by pre-commit
hook)
and pretty much one release per git commit, unless more immediate
follow-up
commits are planned or too lazy to run ``py setup.py sdist bdist_wheel
upload``
for some trivial README typo fix.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/setup.cfg
new/pulsectl-20.1.2/setup.cfg
--- old/pulsectl-18.12.5/setup.cfg 2018-12-18 23:49:04.000000000 +0100
+++ new/pulsectl-20.1.2/setup.cfg 2020-01-11 17:24:10.037188500 +0100
@@ -4,5 +4,4 @@
[egg_info]
tag_build =
tag_date = 0
-tag_svn_revision = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pulsectl-18.12.5/setup.py
new/pulsectl-20.1.2/setup.py
--- old/pulsectl-18.12.5/setup.py 2018-12-18 23:45:14.000000000 +0100
+++ new/pulsectl-20.1.2/setup.py 2020-01-11 17:22:41.000000000 +0100
@@ -13,7 +13,7 @@
setup(
name = 'pulsectl',
- version = '18.12.5',
+ version = '20.1.2',
author = 'George Filipkin, Mike Kazantsev',
author_email = '[email protected]',
license = 'MIT',