diff --git a/0001-alsa-seq-attempt-to-get-more-data-in-timeout.patch b/0001-alsa-seq-attempt-to-get-more-data-in-timeout.patch new file mode 100644 index 0000000..84bd390 --- /dev/null +++ b/0001-alsa-seq-attempt-to-get-more-data-in-timeout.patch @@ -0,0 +1,31 @@ +From 79d688349becca7e3b145fc45cf1dacce637efbb Mon Sep 17 00:00:00 2001 +From: Wim Taymans +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 + diff --git a/0001-spa-alsa-udev-fix-proc-asound-handling-without-CONFI.patch b/0001-spa-alsa-udev-fix-proc-asound-handling-without-CONFI.patch deleted file mode 100644 index cbbf303..0000000 --- a/0001-spa-alsa-udev-fix-proc-asound-handling-without-CONFI.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 0e79a93828069875bd66f75c33db9f97c6c6b966 Mon Sep 17 00:00:00 2001 -From: Pauli Virtanen -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 - diff --git a/0002-jack-set-port-valid-state-safely.patch b/0002-jack-set-port-valid-state-safely.patch new file mode 100644 index 0000000..bfb2e06 --- /dev/null +++ b/0002-jack-set-port-valid-state-safely.patch @@ -0,0 +1,78 @@ +From efca9b9d7eb5c3cfc97475e94029f0af4cfdd418 Mon Sep 17 00:00:00 2001 +From: Wim Taymans +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 + diff --git a/0002-pulse-server-make-sure-we-don-t-exceed-maxlength.patch b/0002-pulse-server-make-sure-we-don-t-exceed-maxlength.patch deleted file mode 100644 index fb7019e..0000000 --- a/0002-pulse-server-make-sure-we-don-t-exceed-maxlength.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 02ab738c317533f40ea49030f38170eec7e49dda Mon Sep 17 00:00:00 2001 -From: Wim Taymans -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 - diff --git a/0003-bluez5-stop-before-freeing-things.patch b/0003-bluez5-stop-before-freeing-things.patch new file mode 100644 index 0000000..1364902 --- /dev/null +++ b/0003-bluez5-stop-before-freeing-things.patch @@ -0,0 +1,73 @@ +From dec704d8e0a4acd972f4d8a596b4a8e653f4266b Mon Sep 17 00:00:00 2001 +From: Wim Taymans +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 + diff --git a/0004-bluez5-reset-timers-when-reassigning-followers.patch b/0004-bluez5-reset-timers-when-reassigning-followers.patch new file mode 100644 index 0000000..469b6cc --- /dev/null +++ b/0004-bluez5-reset-timers-when-reassigning-followers.patch @@ -0,0 +1,41 @@ +From 7aca980c4a7f60dbf5c28be6ab0b03986f5cdbb5 Mon Sep 17 00:00:00 2001 +From: Pauli Virtanen +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 + diff --git a/pipewire.spec b/pipewire.spec index 13549d8..f84518b 100644 --- a/pipewire.spec +++ b/pipewire.spec @@ -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 - 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 - 0.3.59-1 - Update version to 0.3.59