From 8299a7f100f3a061fa0700e8b320bb525ad557d8 Mon Sep 17 00:00:00 2001 From: Sean Greenslade Date: Sat, 4 Jun 2022 00:24:49 -0700 Subject: [PATCH 01/13] pactl: fix parsing of percentages with decimal points The logic for detecting which type of volume was given incorrectly interpreted any value with a decimal as a VOL_LINEAR. It also could set multiple flags, which would put the flags variable into an indeterminate state. Additionally, the flags stack variable was uninitialized which could also lead to an indeterminate flag state. Percentages are now prioritized over all other types, and only one type flag can be set. --- src/utils/pactl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 35163f277..2761ebaaf 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -2527,16 +2527,16 @@ static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flag vs = pa_xstrdup(vol_spec); *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE; - if (strchr(vs, '.')) - *vol_flags |= VOL_LINEAR; if (pa_endswith(vs, "%")) { *vol_flags |= VOL_PERCENT; vs[strlen(vs)-1] = 0; } - if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) { + else if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) { *vol_flags |= VOL_DECIBEL; vs[strlen(vs)-2] = 0; } + else if (strchr(vs, '.')) + *vol_flags |= VOL_LINEAR; atod_input = vs; @@ -2597,7 +2597,7 @@ static int parse_volumes(char *args[], unsigned n) { volume.channels = n; for (i = 0; i < volume.channels; i++) { - enum volume_flags flags; + enum volume_flags flags = 0; if (parse_volume(args[i], &volume.values[i], &flags) < 0) return -1; From 437cfe4630778c9b00cab168d678d17f74577baa Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Thu, 2 Jun 2022 15:07:09 +0900 Subject: [PATCH 02/13] sound-file-stream: Fix crash when playing a file which is not aligned pulseaudio crash occurred when I play a file using pacmd play-file command. The file is not aligned with its frame size and the last rendering size is also not aligned. Thus, an assertion was generated at the end of the file as the following. memblockq.c: Assertion 'uchunk->length % bq->base == 0' failed at ../src/pulsecore/memblockq.c:288, function pa_memblockq_push(). Aborting. When I play the file using paplay, it works good. So, I changed to pa_memblockq_push_align instead of pa_memblockq_push to prevent the assertion. Signed-off-by: Jaechul Lee Part-of: --- src/pulsecore/sound-file-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 147aa2288..255f4b61a 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -185,7 +185,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk tchunk.length = (size_t) n * fs; - pa_memblockq_push(u->memblockq, &tchunk); + pa_memblockq_push_align(u->memblockq, &tchunk); pa_memblock_unref(tchunk.memblock); } From ca8c5242eb1d8efc7d09a7174eeb6f3a8417b0fe Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Mon, 13 Jun 2022 21:38:08 +0300 Subject: [PATCH 03/13] rtp: Initialize SDP info struct field added for OPUS Turned out that pa_sdp_info::enable_opus is never initialized, which seldom makes module-rtp-recv believe it will be playing OPUS-encoded stream even though discovered SDP record does not indicate OPUS codec in metadata. Fix this by adding missing initializer. Part-of: --- src/modules/rtp/sdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index e130509df..c3203ba62 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -129,6 +129,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { i->origin = i->session_name = NULL; i->salen = 0; i->payload = 255; + i->enable_opus = false; if (!pa_startswith(t, PA_SDP_HEADER)) { pa_log("Failed to parse SDP data: invalid header."); From 0e896eb51812dbee2076193145ca47516d243f4d Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Fri, 17 Jun 2022 13:11:11 +0200 Subject: [PATCH 04/13] combine-sink: Fix threading issue during underrun A recent commit added i->origin sink for the sink inputs of the combine sinks. Therefore pa_sink_process_input_underruns() treated the combine sink like filter sinks. pa_sink_process_input_underruns() calls itself with the origin sink, which is only correct for filter sinks because they run in the thread context of the origin sink. The combine sink however has its own thread context, so pa_sink_process_input_underruns() was executed in the wrong context. This patch fixes the issue by skipping the section for module-combine-sink. Part-of: --- src/pulsecore/sink.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 3108ae765..0f0dc56fc 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1016,20 +1016,29 @@ size_t pa_sink_process_input_underruns(pa_sink *s, size_t left_to_play) { if (i->origin_sink) { size_t filter_result, left_to_play_origin; - /* The recursive call works in the origin sink domain ... */ - left_to_play_origin = pa_convert_size(left_to_play, &i->sink->sample_spec, &i->origin_sink->sample_spec); + /* The combine sink sets i->origin sink but has a different threading model + * than the filter sinks. Therefore the recursion below may not be executed + * because pa_sink_process_input_underruns() was not called in the thread + * context of the origin sink. + * FIXME: It is unclear if some other kind of recursion would be necessary + * for the combine sink. */ + if (!i->module || !pa_safe_streq(i->module->name, "module-combine-sink")) { - /* .. and returns the time to sleep before waking up. We need the - * underrun duration for comparisons, so we undo the subtraction on - * the return value... */ - filter_result = left_to_play_origin - pa_sink_process_input_underruns(i->origin_sink, left_to_play_origin); + /* The recursive call works in the origin sink domain ... */ + left_to_play_origin = pa_convert_size(left_to_play, &i->sink->sample_spec, &i->origin_sink->sample_spec); - /* ... and convert it back to the master sink domain */ - filter_result = pa_convert_size(filter_result, &i->origin_sink->sample_spec, &i->sink->sample_spec); + /* .. and returns the time to sleep before waking up. We need the + * underrun duration for comparisons, so we undo the subtraction on + * the return value... */ + filter_result = left_to_play_origin - pa_sink_process_input_underruns(i->origin_sink, left_to_play_origin); - /* Remember the longest underrun so far */ - if (filter_result > result) - result = filter_result; + /* ... and convert it back to the master sink domain */ + filter_result = pa_convert_size(filter_result, &i->origin_sink->sample_spec, &i->sink->sample_spec); + + /* Remember the longest underrun so far */ + if (filter_result > result) + result = filter_result; + } } if (uf == 0) { From e4d54dae918da447705cd2cd6c61e65e86658aa2 Mon Sep 17 00:00:00 2001 From: Jan Palus Date: Fri, 17 Jun 2022 14:36:36 +0200 Subject: [PATCH 05/13] bluetooth/gst: Correct var type for GST_TYPE_BITMASK GST_TYPE_BITMASK is 64-bit bit mask while corresponding channel_mask in pulseaudio is int therefore usually 32-bit. Switch to uint64_t instead to match internal representation in gstreamer. Fixes pulseaudio crash on ARM 32-bit when pulseaudio is compiled with gstreamer and either LDAC or aptX support is available. Part-of: --- src/modules/bluetooth/a2dp-codec-gst.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/bluetooth/a2dp-codec-gst.c b/src/modules/bluetooth/a2dp-codec-gst.c index 8ef74be9c..11839c580 100644 --- a/src/modules/bluetooth/a2dp-codec-gst.c +++ b/src/modules/bluetooth/a2dp-codec-gst.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -82,7 +83,7 @@ fail: static GstCaps *gst_create_caps_from_sample_spec(const pa_sample_spec *ss) { gchar *sample_format; GstCaps *caps; - int channel_mask; + uint64_t channel_mask; switch (ss->format) { case PA_SAMPLE_S16LE: From e5ad31e873eed62bc580a86a61177047f9e8c491 Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Tue, 21 Jun 2022 13:37:19 +0300 Subject: [PATCH 06/13] Update NEWS for 16.1 Part-of: --- NEWS | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/NEWS b/NEWS index 847caf8be..1283eed24 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,22 @@ +PulseAudio 16.1 + +A bug fix release. + + * Fix parsing of percentage volumes with decimal points in pactl + * Fix crash with the "pacmd play-file" command when reads from the disk aren't frame-aligned + * Fix module-rtp-recv sometimes thinking it's receiving an Opus stream when it's not + * Fix frequent crashing in module-combine-sink, regression in 16.0 + * Fix crashing on 32-bit architectures when using the GStreamer codecs for LDAC and AptX + +Contributors + +Georg Chini +Igor V. Kovalenko +Jaechul Lee +Jan Palus +Sean Greenslade + + PulseAudio 16.0 Changes at a glance: From 686ae9c69635f1005f2c9a09539e2be93f86d6ff Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Thu, 25 Aug 2022 08:11:04 +0200 Subject: [PATCH 07/13] time-smoother-2: Fix stream time when stream starts paused When a stream is started but has not yet called smoother_2_put(), pa_smoother_2_get() returns the time since the start of the stream even if the stream was started paused. When the stream is started paused, pa_smoother_2_get() should return 0 instead. This patch fixes the problem. Part-of: --- src/pulsecore/time-smoother_2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/time-smoother_2.c b/src/pulsecore/time-smoother_2.c index e14b52f72..ea7ec1b36 100644 --- a/src/pulsecore/time-smoother_2.c +++ b/src/pulsecore/time-smoother_2.c @@ -295,7 +295,7 @@ pa_usec_t pa_smoother_2_get(pa_smoother_2 *s, pa_usec_t time_stamp) { /* If the smoother has not started, just return system time since resume */ if (!s->start_time) { - if (time_stamp >= s->resume_time) + if (time_stamp >= s->resume_time && !s->paused) current_time = time_stamp - s->resume_time; else current_time = 0; From f2836dc6b645b4d35d1870d2e8c6ac83969d0421 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Fri, 27 May 2022 22:41:51 +0300 Subject: [PATCH 08/13] rtp: Accept CRLF delimiters in SDP as required by RFC 4566 RFC 4566 states that SDP record is terminated with CRLF, and parsers should be able to accept records terminated with just LF. Pulseaudio only accepts LF here. Fix this by accepting both CRLF and LF terminators. --- src/modules/rtp/sap.c | 4 +++- src/modules/rtp/sdp.c | 31 ++++++++++++++++++++++++++----- src/modules/rtp/sdp.h | 2 +- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 7fb1a3895..8614022f8 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -213,7 +213,9 @@ int pa_sap_recv(pa_sap_context *c, bool *goodbye) { if ((unsigned) size >= sizeof(MIME_TYPE) && pa_streq(e, MIME_TYPE)) { e += sizeof(MIME_TYPE); size -= (int) sizeof(MIME_TYPE); - } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) { + } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1) + || strcspn(e, "\r\n") != sizeof(PA_SDP_HEADER)-1) { + /* SDP header does not start with v=0[\r]\n */ pa_log_warn("Invalid SDP header."); goto fail; } diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index c3203ba62..bf131a27e 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -73,7 +73,7 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u pa_assert_se(inet_ntop(af, dst, buf_dst, sizeof(buf_dst))); return pa_sprintf_malloc( - PA_SDP_HEADER + PA_SDP_HEADER "\n" "o=%s %lu 0 IN %s %s\n" "s=%s\n" "c=IN %s %s\n" @@ -131,17 +131,29 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { i->payload = 255; i->enable_opus = false; - if (!pa_startswith(t, PA_SDP_HEADER)) { + if (pa_startswith(t, PA_SDP_HEADER)) { + t += sizeof(PA_SDP_HEADER) - 1; + + /* CR delimiter is optional */ + if (*t == '\r') + t++; + + /* LF delimiter is mandatory */ + if (*t == '\n') + t++; + else { + pa_log("Failed to parse SDP data: missing header record terminator LF."); + goto fail; + } + } else { pa_log("Failed to parse SDP data: invalid header."); goto fail; } - t += sizeof(PA_SDP_HEADER)-1; - while (*t) { size_t l; - l = strcspn(t, "\n"); + l = strcspn(t, "\r\n"); if (l <= 2) { pa_log("Failed to parse SDP data: line too short: >%s<.", t); @@ -241,8 +253,17 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { t += l; + /* CR delimiter is optional */ + if (*t == '\r') + t++; + + /* LF delimiter is mandatory */ if (*t == '\n') t++; + else { + pa_log("Failed to parse SDP data: missing record terminator LF."); + goto fail; + } } if (!i->origin || (!is_goodbye && (!i->salen || i->payload > 127 || !ss_valid || port == 0))) { diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h index 28c755a27..80ab3636e 100644 --- a/src/modules/rtp/sdp.h +++ b/src/modules/rtp/sdp.h @@ -26,7 +26,7 @@ #include -#define PA_SDP_HEADER "v=0\n" +#define PA_SDP_HEADER "v=0" typedef struct pa_sdp_info { char *origin; From a8b28d86cdc54c3da9d7e928650d598e26e5a669 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Tue, 24 Oct 2023 22:50:27 +0300 Subject: [PATCH 09/13] shell-completion: Fix typo in --use-pid-file= suggestion Fixes #3786 Part-of: --- shell-completion/bash/pactl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell-completion/bash/pactl b/shell-completion/bash/pactl index b269815d2..7e24be670 100644 --- a/shell-completion/bash/pactl +++ b/shell-completion/bash/pactl @@ -500,7 +500,7 @@ _pulseaudio() --start -k --kill --check --system= -D --daemonize= --fail= --high-priority= --realtime= --disallow-module-loading= --disallow-exit= --exit-idle-time= --scache-idle-time= --log-level= -v --log-target= --log-meta= --log-time= - --log-backtrace= -p --dl-search-path= --resample-method= --use-pit-file= + --log-backtrace= -p --dl-search-path= --resample-method= --use-pid-file= --no-cpu-limit= --disable-shm= --enable-memfd= -L --load= -F --file= -C -n' _init_completion -n = || return From 9a428e4c5076c06f4d877bb69efb42197db70841 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Sun, 12 Nov 2023 15:40:15 +0300 Subject: [PATCH 10/13] Fix crash running in restricted environment. When `pwd.h` header is not available (i.e. not using glibc) and environment variables are not set (e.g. running via `env --ignore-environment`) client library would crash due to uninitialized variable in `pa_get_home_dir()`. Add missing initialization to fix that. Fixes: #3792 Part-of: --- src/pulse/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/util.c b/src/pulse/util.c index 5933b77e8..c7b828cc2 100644 --- a/src/pulse/util.c +++ b/src/pulse/util.c @@ -167,7 +167,7 @@ char *pa_get_host_name(char *s, size_t l) { char *pa_get_home_dir(char *s, size_t l) { char *e; - char *dir; + char *dir = NULL; #ifdef HAVE_PWD_H struct passwd *r; #endif From 0647fcb6222a119a90703f52c8ed4a8397801d41 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 22 Mar 2024 09:31:48 -0400 Subject: [PATCH 11/13] tests: Don't run volume tests with impossible alignments This worked so far somehow, but we were sending in some samples at unrealistic alignments (given that pa_memblockq will be frame-aligned, and we expect all operations to occur per-frame as well). Fixes: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/3803 Part-of: --- src/tests/cpu-volume-test.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/tests/cpu-volume-test.c b/src/tests/cpu-volume-test.c index 5de8c8304..a779fcce3 100644 --- a/src/tests/cpu-volume-test.c +++ b/src/tests/cpu-volume-test.c @@ -43,6 +43,7 @@ static void run_volume_test( int channels, bool correct, bool perf) { + fail_unless(align % channels == 0); PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES]) = { 0 }; PA_DECLARE_ALIGNED(8, int16_t, s_ref[SAMPLES]) = { 0 }; @@ -56,8 +57,6 @@ static void run_volume_test( samples_ref = s_ref + (8 - align); samples_orig = s_orig + (8 - align); nsamples = SAMPLES - (8 - align); - if (nsamples % channels) - nsamples -= nsamples % channels; size = nsamples * sizeof(int16_t); pa_random(samples, size); @@ -119,12 +118,12 @@ START_TEST (svolume_mmx_test) { pa_log_debug("Checking MMX svolume"); for (i = 1; i <= 3; i++) { - for (j = 0; j < 7; j++) - run_volume_test(mmx_func, orig_func, j, i, true, false); + for (j = 0; j <= 7; j += i) + run_volume_test(mmx_func, orig_func, j, i, true, j == 0); } run_volume_test(mmx_func, orig_func, 7, 1, true, true); - run_volume_test(mmx_func, orig_func, 7, 2, true, true); - run_volume_test(mmx_func, orig_func, 7, 3, true, true); + run_volume_test(mmx_func, orig_func, 6, 2, true, true); + run_volume_test(mmx_func, orig_func, 6, 3, true, true); } END_TEST @@ -146,12 +145,12 @@ START_TEST (svolume_sse_test) { pa_log_debug("Checking SSE2 svolume"); for (i = 1; i <= 3; i++) { - for (j = 0; j < 7; j++) - run_volume_test(sse_func, orig_func, j, i, true, false); + for (j = 0; j < 7; j += i) + run_volume_test(sse_func, orig_func, j, i, true, j == 0); } run_volume_test(sse_func, orig_func, 7, 1, true, true); - run_volume_test(sse_func, orig_func, 7, 2, true, true); - run_volume_test(sse_func, orig_func, 7, 3, true, true); + run_volume_test(sse_func, orig_func, 6, 2, true, true); + run_volume_test(sse_func, orig_func, 6, 3, true, true); } END_TEST #endif /* defined (__i386__) || defined (__amd64__) */ @@ -175,12 +174,12 @@ START_TEST (svolume_arm_test) { pa_log_debug("Checking ARM svolume"); for (i = 1; i <= 3; i++) { - for (j = 0; j < 7; j++) - run_volume_test(arm_func, orig_func, j, i, true, false); + for (j = 0; j < 7; j += i) + run_volume_test(arm_func, orig_func, j, i, true, j == 0); } run_volume_test(arm_func, orig_func, 7, 1, true, true); - run_volume_test(arm_func, orig_func, 7, 2, true, true); - run_volume_test(arm_func, orig_func, 7, 3, true, true); + run_volume_test(arm_func, orig_func, 6, 2, true, true); + run_volume_test(arm_func, orig_func, 6, 3, true, true); } END_TEST #endif /* defined (__arm__) && defined (__linux__) */ @@ -207,11 +206,11 @@ START_TEST (svolume_orc_test) { pa_log_debug("Checking Orc svolume"); for (i = 1; i <= 2; i++) { - for (j = 0; j < 7; j++) - run_volume_test(orc_func, orig_func, j, i, true, false); + for (j = 0; j < 7; j += i) + run_volume_test(orc_func, orig_func, j, i, true, j == 0); } run_volume_test(orc_func, orig_func, 7, 1, true, true); - run_volume_test(orc_func, orig_func, 7, 2, true, true); + run_volume_test(orc_func, orig_func, 6, 2, true, true); } END_TEST From 566849c4aff8083bc838ac04c11ad91453771ee1 Mon Sep 17 00:00:00 2001 From: flyingOwl Date: Fri, 30 Dec 2022 00:16:03 +0100 Subject: [PATCH 12/13] time-smoother-2: Fix time calculation by comparing timestamps This fixes the rare case of resume_time being bigger than time_stamp. Which happens sometimes when a gstreamer client is quickly seeking through a media file. The resulting integer underflow then causes a huge value in current_time which will break the playback. Part-of: --- src/pulsecore/time-smoother_2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/time-smoother_2.c b/src/pulsecore/time-smoother_2.c index ea7ec1b36..46cc5e9cc 100644 --- a/src/pulsecore/time-smoother_2.c +++ b/src/pulsecore/time-smoother_2.c @@ -307,7 +307,8 @@ pa_usec_t pa_smoother_2_get(pa_smoother_2 *s, pa_usec_t time_stamp) { /* If we are initializing, add the time since resume to the card time at pause_time */ else if (s->init) { current_time += (s->pause_time - s->start_time - s->time_offset - s->fixup_time) * s->time_factor; - current_time += (time_stamp - s->resume_time) * s->time_factor; + if (time_stamp > s->resume_time) + current_time += (time_stamp - s->resume_time) * s->time_factor; /* Smoother is running, calculate current sound card time */ } else From 8f839526a59696dac3a9b8909f039026865dcf69 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 1 Nov 2024 22:13:42 -0400 Subject: [PATCH 13/13] Update NEWS for 16.2 --- NEWS | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/NEWS b/NEWS index 1283eed24..883efab8c 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,20 @@ +PulseAudio 16.2 + +A bug fix release. + + * A couple of time-smoother-2 fixes, mainly manifesting in issues for GStreamer clients + * Fix a crash in some restricted environments + * Minor RTP spec compliance fix + * Minur completion and tests fixups + +Contributors + +Arun Raghavan +Georg Chini +Igor V. Kovalenko +flyingOwl + + PulseAudio 16.1 A bug fix release.