Add a patch to fix midi processing in some cases.

Add a patch to fix crash when exiting some JACK apps such as
  Ardour7.
Add a patch to fix a crash when switching bluetooth profiles.
Add a patch to fix bluetooth source switching between drivers.
This commit is contained in:
Wim Taymans 2022-10-21 12:40:38 +02:00
parent fb2653f928
commit f219fca0b1
7 changed files with 235 additions and 268 deletions

View File

@ -0,0 +1,31 @@
From 79d688349becca7e3b145fc45cf1dacce637efbb Mon Sep 17 00:00:00 2001
From: Wim Taymans <wtaymans@redhat.com>
Date: Thu, 20 Oct 2022 17:44:42 +0200
Subject: [PATCH 1/4] alsa-seq: attempt to get more data in timeout
Also emit the NEED_DATA status so that the graph will pull in new
midi data even when we don't output anything.
Fixes #2775
---
spa/plugins/alsa/alsa-seq.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/spa/plugins/alsa/alsa-seq.c b/spa/plugins/alsa/alsa-seq.c
index 381bbc5e1..8da724528 100644
--- a/spa/plugins/alsa/alsa-seq.c
+++ b/spa/plugins/alsa/alsa-seq.c
@@ -803,8 +803,8 @@ static void alsa_on_timeout_event(struct spa_source *source)
update_time(state, state->current_time, false);
res = process_read(state);
- if (res > 0)
- spa_node_call_ready(&state->callbacks, res);
+ if (res >= 0)
+ spa_node_call_ready(&state->callbacks, res | SPA_STATUS_NEED_DATA);
set_timeout(state, state->next_time);
}
--
2.37.3

View File

