commit: 2e4ef773aa0b1f5ce37a0650bbaf9e55dfc4c069
Author: Sam James <sam <AT> gentoo <DOT> org>
AuthorDate: Tue May 27 06:26:43 2025 +0000
Commit: Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Tue May 27 06:27:10 2025 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=2e4ef773
media-video/pipewire: backport several patches to 1.4.3
Robert Mader (1):
gst: src: Change DEFAULT_MIN_BUFFERS back to 1
Wim Taymans (4):
pod: add bytes start/append/end functions
Use "8 bit raw midi" for control ports again
alsa: remove UMP flag from control format
adapter: negotiate from target to follower
Closes: https://bugs.gentoo.org/956654
Signed-off-by: Sam James <sam <AT> gentoo.org>
...-pod-add-bytes-start-append-end-functions.patch | 50 +++
...se-8-bit-raw-midi-for-control-ports-again.patch | 265 ++++++++++++
...-alsa-remove-UMP-flag-from-control-format.patch | 451 +++++++++++++++++++++
...adapter-negotiate-from-target-to-follower.patch | 202 +++++++++
...-src-Change-DEFAULT_MIN_BUFFERS-back-to-1.patch | 39 ++
...ewire-1.4.3.ebuild => pipewire-1.4.3-r1.ebuild} | 0
6 files changed, 1007 insertions(+)
diff --git
a/media-video/pipewire/files/1.4.3/0001-pod-add-bytes-start-append-end-functions.patch
b/media-video/pipewire/files/1.4.3/0001-pod-add-bytes-start-append-end-functions.patch
new file mode 100644
index 000000000000..d0b413f6dc1b
--- /dev/null
+++
b/media-video/pipewire/files/1.4.3/0001-pod-add-bytes-start-append-end-functions.patch
@@ -0,0 +1,50 @@
+From 483b59a9d95aa084dfcd1c17e13ee27bd106d4b0 Mon Sep 17 00:00:00 2001
+Message-ID:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+From: Wim Taymans <[email protected]>
+Date: Fri, 23 May 2025 16:41:00 +0200
+Subject: [PATCH 1/5] pod: add bytes start/append/end functions
+
+Add functions to dynamically start and build a bytes pod.
+---
+ spa/include/spa/pod/builder.h | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/spa/include/spa/pod/builder.h b/spa/include/spa/pod/builder.h
+index 553f75512..3dc4a4f1c 100644
+--- a/spa/include/spa/pod/builder.h
++++ b/spa/include/spa/pod/builder.h
+@@ -326,6 +326,31 @@ spa_pod_builder_reserve_bytes(struct spa_pod_builder
*builder, uint32_t len)
+ return SPA_POD_BODY(spa_pod_builder_deref(builder, offset));
+ }
+
++SPA_API_POD_BUILDER uint32_t
++spa_pod_builder_bytes_start(struct spa_pod_builder *builder)
++{
++ uint32_t offset = builder->state.offset;
++ const struct spa_pod_bytes p = SPA_POD_INIT_Bytes(0);
++ spa_pod_builder_raw(builder, &p, sizeof(p));
++ return offset;
++}
++SPA_API_POD_BUILDER int
++spa_pod_builder_bytes_append(struct spa_pod_builder *builder, uint32_t offset,
++ const void *data, uint32_t size)
++{
++ int res = spa_pod_builder_raw(builder, data, size);
++ struct spa_pod *pod = spa_pod_builder_deref(builder, offset);
++ if (pod)
++ pod->size += size;
++ return res;
++}
++
++SPA_API_POD_BUILDER int
++spa_pod_builder_bytes_end(struct spa_pod_builder *builder, uint32_t offset)
++{
++ return spa_pod_builder_pad(builder, builder->state.offset);
++}
++
+ #define SPA_POD_INIT_Pointer(type,value) ((struct spa_pod_pointer){ {
sizeof(struct spa_pod_pointer_body), SPA_TYPE_Pointer }, { (type), 0, (value) }
})
+
+ SPA_API_POD_BUILDER int
+--
+2.49.0
+
diff --git
a/media-video/pipewire/files/1.4.3/0002-Use-8-bit-raw-midi-for-control-ports-again.patch
b/media-video/pipewire/files/1.4.3/0002-Use-8-bit-raw-midi-for-control-ports-again.patch
new file mode 100644
index 000000000000..54361ee977b3
--- /dev/null
+++
b/media-video/pipewire/files/1.4.3/0002-Use-8-bit-raw-midi-for-control-ports-again.patch
@@ -0,0 +1,265 @@
+From 76db05a0f8edb8b7d4d896d3860bc555934ad383 Mon Sep 17 00:00:00 2001
+Message-ID:
<76db05a0f8edb8b7d4d896d3860bc555934ad383.1748327071.git....@gentoo.org>
+In-Reply-To:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+References:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+From: Wim Taymans <[email protected]>
+Date: Fri, 23 May 2025 16:46:13 +0200
+Subject: [PATCH 2/5] Use "8 bit raw midi" for control ports again
+
+There is no need to encode the potential format in the format.dsp of
+control ports, this is just for legacy compatibility with JACK apps. The
+actual format can be negotiated with the types field.
+
+Fixes midi port visibility with apps compiled against 1.2, such as JACK
+apps in flatpaks.
+---
+ pipewire-jack/src/pipewire-jack.c | 20 +------------------
+ spa/plugins/alsa/alsa-seq-bridge.c | 2 +-
+ spa/plugins/audioconvert/audioconvert.c | 2 +-
+ spa/plugins/bluez5/midi-node.c | 4 ++--
+ .../videoconvert/videoconvert-ffmpeg.c | 2 +-
+ src/examples/midi-src.c | 2 +-
+ src/modules/module-ffado-driver.c | 2 +-
+ src/modules/module-jack-tunnel.c | 2 +-
+ src/modules/module-netjack2-driver.c | 2 +-
+ src/modules/module-netjack2-manager.c | 2 +-
+ src/modules/module-rtp/stream.c | 2 +-
+ src/modules/module-vban/stream.c | 2 +-
+ src/pipewire/filter.c | 4 +++-
+ src/pipewire/stream.c | 2 +-
+ src/tools/pw-cat.c | 2 +-
+ 15 files changed, 18 insertions(+), 34 deletions(-)
+
+diff --git a/pipewire-jack/src/pipewire-jack.c
b/pipewire-jack/src/pipewire-jack.c
+index 14c062a21..b859b64b0 100644
+--- a/pipewire-jack/src/pipewire-jack.c
++++ b/pipewire-jack/src/pipewire-jack.c
+@@ -3466,24 +3466,6 @@ static const char* type_to_string(jack_port_type_id_t
type_id)
+ }
+ }
+
+-static const char* type_to_format_dsp(jack_port_type_id_t type_id)
+-{
+- switch(type_id) {
+- case TYPE_ID_AUDIO:
+- return JACK_DEFAULT_AUDIO_TYPE;
+- case TYPE_ID_VIDEO:
+- return JACK_DEFAULT_VIDEO_TYPE;
+- case TYPE_ID_OSC:
+- return JACK_DEFAULT_OSC_TYPE;
+- case TYPE_ID_MIDI:
+- return JACK_DEFAULT_MIDI_TYPE;
+- case TYPE_ID_UMP:
+- return JACK_DEFAULT_UMP_TYPE;
+- default:
+- return NULL;
+- }
+-}
+-
+ static bool type_is_dsp(jack_port_type_id_t type_id)
+ {
+ switch(type_id) {
+@@ -5544,7 +5526,7 @@ jack_port_t * jack_port_register (jack_client_t *client,
+
+ spa_list_init(&p->mix);
+
+- pw_properties_set(p->props, PW_KEY_FORMAT_DSP,
type_to_format_dsp(type_id));
++ pw_properties_set(p->props, PW_KEY_FORMAT_DSP, type_to_string(type_id));
+ pw_properties_set(p->props, PW_KEY_PORT_NAME, port_name);
+ if (flags > 0x1f) {
+ pw_properties_setf(p->props, PW_KEY_PORT_EXTRA,
+diff --git a/spa/plugins/alsa/alsa-seq-bridge.c
b/spa/plugins/alsa/alsa-seq-bridge.c
+index 7ec39321c..68e6c91a8 100644
+--- a/spa/plugins/alsa/alsa-seq-bridge.c
++++ b/spa/plugins/alsa/alsa-seq-bridge.c
+@@ -275,7 +275,7 @@ static void emit_port_info(struct seq_state *this, struct
seq_port *port, bool f
+ snprintf(alias, sizeof(alias), "%s:%s", client_name, port_name);
+ clean_name(alias);
+
+- items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32
bit raw UMP");
++ items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8
bit raw midi");
+ items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_OBJECT_PATH,
path);
+ items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, name);
+ items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS,
alias);
+diff --git a/spa/plugins/audioconvert/audioconvert.c
b/spa/plugins/audioconvert/audioconvert.c
+index c1fa022d1..c36028bcd 100644
+--- a/spa/plugins/audioconvert/audioconvert.c
++++ b/spa/plugins/audioconvert/audioconvert.c
+@@ -362,7 +362,7 @@ static void emit_port_info(struct impl *this, struct port
*port, bool full)
+ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_PORT_IGNORE_LATENCY, "true");
+ } else if (PORT_IS_CONTROL(this, port->direction, port->id)) {
+ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "control");
+- items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit raw UMP");
++ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi");
+ }
+ if (this->group_name[0] != '\0')
+ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, this->group_name);
+diff --git a/spa/plugins/bluez5/midi-node.c b/spa/plugins/bluez5/midi-node.c
+index b5fd179ea..cfba2bfcf 100644
+--- a/spa/plugins/bluez5/midi-node.c
++++ b/spa/plugins/bluez5/midi-node.c
+@@ -2024,13 +2024,13 @@ impl_init(const struct spa_handle_factory *factory,
+ for (i = 0; i < N_PORTS; ++i) {
+ struct port *port = &this->ports[i];
+ static const struct spa_dict_item in_port_items[] = {
+- SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit raw
UMP"),
++ SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw
midi"),
+ SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "in"),
+ SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS, "in"),
+ SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, "group.0"),
+ };
+ static const struct spa_dict_item out_port_items[] = {
+- SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit raw
UMP"),
++ SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw
midi"),
+ SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "out"),
+ SPA_DICT_ITEM_INIT(SPA_KEY_PORT_ALIAS, "out"),
+ SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, "group.0"),
+diff --git a/spa/plugins/videoconvert/videoconvert-ffmpeg.c
b/spa/plugins/videoconvert/videoconvert-ffmpeg.c
+index ddb810be5..3da0e5677 100644
+--- a/spa/plugins/videoconvert/videoconvert-ffmpeg.c
++++ b/spa/plugins/videoconvert/videoconvert-ffmpeg.c
+@@ -228,7 +228,7 @@ static void emit_port_info(struct impl *this, struct port
*port, bool full)
+ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_PORT_IGNORE_LATENCY, "true");
+ } else if (PORT_IS_CONTROL(this, port->direction, port->id)) {
+ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_PORT_NAME, "control");
+- items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "32 bit raw UMP");
++ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_FORMAT_DSP, "8 bit raw midi");
+ }
+ if (this->group_name[0] != '\0')
+ items[n_items++] =
SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, this->group_name);
+diff --git a/src/examples/midi-src.c b/src/examples/midi-src.c
+index edcaa0f08..12f86d6f2 100644
+--- a/src/examples/midi-src.c
++++ b/src/examples/midi-src.c
+@@ -213,7 +213,7 @@ int main(int argc, char *argv[])
+ PW_FILTER_PORT_FLAG_MAP_BUFFERS,
+ sizeof(struct port),
+ pw_properties_new(
+- PW_KEY_FORMAT_DSP, "32 bit raw UMP",
++ PW_KEY_FORMAT_DSP, "8 bit raw midi",
+ PW_KEY_PORT_NAME, "output",
+ NULL),
+ NULL, 0);
+diff --git a/src/modules/module-ffado-driver.c
b/src/modules/module-ffado-driver.c
+index 4345e5a19..1c9c7c590 100644
+--- a/src/modules/module-ffado-driver.c
++++ b/src/modules/module-ffado-driver.c
+@@ -772,7 +772,7 @@ static int make_stream_ports(struct stream *s)
+ break;
+ case ffado_stream_type_midi:
+ props = pw_properties_new(
+- PW_KEY_FORMAT_DSP, "32 bit raw UMP",
++ PW_KEY_FORMAT_DSP, "8 bit raw midi",
+ PW_KEY_PORT_NAME, port->name,
+ PW_KEY_PORT_PHYSICAL, "true",
+ PW_KEY_PORT_TERMINAL, "true",
+diff --git a/src/modules/module-jack-tunnel.c
b/src/modules/module-jack-tunnel.c
+index 7ab4c9faf..76ac73c8d 100644
+--- a/src/modules/module-jack-tunnel.c
++++ b/src/modules/module-jack-tunnel.c
+@@ -515,7 +515,7 @@ static void make_stream_ports(struct stream *s)
+ } else {
+ snprintf(name, sizeof(name), "%s_%d", prefix, i -
s->info.channels);
+ props = pw_properties_new(
+- PW_KEY_FORMAT_DSP, "32 bit raw UMP",
++ PW_KEY_FORMAT_DSP, "8 bit raw midi",
+ PW_KEY_PORT_NAME, name,
+ PW_KEY_PORT_PHYSICAL, "true",
+ NULL);
+diff --git a/src/modules/module-netjack2-driver.c
b/src/modules/module-netjack2-driver.c
+index 0aa9a85cd..011052e7b 100644
+--- a/src/modules/module-netjack2-driver.c
++++ b/src/modules/module-netjack2-driver.c
+@@ -452,7 +452,7 @@ static void make_stream_ports(struct stream *s)
+ } else {
+ snprintf(name, sizeof(name), "midi%d", i -
s->info.channels);
+ props = pw_properties_new(
+- PW_KEY_FORMAT_DSP, "32 bit raw UMP",
++ PW_KEY_FORMAT_DSP, "8 bit raw midi",
+ PW_KEY_AUDIO_CHANNEL, name,
+ PW_KEY_PORT_PHYSICAL, "true",
+ NULL);
+diff --git a/src/modules/module-netjack2-manager.c
b/src/modules/module-netjack2-manager.c
+index 2cef87218..fe482fd94 100644
+--- a/src/modules/module-netjack2-manager.c
++++ b/src/modules/module-netjack2-manager.c
+@@ -614,7 +614,7 @@ static void make_stream_ports(struct stream *s)
+ } else {
+ snprintf(name, sizeof(name), "midi%d", i -
s->info.channels);
+ props = pw_properties_new(
+- PW_KEY_FORMAT_DSP, "32 bit raw UMP",
++ PW_KEY_FORMAT_DSP, "8 bit raw midi",
+ PW_KEY_PORT_PHYSICAL, "true",
+ PW_KEY_AUDIO_CHANNEL, name,
+ NULL);
+diff --git a/src/modules/module-rtp/stream.c b/src/modules/module-rtp/stream.c
+index f4d3fa3b8..cbd3ee994 100644
+--- a/src/modules/module-rtp/stream.c
++++ b/src/modules/module-rtp/stream.c
+@@ -390,7 +390,7 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
+ res = -EINVAL;
+ goto out;
+ }
+- pw_properties_set(props, PW_KEY_FORMAT_DSP, "32 bit raw UMP");
++ pw_properties_set(props, PW_KEY_FORMAT_DSP, "8 bit raw midi");
+ impl->stride = impl->format_info->size;
+ impl->rate = pw_properties_get_uint32(props, "midi.rate",
10000);
+ if (impl->rate == 0)
+diff --git a/src/modules/module-vban/stream.c
b/src/modules/module-vban/stream.c
+index efa5af370..10eb34a82 100644
+--- a/src/modules/module-vban/stream.c
++++ b/src/modules/module-vban/stream.c
+@@ -307,7 +307,7 @@ struct vban_stream *vban_stream_new(struct pw_core *core,
+ res = -EINVAL;
+ goto out;
+ }
+- pw_properties_set(props, PW_KEY_FORMAT_DSP, "32 bit raw UMP");
++ pw_properties_set(props, PW_KEY_FORMAT_DSP, "8 bit raw midi");
+ impl->stride = impl->format_info->size;
+ impl->rate = pw_properties_get_uint32(props, "midi.rate",
10000);
+ if (impl->rate == 0)
+diff --git a/src/pipewire/filter.c b/src/pipewire/filter.c
+index 519c1e2f7..03706e98a 100644
+--- a/src/pipewire/filter.c
++++ b/src/pipewire/filter.c
+@@ -1855,8 +1855,10 @@ void *pw_filter_add_port(struct pw_filter *filter,
+ add_control_dsp_port_params(impl, p, 1u <<
SPA_CONTROL_Midi);
+ else if (spa_streq(str, "8 bit raw control"))
+ add_control_dsp_port_params(impl, p, 0);
+- else if (spa_streq(str, "32 bit raw UMP"))
++ else if (spa_streq(str, "32 bit raw UMP")) {
+ add_control_dsp_port_params(impl, p, 1u <<
SPA_CONTROL_UMP);
++ pw_properties_set(props, PW_KEY_FORMAT_DSP, "8 bit raw
midi");
++ }
+ }
+ /* then override with user provided if any */
+ if (update_params(impl, p, SPA_ID_INVALID, params, n_params) < 0)
+diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c
+index 4af3a3afa..f5684d5e7 100644
+--- a/src/pipewire/stream.c
++++ b/src/pipewire/stream.c
+@@ -2053,7 +2053,7 @@ pw_stream_connect(struct pw_stream *stream,
+ pw_properties_set(impl->port_props, PW_KEY_FORMAT_DSP, str);
+ else if (impl->media_type == SPA_MEDIA_TYPE_application &&
+ impl->media_subtype == SPA_MEDIA_SUBTYPE_control)
+- pw_properties_set(impl->port_props, PW_KEY_FORMAT_DSP, "32 bit
raw UMP");
++ pw_properties_set(impl->port_props, PW_KEY_FORMAT_DSP, "8 bit
raw midi");
+ if (pw_properties_get(impl->port_props, PW_KEY_PORT_GROUP) == NULL)
+ pw_properties_set(impl->port_props, PW_KEY_PORT_GROUP,
"stream.0");
+
+diff --git a/src/tools/pw-cat.c b/src/tools/pw-cat.c
+index 36a78981e..928afed0e 100644
+--- a/src/tools/pw-cat.c
++++ b/src/tools/pw-cat.c
+@@ -1985,7 +1985,7 @@ int main(int argc, char *argv[])
+ SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_application),
+ SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
+
+- pw_properties_set(data.props, PW_KEY_FORMAT_DSP, "32 bit raw
UMP");
++ pw_properties_set(data.props, PW_KEY_FORMAT_DSP, "8 bit raw
midi");
+ break;
+ case TYPE_DSD:
+ {
+--
+2.49.0
+
diff --git
a/media-video/pipewire/files/1.4.3/0003-alsa-remove-UMP-flag-from-control-format.patch
b/media-video/pipewire/files/1.4.3/0003-alsa-remove-UMP-flag-from-control-format.patch
new file mode 100644
index 000000000000..f29487147a3b
--- /dev/null
+++
b/media-video/pipewire/files/1.4.3/0003-alsa-remove-UMP-flag-from-control-format.patch
@@ -0,0 +1,451 @@
+From 06941f7315c3ca814771cc8b6612c3d01a8bf968 Mon Sep 17 00:00:00 2001
+Message-ID:
<06941f7315c3ca814771cc8b6612c3d01a8bf968.1748327071.git....@gentoo.org>
+In-Reply-To:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+References:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+From: Wim Taymans <[email protected]>
+Date: Fri, 23 May 2025 16:53:42 +0200
+Subject: [PATCH 3/5] alsa: remove UMP flag from control format
+
+Don't set the UMP type flag on the format. Use the negotiated types flag
+to decide what format to output. Add support for output to old style
+midi.
+
+Set the UMP type flag only on the new mixer and JACK when UMP is
+enabled.
+
+This ensures that only new (or explicitly requesting) apps get UMP and
+old apps receive old midi.
+
+This makes JACK running on 1.2 in flatpaks work with midi again.
+---
+ pipewire-jack/src/pipewire-jack.c | 23 ++++-
+ spa/plugins/alsa/alsa-seq-bridge.c | 13 +--
+ spa/plugins/alsa/alsa-seq.c | 159 ++++++++++++++++++++---------
+ spa/plugins/alsa/alsa-seq.h | 3 +
+ spa/plugins/control/mixer.c | 3 +-
+ src/modules/module-jack-tunnel.c | 33 +++---
+ 6 files changed, 157 insertions(+), 77 deletions(-)
+
+diff --git a/pipewire-jack/src/pipewire-jack.c
b/pipewire-jack/src/pipewire-jack.c
+index b859b64b0..695938f90 100644
+--- a/pipewire-jack/src/pipewire-jack.c
++++ b/pipewire-jack/src/pipewire-jack.c
+@@ -2549,11 +2549,28 @@ static int param_enum_format(struct client *c, struct
port *p,
+ case TYPE_ID_UMP:
+ case TYPE_ID_OSC:
+ case TYPE_ID_MIDI:
+- *param = spa_pod_builder_add_object(b,
+- SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
++ {
++ struct spa_pod_frame f;
++ int32_t types = 0;
++
++ spa_pod_builder_push_object(b, &f,
++ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
++ spa_pod_builder_add(b,
+ SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_application),
+- SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
++ SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
++ 0);
++ if (p->object->port.type_id == TYPE_ID_UMP)
++ types |= 1u<<SPA_CONTROL_UMP;
++ if (p->object->port.type_id == TYPE_ID_OSC)
++ types |= 1u<<SPA_CONTROL_OSC;
++ if (types != 0)
++ spa_pod_builder_add(b,
++ SPA_FORMAT_CONTROL_types,
SPA_POD_CHOICE_FLAGS_Int(types),
++ 0);
++
++ *param = spa_pod_builder_pop(b, &f);
+ break;
++ }
+ case TYPE_ID_VIDEO:
+ *param = spa_pod_builder_add_object(b,
+ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
+diff --git a/spa/plugins/alsa/alsa-seq-bridge.c
b/spa/plugins/alsa/alsa-seq-bridge.c
+index 68e6c91a8..445808017 100644
+--- a/spa/plugins/alsa/alsa-seq-bridge.c
++++ b/spa/plugins/alsa/alsa-seq-bridge.c
+@@ -529,8 +529,7 @@ impl_node_port_enum_params(void *object, int seq,
+ param = spa_pod_builder_add_object(&b,
+ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
+ SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_application),
+- SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
+- SPA_FORMAT_CONTROL_types,
SPA_POD_CHOICE_FLAGS_Int(1u<<SPA_CONTROL_UMP));
++ SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
+ break;
+
+ case SPA_PARAM_Format:
+@@ -541,8 +540,7 @@ impl_node_port_enum_params(void *object, int seq,
+ param = spa_pod_builder_add_object(&b,
+ SPA_TYPE_OBJECT_Format, SPA_PARAM_Format,
+ SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_application),
+- SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
+- SPA_FORMAT_CONTROL_types,
SPA_POD_Int(1u<<SPA_CONTROL_UMP));
++ SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
+ break;
+
+ case SPA_PARAM_Buffers:
+@@ -635,7 +633,7 @@ static int port_set_format(void *object, struct seq_port
*port,
+ port->have_format = false;
+ } else {
+ struct spa_audio_info info = { 0 };
+- uint32_t types;
++ uint32_t types = 0;
+
+ if ((err = spa_format_parse(format, &info.media_type,
&info.media_subtype)) < 0)
+ return err;
+@@ -646,13 +644,12 @@ static int port_set_format(void *object, struct seq_port
*port,
+
+ if ((err = spa_pod_parse_object(format,
+ SPA_TYPE_OBJECT_Format, NULL,
+- SPA_FORMAT_CONTROL_types,
SPA_POD_Int(&types))) < 0)
++ SPA_FORMAT_CONTROL_types,
SPA_POD_OPT_Int(&types))) < 0)
+ return err;
+- if (types != 1u << SPA_CONTROL_UMP)
+- return -EINVAL;
+
+ port->current_format = info;
+ port->have_format = true;
++ port->control_types = types;
+ }
+
+ port->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
+diff --git a/spa/plugins/alsa/alsa-seq.c b/spa/plugins/alsa/alsa-seq.c
+index 04280f291..75d9c604a 100644
+--- a/spa/plugins/alsa/alsa-seq.c
++++ b/spa/plugins/alsa/alsa-seq.c
+@@ -586,7 +586,8 @@ static int prepare_buffer(struct seq_state *state, struct
seq_port *port)
+ spa_pod_builder_init(&port->builder,
+ port->buffer->buf->datas[0].data,
+ port->buffer->buf->datas[0].maxsize);
+- spa_pod_builder_push_sequence(&port->builder, &port->frame, 0);
++ spa_pod_builder_push_sequence(&port->builder, &port->frame, 0);
++ port->ev_offset = SPA_IDX_INVALID;
+
+ return 0;
+ }
+@@ -620,10 +621,8 @@ static int process_read(struct seq_state *state)
+ struct seq_stream *stream = &state->streams[SPA_DIRECTION_OUTPUT];
+ const bool ump = state->ump;
+ uint32_t i;
+- uint32_t *data;
+ uint8_t midi1_data[MAX_EVENT_SIZE];
+ uint32_t ump_data[MAX_EVENT_SIZE];
+- long size;
+ int res = -1;
+
+ /* copy all new midi events into their port buffers */
+@@ -631,10 +630,11 @@ static int process_read(struct seq_state *state)
+ const snd_seq_addr_t *addr;
+ struct seq_port *port;
+ uint64_t ev_time, diff;
+- uint32_t offset;
++ uint32_t offset, ev_type;
+ void *event;
+- uint8_t *midi1_ptr;
+- size_t midi1_size = 0;
++ uint8_t *data_ptr;
++ size_t data_size = 0;
++ long size;
+ uint64_t ump_state = 0;
+ snd_seq_event_type_t SPA_UNUSED type;
+
+@@ -679,7 +679,7 @@ static int process_read(struct seq_state *state)
+ continue;
+
+ if ((res = prepare_buffer(state, port)) < 0) {
+- spa_log_debug(state->log, "can't prepare buffer port:%p
%d.%d: %s",
++ spa_log_warn(state->log, "can't prepare buffer port:%p
%d.%d: %s",
+ port, addr->client, addr->port,
spa_strerror(res));
+ continue;
+ }
+@@ -702,8 +702,8 @@ static int process_read(struct seq_state *state)
+ #ifdef HAVE_ALSA_UMP
+ snd_seq_ump_event_t *ev = event;
+
+- data = (uint32_t*)&ev->ump[0];
+- size =
spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump[0])) * 4;
++ data_ptr = (uint8_t*)&ev->ump[0];
++ data_size =
spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump[0])) * 4;
+ #else
+ spa_assert_not_reached();
+ #endif
+@@ -712,40 +712,69 @@ static int process_read(struct seq_state *state)
+
+ snd_midi_event_reset_decode(stream->codec);
+ if ((size = snd_midi_event_decode(stream->codec,
midi1_data, sizeof(midi1_data), ev)) < 0) {
+- spa_log_warn(state->log, "decode failed: %s",
snd_strerror(size));
++ spa_log_warn(state->log, "decode failed: %s",
snd_strerror(data_size));
+ continue;
+ }
++ data_ptr = midi1_data;
++ data_size = size;
++ }
++
++ ev_type = (port->control_types & (1u << SPA_CONTROL_UMP)) ?
++ SPA_CONTROL_UMP : SPA_CONTROL_Midi;
+
+- midi1_ptr = midi1_data;
+- midi1_size = size;
++ spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d
size:%ld port:%d.%d",
++ type, ev_time, offset, data_size, addr->client,
addr->port);
++
++ if ((ump && ev_type == SPA_CONTROL_UMP) ||
++ (!ump && ev_type == SPA_CONTROL_Midi)) {
++ /* no conversion needed */
++ spa_pod_builder_control(&port->builder, offset,
ev_type);
++ spa_pod_builder_bytes(&port->builder, data_ptr,
data_size);
+ }
++ else if (ump) {
++ bool continued = port->ev_offset != SPA_IDX_INVALID;
++
++ /* UMP -> MIDI */
++ size = spa_ump_to_midi((uint32_t*)data_ptr, data_size,
++ midi1_data, sizeof(midi1_data));
++ if (size < 0)
++ continue;
++
++ if (!continued) {
++ spa_pod_builder_control(&port->builder, offset,
ev_type);
++ port->ev_offset =
spa_pod_builder_bytes_start(&port->builder);
++ if (midi1_data[0] == 0xf0)
++ continued = true;
++ } else {
++ if (midi1_data[size-1] == 0xf7)
++ continued = false;
++ }
++ spa_pod_builder_bytes_append(&port->builder,
port->ev_offset, midi1_data, size);
+
+- do {
+- if (!ump) {
+- data = ump_data;
+- size = spa_ump_from_midi(&midi1_ptr,
&midi1_size,
++ if (!continued) {
++ spa_pod_builder_bytes_end(&port->builder,
port->ev_offset);
++ port->ev_offset = SPA_IDX_INVALID;
++ }
++ } else {
++ /* MIDI -> UMP */
++ while (data_size > 0) {
++ size = spa_ump_from_midi(&data_ptr, &data_size,
+ ump_data, sizeof(ump_data), 0,
&ump_state);
+ if (size <= 0)
+ break;
+- }
+-
+- spa_log_trace_fp(state->log, "event %d time:%"PRIu64"
offset:%d size:%ld port:%d.%d",
+- type, ev_time, offset, size,
addr->client, addr->port);
+
+- spa_pod_builder_control(&port->builder, offset,
SPA_CONTROL_UMP);
+- spa_pod_builder_bytes(&port->builder, data, size);
+-
+- /* make sure we can fit at least one control event of
max size otherwise
+- * we keep the event in the queue and try to copy it in
the next cycle */
+- if (port->builder.state.offset +
+- sizeof(struct spa_pod_control) +
+- MAX_EVENT_SIZE >
port->buffer->buf->datas[0].maxsize)
+- goto done;
++ spa_pod_builder_control(&port->builder, offset,
ev_type);
++ spa_pod_builder_bytes(&port->builder, ump_data,
size);
++ }
++ }
+
+- } while (!ump);
++ /* make sure we can fit at least one control event of max size
otherwise
++ * we keep the event in the queue and try to copy it in the
next cycle */
++ if (port->builder.state.offset +
++ sizeof(struct spa_pod_control) +
++ MAX_EVENT_SIZE >
port->buffer->buf->datas[0].maxsize)
++ break;
+ }
+-
+-done:
+ if (res < 0 && res != -EAGAIN)
+ spa_log_warn(state->log, "event read failed: %s",
snd_strerror(res));
+
+@@ -760,6 +789,8 @@ done:
+ continue;
+
+ if (prepare_buffer(state, port) >= 0) {
++ if (port->ev_offset != SPA_IDX_INVALID)
++ spa_pod_builder_bytes_end(&port->builder,
port->ev_offset);
+ spa_pod_builder_pop(&port->builder, &port->frame);
+
+ port->buffer->buf->datas[0].chunk->offset = 0;
+@@ -846,9 +877,7 @@ static int process_write(struct seq_state *state)
+ SPA_POD_SEQUENCE_FOREACH(pod, c) {
+ size_t body_size;
+ uint8_t *body;
+-
+- if (c->type != SPA_CONTROL_UMP)
+- continue;
++ int size;
+
+ body = SPA_POD_BODY(&c->value);
+ body_size = SPA_POD_BODY_SIZE(&c->value);
+@@ -862,33 +891,67 @@ static int process_write(struct seq_state *state)
+
+ if (ump) {
+ #ifdef HAVE_ALSA_UMP
++ uint8_t *ump_data;
++ uint32_t data[MAX_EVENT_SIZE];
+ snd_seq_ump_event_t ev;
+
+- snd_seq_ump_ev_clear(&ev);
+- snd_seq_ev_set_ump_data(&ev, body,
SPA_MIN(sizeof(ev.ump), (size_t)body_size));
+- snd_seq_ev_set_source(&ev,
state->event.addr.port);
+- snd_seq_ev_set_dest(&ev, port->addr.client,
port->addr.port);
+- snd_seq_ev_schedule_real(&ev,
state->event.queue_id, 0, &out_rt);
+-
+- if ((err =
snd_seq_ump_event_output(state->event.hndl, &ev)) < 0) {
+- spa_log_warn(state->log, "failed to
output event: %s",
+- snd_strerror(err));
+- }
++ do {
++ switch (c->type) {
++ case SPA_CONTROL_UMP:
++ ump_data = body;
++ size = body_size;
++ body_size = 0;
++ break;
++ case SPA_CONTROL_Midi:
++ size = spa_ump_from_midi(&body,
&body_size,
++ data,
sizeof(data), 0, &port->ump_state);
++ ump_data = (uint8_t*)data;
++ break;
++ default:
++ size = 0;
++ body_size = 0;
++ continue;
++ }
++ if (size <= 0)
++ break;
++
++ snd_seq_ump_ev_clear(&ev);
++ snd_seq_ev_set_ump_data(&ev, ump_data,
SPA_MIN(sizeof(ev.ump), (size_t)size));
++ snd_seq_ev_set_source(&ev,
state->event.addr.port);
++ snd_seq_ev_set_dest(&ev,
port->addr.client, port->addr.port);
++ snd_seq_ev_schedule_real(&ev,
state->event.queue_id, 0, &out_rt);
++
++ if ((err =
snd_seq_ump_event_output(state->event.hndl, &ev)) < 0) {
++ spa_log_warn(state->log,
"failed to output event: %s",
++
snd_strerror(err));
++ }
++ } while (body_size > 0);
+ #else
+ spa_assert_not_reached();
+ #endif
+ } else {
+ snd_seq_event_t ev;
+ uint8_t data[MAX_EVENT_SIZE];
+- int size;
++ uint8_t *midi_data;
+
+- if ((size = spa_ump_to_midi((uint32_t *)body,
body_size, data, sizeof(data))) <= 0)
++ switch (c->type) {
++ case SPA_CONTROL_UMP:
++ if ((size = spa_ump_to_midi((uint32_t
*)body, body_size, data, sizeof(data))) <= 0)
++ continue;
++ midi_data = data;
++ break;
++ case SPA_CONTROL_Midi:
++ midi_data = body;
++ size = body_size;
++ break;
++ default:
+ continue;
++ }
+
+ if (first)
+ snd_seq_ev_clear(&ev);
+
+- if ((size =
snd_midi_event_encode(stream->codec, data, size, &ev)) < 0) {
++ if ((size =
snd_midi_event_encode(stream->codec, midi_data, size, &ev)) < 0) {
+ spa_log_warn(state->log, "failed to
encode event: %s", snd_strerror(size));
+
snd_midi_event_reset_encode(stream->codec);
+ first = true;
+diff --git a/spa/plugins/alsa/alsa-seq.h b/spa/plugins/alsa/alsa-seq.h
+index 274311c70..7e9fc4297 100644
+--- a/spa/plugins/alsa/alsa-seq.h
++++ b/spa/plugins/alsa/alsa-seq.h
+@@ -80,7 +80,10 @@ struct seq_port {
+ struct buffer *buffer;
+ struct spa_pod_builder builder;
+ struct spa_pod_frame frame;
++ uint32_t ev_offset;
++ uint64_t ump_state;
+
++ uint32_t control_types;
+ struct spa_audio_info current_format;
+ unsigned int have_format:1;
+ unsigned int valid:1;
+diff --git a/spa/plugins/control/mixer.c b/spa/plugins/control/mixer.c
+index e97072d45..cfe3c394b 100644
+--- a/spa/plugins/control/mixer.c
++++ b/spa/plugins/control/mixer.c
+@@ -298,7 +298,8 @@ static int port_enum_formats(void *object, struct port
*port,
+ *param = spa_pod_builder_add_object(builder,
+ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
+ SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_application),
+- SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
++ SPA_FORMAT_mediaSubtype,
SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
++ SPA_FORMAT_CONTROL_types,
SPA_POD_CHOICE_FLAGS_Int(SPA_ID_INVALID));
+ break;
+ default:
+ return 0;
+diff --git a/src/modules/module-jack-tunnel.c
b/src/modules/module-jack-tunnel.c
+index 76ac73c8d..7cce66b0b 100644
+--- a/src/modules/module-jack-tunnel.c
++++ b/src/modules/module-jack-tunnel.c
+@@ -247,7 +247,6 @@ static void midi_to_jack(struct impl *impl, float *dst,
float *src, uint32_t n_s
+ struct spa_pod_sequence *seq;
+ struct spa_pod_control *c;
+ int res;
+- bool in_sysex = false;
+ uint8_t tmp[n_samples * 4];
+ size_t tmp_size = 0;
+
+@@ -267,23 +266,23 @@ static void midi_to_jack(struct impl *impl, float *dst,
float *src, uint32_t n_s
+
+ if (c->type != SPA_CONTROL_UMP)
+ continue;
++ switch (c->type) {
++ case SPA_CONTROL_UMP:
++ size = spa_ump_to_midi(SPA_POD_BODY(&c->value),
++ SPA_POD_BODY_SIZE(&c->value),
&tmp[tmp_size], sizeof(tmp) - tmp_size);
++ if (size <= 0)
++ continue;
++ tmp_size += size;
++ break;
++ case SPA_CONTROL_Midi:
++ tmp_size = SPA_POD_BODY_SIZE(&c->value);
++ memcpy(tmp, SPA_POD_BODY(&c->value),
SPA_MIN(sizeof(tmp), tmp_size));
++ break;
++ }
+
+- size = spa_ump_to_midi(SPA_POD_BODY(&c->value),
+- SPA_POD_BODY_SIZE(&c->value), &tmp[tmp_size],
sizeof(tmp) - tmp_size);
+- if (size <= 0)
+- continue;
+-
+- if (impl->fix_midi)
+- fix_midi_event(&tmp[tmp_size], size);
+-
+- if (!in_sysex && tmp[tmp_size] == 0xf0)
+- in_sysex = true;
+-
+- tmp_size += size;
+- if (in_sysex && tmp[tmp_size-1] == 0xf7)
+- in_sysex = false;
+-
+- if (!in_sysex) {
++ if (tmp[0] != 0xf0 || tmp[tmp_size-1] == 0xf7) {
++ if (impl->fix_midi)
++ fix_midi_event(tmp, tmp_size);
+ if ((res = jack.midi_event_write(dst, c->offset, tmp,
tmp_size)) < 0)
+ pw_log_warn("midi %p: can't write event: %s",
dst,
+ spa_strerror(res));
+--
+2.49.0
+
diff --git
a/media-video/pipewire/files/1.4.3/0004-adapter-negotiate-from-target-to-follower.patch
b/media-video/pipewire/files/1.4.3/0004-adapter-negotiate-from-target-to-follower.patch
new file mode 100644
index 000000000000..81577ad1a0d2
--- /dev/null
+++
b/media-video/pipewire/files/1.4.3/0004-adapter-negotiate-from-target-to-follower.patch
@@ -0,0 +1,202 @@
+From c507c4b0ffa094d92c76ad4589ad776b677d94d2 Mon Sep 17 00:00:00 2001
+Message-ID:
<c507c4b0ffa094d92c76ad4589ad776b677d94d2.1748327071.git....@gentoo.org>
+In-Reply-To:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+References:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+From: Wim Taymans <[email protected]>
+Date: Mon, 26 May 2025 15:44:51 +0200
+Subject: [PATCH 4/5] adapter: negotiate from target to follower
+
+Since 3abda54d80cb02cacb25b9a66ce2808dc4615b34 we prefer the format
+of the filter. This reverses the selection of the default value when
+negotiating buffers from the target to the follower.
+
+If the follower does not select a reasonable value for the buffer size,
+for example, this then results in wrongly sized buffers.
+
+Fix this by reversing the order of allocation from target to follower
+where we let the target (converter) select a default value, which is
+more likely to be correct.
+
+See #4713, #4619
+---
+ spa/plugins/audioconvert/audioadapter.c | 39 ++++++++-----------------
+ spa/plugins/videoconvert/videoadapter.c | 39 ++++++++-----------------
+ 2 files changed, 24 insertions(+), 54 deletions(-)
+
+diff --git a/spa/plugins/audioconvert/audioadapter.c
b/spa/plugins/audioconvert/audioadapter.c
+index 43a47e25c..f15d5a4ca 100644
+--- a/spa/plugins/audioconvert/audioadapter.c
++++ b/spa/plugins/audioconvert/audioadapter.c
+@@ -442,8 +442,8 @@ static int negotiate_buffers(struct impl *this)
+
+ state = 0;
+ param = NULL;
+- if ((res = node_port_enum_params_sync(this, this->follower,
+- this->direction, 0,
++ if ((res = node_port_enum_params_sync(this, this->target,
++ SPA_DIRECTION_REVERSE(this->direction), 0,
+ SPA_PARAM_Buffers, &state,
+ param, ¶m, &b)) < 0) {
+ if (res == -ENOENT)
+@@ -456,8 +456,8 @@ static int negotiate_buffers(struct impl *this)
+ }
+
+ state = 0;
+- if ((res = node_port_enum_params_sync(this, this->target,
+- SPA_DIRECTION_REVERSE(this->direction), 0,
++ if ((res = node_port_enum_params_sync(this, this->follower,
++ this->direction, 0,
+ SPA_PARAM_Buffers, &state,
+ param, ¶m, &b)) != 1) {
+ debug_params(this, this->target,
+@@ -497,7 +497,7 @@ static int negotiate_buffers(struct impl *this)
+ if (this->async)
+ buffers = SPA_MAX(2u, buffers);
+
+- spa_log_debug(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d
align:%d %d:%d",
++ spa_log_info(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d
align:%d %d:%d",
+ this, buffers, blocks, size, stride, align,
follower_alloc, conv_alloc);
+
+ align = SPA_MAX(align, this->max_align);
+@@ -941,27 +941,13 @@ static int negotiate_format(struct impl *this)
+ spa_node_send_command(this->follower,
+ &SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_ParamBegin));
+
+- /* first try the ideal converter format, which is likely passthrough */
+- tstate = 0;
+- fres = node_port_enum_params_sync(this, this->target,
+- SPA_DIRECTION_REVERSE(this->direction), 0,
+- SPA_PARAM_EnumFormat, &tstate,
+- NULL, &format, &b);
+- if (fres == 1) {
+- fstate = 0;
+- res = node_port_enum_params_sync(this, this->follower,
+- this->direction, 0,
+- SPA_PARAM_EnumFormat, &fstate,
+- format, &format, &b);
+- if (res == 1)
+- goto found;
+- }
+-
+- /* then try something the follower can accept */
++ /* The target has been negotiated on its other ports and so it can
propose
++ * a passthrough format or an ideal conversion. We use the suggestions
of the
++ * target to find the best follower format */
+ for (fstate = 0;;) {
+ format = NULL;
+- res = node_port_enum_params_sync(this, this->follower,
+- this->direction, 0,
++ res = node_port_enum_params_sync(this, this->target,
++ SPA_DIRECTION_REVERSE(this->direction),
0,
+ SPA_PARAM_EnumFormat, &fstate,
+ NULL, &format, &b);
+
+@@ -971,8 +957,8 @@ static int negotiate_format(struct impl *this)
+ break;
+
+ tstate = 0;
+- fres = node_port_enum_params_sync(this, this->target,
+- SPA_DIRECTION_REVERSE(this->direction),
0,
++ fres = node_port_enum_params_sync(this, this->follower,
++ this->direction, 0,
+ SPA_PARAM_EnumFormat, &tstate,
+ format, &format, &b);
+ if (fres == 0 && res == 1)
+@@ -981,7 +967,6 @@ static int negotiate_format(struct impl *this)
+ res = fres;
+ break;
+ }
+-found:
+ if (format == NULL) {
+ debug_params(this, this->follower, this->direction, 0,
+ SPA_PARAM_EnumFormat, format, "follower
format", res);
+diff --git a/spa/plugins/videoconvert/videoadapter.c
b/spa/plugins/videoconvert/videoadapter.c
+index 078c90553..e10a8adf5 100644
+--- a/spa/plugins/videoconvert/videoadapter.c
++++ b/spa/plugins/videoconvert/videoadapter.c
+@@ -416,8 +416,8 @@ static int negotiate_buffers(struct impl *this)
+
+ state = 0;
+ param = NULL;
+- if ((res = spa_node_port_enum_params_sync(this->follower,
+- this->direction, 0,
++ if ((res = spa_node_port_enum_params_sync(this->target,
++ SPA_DIRECTION_REVERSE(this->direction), 0,
+ SPA_PARAM_Buffers, &state,
+ param, ¶m, &b)) < 0) {
+ if (res == -ENOENT)
+@@ -430,8 +430,8 @@ static int negotiate_buffers(struct impl *this)
+ }
+
+ state = 0;
+- if ((res = spa_node_port_enum_params_sync(this->target,
+- SPA_DIRECTION_REVERSE(this->direction), 0,
++ if ((res = spa_node_port_enum_params_sync(this->follower,
++ this->direction, 0,
+ SPA_PARAM_Buffers, &state,
+ param, ¶m, &b)) != 1) {
+ debug_params(this, this->target,
+@@ -471,7 +471,7 @@ static int negotiate_buffers(struct impl *this)
+ if (this->async)
+ buffers = SPA_MAX(2u, buffers);
+
+- spa_log_debug(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d
align:%d %d:%d",
++ spa_log_info(this->log, "%p: buffers:%d, blocks:%d, size:%d, stride:%d
align:%d %d:%d",
+ this, buffers, blocks, size, stride, align,
follower_alloc, conv_alloc);
+
+ align = SPA_MAX(align, this->max_align);
+@@ -908,27 +908,13 @@ static int negotiate_format(struct impl *this)
+ spa_node_send_command(this->follower,
+ &SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_ParamBegin));
+
+- /* first try the ideal converter format, which is likely passthrough */
+- tstate = 0;
+- fres = spa_node_port_enum_params_sync(this->target,
+- SPA_DIRECTION_REVERSE(this->direction), 0,
+- SPA_PARAM_EnumFormat, &tstate,
+- NULL, &format, &b);
+- if (fres == 1) {
+- fstate = 0;
+- res = spa_node_port_enum_params_sync(this->follower,
+- this->direction, 0,
+- SPA_PARAM_EnumFormat, &fstate,
+- format, &format, &b);
+- if (res == 1)
+- goto found;
+- }
+-
+- /* then try something the follower can accept */
++ /* The target has been negotiated on its other ports and so it can
propose
++ * a passthrough format or an ideal conversion. We use the suggestions
of the
++ * target to find the best follower format */
+ for (fstate = 0;;) {
+ format = NULL;
+- res = spa_node_port_enum_params_sync(this->follower,
+- this->direction, 0,
++ res = spa_node_port_enum_params_sync(this->target,
++ SPA_DIRECTION_REVERSE(this->direction),
0,
+ SPA_PARAM_EnumFormat, &fstate,
+ NULL, &format, &b);
+
+@@ -938,8 +924,8 @@ static int negotiate_format(struct impl *this)
+ break;
+
+ tstate = 0;
+- fres = spa_node_port_enum_params_sync(this->target,
+- SPA_DIRECTION_REVERSE(this->direction),
0,
++ fres = spa_node_port_enum_params_sync(this->follower,
++ this->direction, 0,
+ SPA_PARAM_EnumFormat, &tstate,
+ format, &format, &b);
+ if (fres == 0 && res == 1)
+@@ -948,7 +934,6 @@ static int negotiate_format(struct impl *this)
+ res = fres;
+ break;
+ }
+-found:
+ if (format == NULL) {
+ debug_params(this, this->follower, this->direction, 0,
+ SPA_PARAM_EnumFormat, format, "follower
format", res);
+--
+2.49.0
+
diff --git
a/media-video/pipewire/files/1.4.3/0005-gst-src-Change-DEFAULT_MIN_BUFFERS-back-to-1.patch
b/media-video/pipewire/files/1.4.3/0005-gst-src-Change-DEFAULT_MIN_BUFFERS-back-to-1.patch
new file mode 100644
index 000000000000..c6b4ee66dafb
--- /dev/null
+++
b/media-video/pipewire/files/1.4.3/0005-gst-src-Change-DEFAULT_MIN_BUFFERS-back-to-1.patch
@@ -0,0 +1,39 @@
+From eda42ef2fc9eaa41dd7dc1582ae062d2ce727612 Mon Sep 17 00:00:00 2001
+Message-ID:
<eda42ef2fc9eaa41dd7dc1582ae062d2ce727612.1748327071.git....@gentoo.org>
+In-Reply-To:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+References:
<483b59a9d95aa084dfcd1c17e13ee27bd106d4b0.1748327071.git....@gentoo.org>
+From: Robert Mader <[email protected]>
+Date: Sun, 25 May 2025 03:57:38 +0200
+Subject: [PATCH 5/5] gst: src: Change DEFAULT_MIN_BUFFERS back to 1
+
+The change from 1 to 8 was done without justification in the commit
+message and possibly for debug purposes. Unfortunately it breaks
+negotiation with the libcamera virtual pipeline, which defaults to
+4 buffers.
+
+Set the the value to 1 again as successful negotiation - even with an
+unusually low number of buffers - is usually more desirable than an
+error.
+
+Fixes: 98b7dc7c0 ("gst: don't do set_caps from the pipewire callback")
+(cherry picked from commit e81fb773224fb5cd4b9399393ca2d2bfab7f4273)
+---
+ src/gst/gstpipewiresrc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c
+index 694cbea0e..994534c60 100644
+--- a/src/gst/gstpipewiresrc.c
++++ b/src/gst/gstpipewiresrc.c
+@@ -41,7 +41,7 @@ GST_DEBUG_CATEGORY_STATIC (pipewire_src_debug);
+ #define GST_CAT_DEFAULT pipewire_src_debug
+
+ #define DEFAULT_ALWAYS_COPY false
+-#define DEFAULT_MIN_BUFFERS 8
++#define DEFAULT_MIN_BUFFERS 1
+ #define DEFAULT_MAX_BUFFERS INT32_MAX
+ #define DEFAULT_RESEND_LAST false
+ #define DEFAULT_KEEPALIVE_TIME 0
+--
+2.49.0
+
diff --git a/media-video/pipewire/pipewire-1.4.3.ebuild
b/media-video/pipewire/pipewire-1.4.3-r1.ebuild
similarity index 100%
rename from media-video/pipewire/pipewire-1.4.3.ebuild
rename to media-video/pipewire/pipewire-1.4.3-r1.ebuild