@ -1,161 +0,0 @@
From 0e79a93828069875bd66f75c33db9f97c6c6b966 Mon Sep 17 00:00:00 2001
From: Pauli Virtanen <pav@iki.fi>
Date: Thu, 3 Feb 2022 19:23:23 +0200
Subject: [PATCH 1/2] spa/alsa-udev: fix /proc/asound handling without
CONFIG_SND_VERBOSE_PROCFS
For kernels compiled with CONFIG_SND_VERBOSE_PROCFS=n, the pcmXX
/proc/asound entries do not exist. In that case, the "device busy"
check cannot be done, but we should still check existence of PCM devices
correctly.
Count the number of PCM devices from /dev/snd, which should work also
without /proc/asound or /sysfs/class/sound.
---
spa/plugins/alsa/alsa-udev.c | 88 ++++++++++++++++++++++++++++++------
1 file changed, 73 insertions(+), 15 deletions(-)
diff --git a/spa/plugins/alsa/alsa-udev.c b/spa/plugins/alsa/alsa-udev.c
index 572bb8a32..08373239d 100644
--- a/spa/plugins/alsa/alsa-udev.c
+++ b/spa/plugins/alsa/alsa-udev.c
@@ -246,6 +246,60 @@ static void unescape(const char *src, char *dst)
*d = 0;
}
+static int check_device_pcm_class(const char *devname)
+{
+ FILE *f;
+ char path[PATH_MAX];
+ char buf[16];
+ size_t sz;
+
+ /* Check device class */
+ spa_scnprintf(path, sizeof(path), "/sys/class/sound/%s/pcm_class",
+ devname);
+ f = fopen(path, "r");
+ if (f == NULL)
+ return -errno;
+ sz = fread(buf, 1, sizeof(buf) - 1, f);
+ buf[sz] = '\0';
+ fclose(f);
+ return spa_strstartswith(buf, "modem") ? -ENXIO : 0;
+}
+
+static int get_num_pcm_devices(unsigned int card_id)
+{
+ char prefix[32];
+ DIR *snd = NULL;
+ struct dirent *entry;
+ int num_dev = 0;
+ int res;
+
+ /* Check if card has PCM devices, without opening them */
+
+ spa_scnprintf(prefix, sizeof(prefix), "pcmC%uD", card_id);
+
+ if ((snd = opendir("/dev/snd")) == NULL)
+ return -errno;
+
+ while ((errno = 0, entry = readdir(snd)) != NULL) {
+ if (!(entry->d_type == DT_CHR &&
+ spa_strstartswith(entry->d_name, prefix)))
+ continue;
+
+ res = check_device_pcm_class(entry->d_name);
+ if (res == 0 || res == -ENOENT) {
+ /* count device also if sysfs status file not there */
+ ++num_dev;
+ }
+ }
+ if (errno != 0)
+ res = -errno;
+ else
+ res = num_dev;
+
+ closedir(snd);
+ return res;
+}
+
static int check_device_available(struct impl *this, struct device *device, int *num_pcm)
{
char path[PATH_MAX];
@@ -256,14 +310,26 @@ static int check_device_available(struct impl *this, struct device *device, int
struct dirent *entry, *entry_pcm;
int res;
+ res = get_num_pcm_devices(device->id);
+ if (res < 0) {
+ spa_log_error(this->log, "Error finding PCM devices for ALSA card %u: %s",
+ (unsigned int)device->id, spa_strerror(res));
+ return res;
+ }
+ *num_pcm = res;
+
+ spa_log_debug(this->log, "card %u has %d pcm device(s)", (unsigned int)device->id, *num_pcm);
+
/*
* Check if some pcm devices of the card are busy. Check it via /proc, as we
* don't want to actually open any devices using alsa-lib (generates uncontrolled
* number of inotify events), or replicate its subdevice logic.
+ *
+ * The pcmXX directories do not exist if kernel is compiled with
+ * CONFIG_SND_VERBOSE_PROCFS=n. In that case, the busy check always
+ * succeeds.
*/
- *num_pcm = 0;
-
spa_scnprintf(path, sizeof(path), "/proc/asound/card%u", (unsigned int)device->id);
if ((card = opendir(path)) == NULL)
@@ -274,16 +340,9 @@ static int check_device_available(struct impl *this, struct device *device, int
spa_strstartswith(entry->d_name, "pcm")))
continue;
- /* Check device class */
- spa_scnprintf(path, sizeof(path), "/sys/class/sound/pcmC%uD%s/pcm_class",
+ spa_scnprintf(path, sizeof(path), "pcmC%uD%s",
(unsigned int)device->id, entry->d_name+3);
- f = fopen(path, "r");
- if (f == NULL)
- goto done;
- sz = fread(buf, 1, sizeof(buf) - 1, f);
- buf[sz] = '\0';
- fclose(f);
- if (spa_strstartswith(buf, "modem"))
+ if (check_device_pcm_class(path) < 0)
continue;
/* Check busy status */
@@ -319,8 +378,6 @@ static int check_device_available(struct impl *this, struct device *device, int
if (errno != 0)
goto done;
- ++*num_pcm;
-
closedir(pcm);
pcm = NULL;
}
@@ -352,15 +409,16 @@ static int emit_object_info(struct impl *this, struct device *device)
* device->emitted to true. alsalib functions can be used after that.
*/
+ snprintf(path, sizeof(path), "hw:%u", id);
+
if ((res = check_device_available(this, device, &pcm)) < 0)
return res;
if (pcm == 0) {
spa_log_debug(this->log, "no pcm devices for %s", path);
device->ignored = true;
- return 0;
+ return -ENODEV;
}
- snprintf(path, sizeof(path), "hw:%u", id);
spa_log_debug(this->log, "emitting card %s", path);
device->emitted = true;
--
2.34.1

View File

@ -0,0 +1,78 @@
From efca9b9d7eb5c3cfc97475e94029f0af4cfdd418 Mon Sep 17 00:00:00 2001
From: Wim Taymans <wtaymans@redhat.com>
Date: Thu, 20 Oct 2022 21:34:01 +0200
Subject: [PATCH 2/4] jack: set port valid state safely
When unregistering a port, set the port to invalid first and sync the
data loop so that it will not be used anymore from the data loop.
See #2652
---
pipewire-jack/src/pipewire-jack.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c
index 7100a41b0..54551f309 100644
--- a/pipewire-jack/src/pipewire-jack.c
+++ b/pipewire-jack/src/pipewire-jack.c
@@ -610,13 +610,9 @@ static void free_port(struct client *c, struct port *p)
{
struct mix *m;
- if (!p->valid)
- return;
-
spa_list_consume(m, &p->mix, port_link)
free_mix(c, m);
- p->valid = false;
pw_map_remove(&c->ports[p->direction], p->port_id);
free_object(c, p->object);
pw_properties_free(p->props);
@@ -1056,7 +1052,7 @@ static inline void *get_buffer_output(struct port *p, uint32_t frames, uint32_t
struct buffer *b;
struct spa_data *d;
- if (frames == 0)
+ if (frames == 0 || !p->valid)
return NULL;
if (SPA_UNLIKELY((mix = p->global_mix) == NULL))
@@ -4369,6 +4365,15 @@ jack_port_t * jack_port_register (jack_client_t *client,
return (jack_port_t *) o;
}
+static int
+do_invalidate_port(struct spa_loop *loop,
+ bool async, uint32_t seq, const void *data, size_t size, void *user_data)
+{
+ struct port *p = user_data;
+ p->valid = false;
+ return 0;
+}
+
SPA_EXPORT
int jack_port_unregister (jack_client_t *client, jack_port_t *port)
{
@@ -4389,6 +4394,9 @@ int jack_port_unregister (jack_client_t *client, jack_port_t *port)
res = -EINVAL;
goto done;
}
+ pw_data_loop_invoke(c->loop,
+ do_invalidate_port, 1, NULL, 0, !c->data_locked, p);
+
pw_log_info("%p: port %p unregister \"%s\"", client, port, o->port.name);
pw_client_node_port_update(c->node,
@@ -4566,6 +4574,8 @@ void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
return SPA_PTROFF(d->data, offset, void);
}
+ if (!p->valid)
+ return NULL;
ptr = p->get_buffer(p, frames);
pw_log_trace_fp("%p: port %p buffer %p empty:%u", p->client, p, ptr, p->empty_out);
--
2.37.3

View File

@ -1,106 +0,0 @@
From 02ab738c317533f40ea49030f38170eec7e49dda Mon Sep 17 00:00:00 2001
From: Wim Taymans <wtaymans@redhat.com>
Date: Fri, 4 Feb 2022 11:59:57 +0100
Subject: [PATCH 2/2] pulse-server: make sure we don't exceed maxlength
Make sure the various buffer attributes don't exceed maxlength.
Add some SPA_ROUND_UP and SPA_ROUND_DOWN macros.
Fixes #2100
---
spa/include/spa/utils/defs.h | 3 +++
.../module-protocol-pulse/pulse-server.c | 25 +++++++++----------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h
index f37216e73..369dd22a9 100644
--- a/spa/include/spa/utils/defs.h
+++ b/spa/include/spa/utils/defs.h
@@ -228,6 +228,9 @@ struct spa_fraction {
#define SPA_RESTRICT
#endif
+#define SPA_ROUND_DOWN(num,value) ((num) - ((num) % (value)))
+#define SPA_ROUND_UP(num,value) ((((num) + (value) - 1) / (value)) * (value))
+
#define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1))
#define SPA_ROUND_UP_N(num,align) SPA_ROUND_DOWN_N((num) + ((align) - 1),align)
diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c
index eedb23901..8f6bc1850 100644
--- a/src/modules/module-protocol-pulse/pulse-server.c
+++ b/src/modules/module-protocol-pulse/pulse-server.c
@@ -374,15 +374,14 @@ static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a
if (attr->maxlength == (uint32_t) -1 || attr->maxlength > MAXLENGTH)
attr->maxlength = MAXLENGTH;
- attr->maxlength -= attr->maxlength % frame_size;
- attr->maxlength = SPA_MAX(attr->maxlength, frame_size);
+ attr->maxlength = SPA_ROUND_UP(attr->maxlength, frame_size);
+
+ minreq = SPA_MIN(minreq, attr->maxlength);
if (attr->tlength == (uint32_t) -1)
attr->tlength = frac_to_bytes_round_up(s->default_tlength, &s->ss);
- if (attr->tlength > attr->maxlength)
- attr->tlength = attr->maxlength;
- attr->tlength -= attr->tlength % frame_size;
- attr->tlength = SPA_MAX(attr->tlength, frame_size);
+ attr->tlength = SPA_MIN(attr->tlength, attr->maxlength);
+ attr->tlength = SPA_ROUND_UP(attr->tlength, frame_size);
attr->tlength = SPA_MAX(attr->tlength, minreq);
if (attr->minreq == (uint32_t) -1) {
@@ -390,13 +389,13 @@ static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a
/* With low-latency, tlength/4 gives a decent default in all of traditional,
* adjust latency and early request modes. */
uint32_t m = attr->tlength / 4;
- m -= m % frame_size;
+ m = SPA_ROUND_DOWN(m, frame_size);
attr->minreq = SPA_MIN(process, m);
}
attr->minreq = SPA_MAX(attr->minreq, minreq);
if (attr->tlength < attr->minreq+frame_size)
- attr->tlength = attr->minreq + frame_size;
+ attr->tlength = SPA_MIN(attr->minreq + frame_size, attr->maxlength);
if (s->early_requests) {
latency = attr->minreq;
@@ -406,7 +405,7 @@ static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a
else
latency = attr->minreq;
- latency -= latency % frame_size;
+ latency = SPA_ROUND_DOWN(latency, frame_size);
if (attr->tlength >= latency)
attr->tlength -= latency;
@@ -418,20 +417,20 @@ static uint32_t fix_playback_buffer_attr(struct stream *s, struct buffer_attr *a
}
if (attr->tlength < latency + 2 * attr->minreq)
- attr->tlength = latency + 2 * attr->minreq;
+ attr->tlength = SPA_MIN(latency + 2 * attr->minreq, attr->maxlength);
- attr->minreq -= attr->minreq % frame_size;
+ attr->minreq = SPA_ROUND_DOWN(attr->minreq, frame_size);
if (attr->minreq <= 0) {
attr->minreq = frame_size;
attr->tlength += frame_size*2;
}
if (attr->tlength <= attr->minreq)
- attr->tlength = attr->minreq*2 + frame_size;
+ attr->tlength = SPA_MIN(attr->minreq*2 + frame_size, attr->maxlength);
max_prebuf = attr->tlength + frame_size - attr->minreq;
if (attr->prebuf == (uint32_t) -1 || attr->prebuf > max_prebuf)
attr->prebuf = max_prebuf;
- attr->prebuf -= attr->prebuf % frame_size;
+ attr->prebuf = SPA_ROUND_DOWN(attr->prebuf, frame_size);
attr->fragsize = 0;
--
2.34.1

View File

@ -0,0 +1,73 @@
From dec704d8e0a4acd972f4d8a596b4a8e653f4266b Mon Sep 17 00:00:00 2001
From: Wim Taymans <wtaymans@redhat.com>
Date: Thu, 20 Oct 2022 21:52:49 +0200
Subject: [PATCH 3/4] bluez5: stop before freeing things
Make sure all timers are stopped before we clear our state.
See #2764
---
spa/plugins/bluez5/media-sink.c | 3 +--
spa/plugins/bluez5/media-source.c | 4 ++--
spa/plugins/bluez5/sco-sink.c | 2 ++
spa/plugins/bluez5/sco-source.c | 2 ++
4 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/spa/plugins/bluez5/media-sink.c b/spa/plugins/bluez5/media-sink.c
index 255bd7a43..1e4c05669 100644
--- a/spa/plugins/bluez5/media-sink.c
+++ b/spa/plugins/bluez5/media-sink.c
@@ -1663,8 +1663,7 @@ static int impl_clear(struct spa_handle *handle)
{
struct impl *this = (struct impl *) handle;
- if (this->codec_data)
- this->codec->deinit(this->codec_data);
+ do_stop(this);
if (this->codec_props && this->codec->clear_props)
this->codec->clear_props(this->codec_props);
if (this->transport)
diff --git a/spa/plugins/bluez5/media-source.c b/spa/plugins/bluez5/media-source.c
index c03d767b1..b1387da49 100644
--- a/spa/plugins/bluez5/media-source.c
+++ b/spa/plugins/bluez5/media-source.c
@@ -1452,8 +1452,8 @@ static int impl_clear(struct spa_handle *handle)
{
struct impl *this = (struct impl *) handle;
struct port *port = &this->port;
- if (this->codec_data)
- this->codec->deinit(this->codec_data);
+
+ do_stop(this);
if (this->codec_props && this->codec->clear_props)
this->codec->clear_props(this->codec_props);
if (this->transport)
diff --git a/spa/plugins/bluez5/sco-sink.c b/spa/plugins/bluez5/sco-sink.c
index d92bada2a..d0578d202 100644
--- a/spa/plugins/bluez5/sco-sink.c
+++ b/spa/plugins/bluez5/sco-sink.c
@@ -1236,6 +1236,8 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
static int impl_clear(struct spa_handle *handle)
{
struct impl *this = (struct impl *) handle;
+
+ do_stop(this);
if (this->transport)
spa_hook_remove(&this->transport_listener);
spa_system_close(this->data_system, this->timerfd);
diff --git a/spa/plugins/bluez5/sco-source.c b/spa/plugins/bluez5/sco-source.c
index 52a1d27cc..81470d267 100644
--- a/spa/plugins/bluez5/sco-source.c
+++ b/spa/plugins/bluez5/sco-source.c
@@ -1391,6 +1391,8 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
static int impl_clear(struct spa_handle *handle)
{
struct impl *this = (struct impl *) handle;
+
+ do_stop(this);
if (this->transport)
spa_hook_remove(&this->transport_listener);
spa_system_close(this->data_system, this->timerfd);
--
2.37.3

View File

@ -0,0 +1,41 @@
From 7aca980c4a7f60dbf5c28be6ab0b03986f5cdbb5 Mon Sep 17 00:00:00 2001
From: Pauli Virtanen <pav@iki.fi>
Date: Wed, 19 Oct 2022 18:56:09 +0300
Subject: [PATCH 4/4] bluez5: reset timers when reassigning followers
Driver timeouts need to be started/stopped when we switch from follower
to driver or vice versa.
The BT sources fail to do this, so fix it. Sinks already do it right.
---
spa/plugins/bluez5/media-source.c | 1 +
spa/plugins/bluez5/sco-source.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/spa/plugins/bluez5/media-source.c b/spa/plugins/bluez5/media-source.c
index b1387da49..515eedbe6 100644
--- a/spa/plugins/bluez5/media-source.c
+++ b/spa/plugins/bluez5/media-source.c
@@ -276,6 +276,7 @@ static int do_reassign_follower(struct spa_loop *loop,
struct impl *this = user_data;
struct port *port = &this->port;
+ set_timers(this);
spa_bt_decode_buffer_recover(&port->buffer);
return 0;
}
diff --git a/spa/plugins/bluez5/sco-source.c b/spa/plugins/bluez5/sco-source.c
index 81470d267..11c126262 100644
--- a/spa/plugins/bluez5/sco-source.c
+++ b/spa/plugins/bluez5/sco-source.c
@@ -248,6 +248,7 @@ static int do_reassign_follower(struct spa_loop *loop,
struct impl *this = user_data;
struct port *port = &this->port;
+ set_timers(this);
spa_bt_decode_buffer_recover(&port->buffer);
return 0;
}
--
2.37.3

View File

@ -9,7 +9,7 @@
%global ms_version 0.4.1
# For rpmdev-bumpspec and releng automation
%global baserelease 1
%global baserelease 2
#global snapdate 20210107
#global gitcommit b17db2cebc1a5ab2c01851d29c05f79cd2f262bb
@ -80,6 +80,10 @@ Source1: https://gitlab.freedesktop.org/pipewire/media-session/-/archive/
%endif
## upstream patches
Patch0001: 0001-alsa-seq-attempt-to-get-more-data-in-timeout.patch
Patch0002: 0002-jack-set-port-valid-state-safely.patch
Patch0003: 0003-bluez5-stop-before-freeing-things.patch
Patch0004: 0004-bluez5-reset-timers-when-reassigning-followers.patch
## upstreamable patches
@ -624,6 +628,13 @@ systemctl --no-reload preset --global pipewire.socket >/dev/null 2>&1 || :
%endif
%changelog
* Fri Oct 21 2022 Wim Taymans <wtaymans@redhat.com> - 0.3.59-2
- Add a patch to fix midi processing in some cases.
- Add a patch to fix crash when exiting some JACK apps such as
Ardour7.
- Add a patch to fix a crash when switching bluetooth profiles.
- Add a patch to fix bluetooth source switching between drivers.
* Fri Sep 30 2022 Wim Taymans <wtaymans@redhat.com> - 0.3.59-1
- Update version to 0.3.59