diff -Nru pipewire-1.0.4/.gitlab-ci.yml pipewire-1.0.5/.gitlab-ci.yml --- pipewire-1.0.4/.gitlab-ci.yml 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/.gitlab-ci.yml 2024-04-15 07:33:15.000000000 +0000 @@ -263,6 +263,9 @@ variables: MESON_OPTIONS: >- -Ddocs=enabled + -Dman=enabled + -Ddoc-prefix-value=/usr + -Ddoc-sysconfdir-value=/etc -Dinstalled_tests=enabled -Dsystemd-system-service=enabled -Dbluez5-backend-hsphfpd=enabled @@ -281,6 +284,47 @@ - build-*/meson-logs - prefix-* +build_on_fedora_html_docs: + extends: + - .build_on_fedora + variables: + MESON_OPTIONS: >- + -Ddocs=enabled + -Dman=enabled + -Ddoc-prefix-value=/usr + -Ddoc-sysconfdir-value=/etc + -Dinstalled_tests=enabled + -Dsystemd-system-service=enabled + -Dbluez5-backend-hsphfpd=enabled + -Daudiotestsrc=enabled + -Dtest=enabled + -Dvideotestsrc=enabled + -Dvolume=enabled + -Dvulkan=enabled + -Dsdl2=enabled + -Dsndfile=enabled + -Dsession-managers=[] + before_script: + - git fetch origin 1.0 master + - git branch -f 1.0 origin/1.0 + - git branch -f master origin/master + - git clone -b 1.0 . branch-1.0 + - git clone -b master . branch-master + - !reference [.build, before_script] + script: + - cd branch-1.0 + - meson setup builddir $MESON_OPTIONS + - meson compile -C builddir doc/pipewire-docs + - cd ../branch-master + - meson setup builddir $MESON_OPTIONS + - meson compile -C builddir doc/pipewire-docs + artifacts: + name: pipewire-$CI_COMMIT_SHA + when: always + paths: + - branch-*/builddir/meson-logs + - branch-*/builddir/doc/html + build_on_alpine: extends: - .alpine @@ -507,12 +551,14 @@ - .not_coverity stage: pages dependencies: - - build_on_fedora + - build_on_fedora_html_docs script: - - mkdir public - - cp -R prefix-*/share/doc/pipewire/html/* public/ + - mkdir public public/devel + - cp -R branch-1.0/builddir/doc/html/* public/ + - cp -R branch-master/builddir/doc/html/* public/devel/ artifacts: paths: - public only: + - 'master' - '1.0' diff -Nru pipewire-1.0.4/NEWS pipewire-1.0.5/NEWS --- pipewire-1.0.4/NEWS 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/NEWS 2024-04-15 07:33:15.000000000 +0000 @@ -1,3 +1,58 @@ +# PipeWire 1.0.5 (2024-04-15) + +This is a bugfix release that is API and ABI compatible with previous +1.0.x releases. + +## Highlights + - pw_stream can now report timestamps on buffers and the expected + amount of samples for the resampler. + - The GStreamer element now has more correct timestamps using the new + pw_stream timestamps as a fallback. + - The FFADO module now handles suspend and resume better. + - A regression in v4l2 was fixed when parsing malformed filters. + - A potential memory/fd leak was fixed in client-node. + - Many more small bugfixes and improvements. + + +## PipeWire + - pw_stream now reports the expected resampler input or output size in + the pw_time structure. (#3750) + - pw_stream now also adds a time field to the buffer, which contains the + time of the graph when the buffer was received in the stream. + - Fix a compiler error when compiling with -Werror=shadow. (#3915) + - The config parser will warn when invalid config is detected. + +## Modules + - The FFADO module now opens and closes when suspending. This fixes some + problems when FFADO properties are changed while suspended. (#3558) + - Filter-chain will now warn when invalid config is detected. + - Echo-cancel will now handle manage the state of the echo-cancel plugin + better, making sure run() is not called after deactivate(). + - Fix some potential memory/fd leaks in client-node. + +## SPA + - Improve reading the bound ALSA controls. + - The resampler can now also report the number of expected output samples. + - The ALSA ACP device objects have some more properties like the card.id + and alsa.components. (#3912) + - Fix a potential string corruption when parsing JSON strings. + - V4l2 now sets the latency on the port. (#3910) + - alsa-udev now has an option to expose the device even if busy. (#3914) + - Improve null-audio-sink channel handling. (#3931) + - v4l2 will now drop the first frame because it often contains wrong + timestamps or garbage. (#3910) + - A regression in v4l2 was fixed where invalid/empty properties in the + filter would make it error early. (#3959) + +## GStreamer + - The source now falls back to the new pw_buffer time for the timestamps. + +## Docs + - Sync with the master branch. + +Older versions: + + # PipeWire 1.0.4 (2024-03-13) This is a bugfix release that is API and ABI compatible with previous @@ -82,9 +137,6 @@ ## ALSA - Handle errors from eventfd_create correctly. -Older versions: - - # PipeWire 1.0.3 (2024-02-02) This is a quick bugfix release that is API and ABI compatible with previous diff -Nru pipewire-1.0.4/debian/changelog pipewire-1.0.5/debian/changelog --- pipewire-1.0.4/debian/changelog 2024-04-07 07:21:01.000000000 +0000 +++ pipewire-1.0.5/debian/changelog 2024-04-15 20:07:28.000000000 +0000 @@ -1,26 +1,44 @@ -pipewire (1.0.4-2ubuntu4) noble; urgency=medium +pipewire (1.0.5-1~bpo24.04.1) noble; urgency=medium - * No-change rebuild against libasound2t64 + * No-change backport to noble. - -- Steve Langasek Sun, 07 Apr 2024 07:21:01 +0000 + -- Jeremy Bícha Mon, 15 Apr 2024 16:07:28 -0400 -pipewire (1.0.4-2ubuntu3) noble; urgency=medium +pipewire (1.0.5-1) unstable; urgency=medium - * No-change rebuild for CVE-2024-3094 + [ Dylan Aïssi ] + * New upstream release (Closes: #1069033, LP: #2061381) + * Refresh patches + * Drop patch included in upstream release: + - 64-bit-time-t-compat.patch - -- Steve Langasek Sun, 31 Mar 2024 00:12:56 +0000 + [ Jeremy Bícha ] + * Revert "Temporarily disable Snap integration on 32-bit non-x86" + * Revert "Temporarily disable libffado integration on 32-bit non-x86" -pipewire (1.0.4-2ubuntu2) noble; urgency=medium + -- Dylan Aïssi Mon, 15 Apr 2024 21:08:58 +0200 - * No-change rebuild against libcanberra t64. +pipewire (1.0.4-3) unstable; urgency=medium - -- Matthias Klose Sun, 24 Mar 2024 14:47:12 +0100 + * Team upload -pipewire (1.0.4-2ubuntu1) noble; urgency=medium + [ Michael Hudson-Doyle ] + * s/libpipewire-0.3-0/libpipewire-0.3-0t64/ in the shlibs.local files - * s/libpipewire-0.3-0/libpipewire-0.3-0t64/ in the shlibs.local files. + [ Simon McVittie ] + * Only build Snap integration on supported architectures. + According to Snap documentation, only these architectures are + supported, so enabling the others is unlikely to be particularly + useful. Reducing the architecture list reduces the impact of any + non-portability in snapd-glib. + * Temporarily disable Snap integration on 32-bit non-x86. + snapd-glib has not yet been rebuilt for the 64-bit time_t transition. + This change should be reverted after snapd-glib is rebuilt. + * Temporarily disable libffado integration on 32-bit non-x86. + Same reasoning as for snapd-glib, above. + (Closes: #1067558) - -- Michael Hudson-Doyle Fri, 22 Mar 2024 18:03:57 +1300 + -- Simon McVittie Sun, 24 Mar 2024 17:06:55 +0000 pipewire (1.0.4-2) unstable; urgency=medium diff -Nru pipewire-1.0.4/debian/control pipewire-1.0.5/debian/control --- pipewire-1.0.4/debian/control 2024-03-22 05:03:57.000000000 +0000 +++ pipewire-1.0.5/debian/control 2024-04-15 19:08:58.000000000 +0000 @@ -1,8 +1,7 @@ Source: pipewire Section: libs Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Utopia Maintenance Team +Maintainer: Utopia Maintenance Team Uploaders: Jeremy Bicha , Dylan Aïssi Build-Depends: dpkg-dev (>= 1.22.5), debhelper-compat (= 13), @@ -33,7 +32,7 @@ libroc-dev (>= 0.3.0+dfsg-3), libsbc-dev, libsdl2-dev , - libsnapd-glib-dev [linux-any], + libsnapd-glib-dev [amd64 arm64 armhf i386 powerpc ppc64el riscv64 s390x], libsndfile1-dev, libssl-dev, libsystemd-dev [linux-any], diff -Nru pipewire-1.0.4/debian/patches/64-bit-time-t-compat.patch pipewire-1.0.5/debian/patches/64-bit-time-t-compat.patch --- pipewire-1.0.4/debian/patches/64-bit-time-t-compat.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/64-bit-time-t-compat.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Description: 64-bit time_t compatibility for v4l2 module - The v4l2 build unsets _FILE_OFFSET_BITS, which is not allowed when setting - _TIME_BITS=64. Having verified that nothing in this module is sensitive to - 64-bit time_t (none of the functions it intercepts handle time), we also - unset _TIME_BITS to allow this to build as before. -Author: Steve Langasek -Forwarded: no -Last-Update: 2024-03-13 -Bug-Debian: https://bugs.debian.org/1066839 - -Index: pipewire-1.0.3/pipewire-v4l2/src/meson.build -=================================================================== ---- pipewire-1.0.3.orig/pipewire-v4l2/src/meson.build -+++ pipewire-1.0.3/pipewire-v4l2/src/meson.build -@@ -12,6 +12,7 @@ - '-U_FILE_OFFSET_BITS', - '-D_FILE_OFFSET_BITS=32', - '-D_LARGEFILE64_SOURCE', -+ '-U_TIME_BITS', - '-fvisibility=hidden', - ] - diff -Nru pipewire-1.0.4/debian/patches/series pipewire-1.0.5/debian/patches/series --- pipewire-1.0.4/debian/patches/series 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/series 2024-04-15 19:08:58.000000000 +0000 @@ -20,5 +20,3 @@ snap/snap-policy-Manage-ENOPROTOOPT-error-in-aa_getpeercon.patch snap/snap-policy-ensure-audio-works-with-.deb-snapd.patch snap/snap-policy-fix-memory-leak.patch - -64-bit-time-t-compat.patch diff -Nru pipewire-1.0.4/debian/patches/snap/Add-missing-files.patch pipewire-1.0.5/debian/patches/snap/Add-missing-files.patch --- pipewire-1.0.4/debian/patches/snap/Add-missing-files.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Add-missing-files.patch 2024-04-15 19:08:58.000000000 +0000 @@ -14,9 +14,6 @@ create mode 100644 src/modules/module-protocol-pulse/snap-policy.c create mode 100644 src/modules/module-protocol-pulse/snap-policy.h -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -new file mode 100644 -index 0000000..70bf984 --- /dev/null +++ b/src/modules/module-protocol-pulse/snap-policy.c @@ -0,0 +1,193 @@ @@ -213,9 +210,6 @@ + + return permissions; +} -diff --git a/src/modules/module-protocol-pulse/snap-policy.h b/src/modules/module-protocol-pulse/snap-policy.h -new file mode 100644 -index 0000000..0c152d3 --- /dev/null +++ b/src/modules/module-protocol-pulse/snap-policy.h @@ -0,0 +1,22 @@ diff -Nru pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-1.patch pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-1.patch --- pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-1.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-1.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,8 +9,6 @@ src/modules/module-protocol-pulse/snap-policy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index 8cf2762..7bec184 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c @@ -19,7 +19,8 @@ diff -Nru pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-2.patch pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-2.patch --- pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-2.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-2.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index d838d33..a6f2e24 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -58,7 +58,7 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -58,7 +58,7 @@ SnapdPlug **plug = NULL; GPtrArray *slots = NULL; SnapdSlotRef **slot = NULL; diff -Nru pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-3.patch pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-3.patch --- pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-3.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s-3.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/meson.build b/meson.build -index ccdd998..a564b16 100644 --- a/meson.build +++ b/meson.build -@@ -439,7 +439,7 @@ else +@@ -441,7 +441,7 @@ snap_dep = dependency('snapd-glib', required : get_option('snap')) endif if snap_dep.found() and glib2_snap_dep.found() and gio2_snap_dep.found() and apparmor_snap_dep.found() diff -Nru pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s.patch pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s.patch --- pipewire-1.0.4/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Apply-1-suggestion-s-to-1-file-s.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index 70bf984..8cf2762 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -90,7 +90,7 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -90,7 +90,7 @@ *app_id = snap_id; // it's a "classic" or a "devmode" confinement snap, so we give it full access diff -Nru pipewire-1.0.4/debian/patches/snap/Better-error-logging-if-getting-connections-fails.patch pipewire-1.0.5/debian/patches/snap/Better-error-logging-if-getting-connections-fails.patch --- pipewire-1.0.4/debian/patches/snap/Better-error-logging-if-getting-connections-fails.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Better-error-logging-if-getting-connections-fails.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index a6f2e24..14e9827 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -148,17 +148,17 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -148,17 +148,17 @@ &plugs, NULL, NULL, diff -Nru pipewire-1.0.4/debian/patches/snap/Better-meson_options-description.patch pipewire-1.0.5/debian/patches/snap/Better-meson_options-description.patch --- pipewire-1.0.4/debian/patches/snap/Better-meson_options-description.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Better-meson_options-description.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ meson_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/meson_options.txt b/meson_options.txt -index e0937b4..6b274dc 100644 --- a/meson_options.txt +++ b/meson_options.txt -@@ -331,6 +331,6 @@ option('libffado', +@@ -343,7 +343,7 @@ type: 'feature', value: 'auto') option('snap', @@ -21,3 +19,4 @@ + description : 'Enable Snap permissions support.', type : 'feature', value : 'auto') + option('doc-prefix-value', diff -Nru pipewire-1.0.4/debian/patches/snap/Fix-spacing-when-calling-functions.patch pipewire-1.0.5/debian/patches/snap/Fix-spacing-when-calling-functions.patch --- pipewire-1.0.4/debian/patches/snap/Fix-spacing-when-calling-functions.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Fix-spacing-when-calling-functions.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index b96c599..e1dd0d5 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -106,15 +106,15 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -106,15 +106,15 @@ // give to it full access. if (check_is_same_snap(aacon, aa_label)) return PW_SANDBOX_ACCESS_ALL; @@ -32,7 +30,7 @@ pw_log_warn("snap_get_audio_permissions: error summoning snapctl2 for pulseaudio interface: %s", error->message); return PW_SANDBOX_ACCESS_NONE; } -@@ -125,7 +125,7 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -125,7 +125,7 @@ return PW_SANDBOX_ACCESS_ALL; } char *snapctl_command2[] = { "is-connected", "--apparmor-label", aa_label, "audio-record", NULL }; @@ -41,7 +39,7 @@ pw_log_warn("snap_get_audio_permissions: error summoning snapctl2 for audio-record interface: %s", error->message); return PW_SANDBOX_ACCESS_NONE; } -@@ -177,10 +177,10 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -177,10 +177,10 @@ SnapdSlotRef **slot = (SnapdSlotRef**) slots->pdata; for (guint q = 0; q < slots->len; q++, slot++) { diff -Nru pipewire-1.0.4/debian/patches/snap/Move-add_permission-definition-inside-block.patch pipewire-1.0.5/debian/patches/snap/Move-add_permission-definition-inside-block.patch --- pipewire-1.0.4/debian/patches/snap/Move-add_permission-definition-inside-block.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Move-add_permission-definition-inside-block.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index ebb5f29..b96c599 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -53,7 +53,6 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -53,7 +53,6 @@ g_autoptr(GPtrArray) plugs = NULL; gboolean retv; pw_sandbox_access_t permissions = PW_SANDBOX_ACCESS_NONE; @@ -21,7 +19,7 @@ SnapdPlug **plug = NULL; g_autoptr(GError) error = NULL; int exit_code; -@@ -161,6 +160,7 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -161,6 +160,7 @@ plug = (SnapdPlug **)plugs->pdata; for (guint p = 0; p < plugs->len; p++, plug++) { diff -Nru pipewire-1.0.4/debian/patches/snap/Move-context-variable-definition-inside-block.patch pipewire-1.0.5/debian/patches/snap/Move-context-variable-definition-inside-block.patch --- pipewire-1.0.4/debian/patches/snap/Move-context-variable-definition-inside-block.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Move-context-variable-definition-inside-block.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index fcb1ed6..ebb5f29 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -49,7 +49,6 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -49,7 +49,6 @@ gchar *separator = NULL; g_autofree gchar *aacon = NULL; gchar *aamode = NULL; @@ -21,7 +19,7 @@ g_autoptr(SnapdClient) snapdclient = NULL; g_autoptr(GPtrArray) plugs = NULL; gboolean retv; -@@ -111,7 +110,7 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -111,7 +110,7 @@ snapd_client_set_socket_path (snapdclient, "/run/snapd-snap.socket"); /* Take context from the environment if available */ diff -Nru pipewire-1.0.4/debian/patches/snap/Move-variable-definition-inside-block.patch pipewire-1.0.5/debian/patches/snap/Move-variable-definition-inside-block.patch --- pipewire-1.0.4/debian/patches/snap/Move-variable-definition-inside-block.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Move-variable-definition-inside-block.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,11 +9,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index 14e9827..fcb1ed6 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -56,8 +56,6 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -56,8 +56,6 @@ pw_sandbox_access_t permissions = PW_SANDBOX_ACCESS_NONE; pw_sandbox_access_t add_permission = PW_SANDBOX_ACCESS_NONE; SnapdPlug **plug = NULL; @@ -22,7 +20,7 @@ g_autoptr(GError) error = NULL; int exit_code; -@@ -174,10 +172,10 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -174,10 +172,10 @@ } else { continue; } diff -Nru pipewire-1.0.4/debian/patches/snap/Replace-spaces-with-tabs.patch pipewire-1.0.5/debian/patches/snap/Replace-spaces-with-tabs.patch --- pipewire-1.0.4/debian/patches/snap/Replace-spaces-with-tabs.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Replace-spaces-with-tabs.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,8 +9,6 @@ src/modules/module-protocol-pulse/snap-policy.c | 322 ++++++++++++------------ 1 file changed, 161 insertions(+), 161 deletions(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index e1dd0d5..f027f5c 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c @@ -18,172 +18,172 @@ @@ -201,8 +199,6 @@ - permissions |= add_permission; - } - } -- -- return permissions; + g_autofree gchar* aa_label = NULL; + gchar* snap_id = NULL; + gchar* snap_confinement = NULL; @@ -344,6 +340,7 @@ + permissions |= add_permission; + } + } -+ + +- return permissions; + return permissions; } diff -Nru pipewire-1.0.4/debian/patches/snap/Use-assert-to-check-client-is-not-NULL.patch pipewire-1.0.5/debian/patches/snap/Use-assert-to-check-client-is-not-NULL.patch --- pipewire-1.0.4/debian/patches/snap/Use-assert-to-check-client-is-not-NULL.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/Use-assert-to-check-client-is-not-NULL.patch 2024-04-15 19:08:58.000000000 +0000 @@ -9,8 +9,6 @@ src/modules/module-protocol-pulse/snap-policy.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index 7bec184..d838d33 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c @@ -16,6 +16,7 @@ @@ -21,7 +19,7 @@ #define SNAP_LABEL_PREFIX "snap." -@@ -61,10 +62,7 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -61,10 +62,7 @@ int exit_code; *app_id = g_strdup("unknown"); diff -Nru pipewire-1.0.4/debian/patches/snap/fix-possible-leak.patch pipewire-1.0.5/debian/patches/snap/fix-possible-leak.patch --- pipewire-1.0.4/debian/patches/snap/fix-possible-leak.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/fix-possible-leak.patch 2024-04-15 19:08:58.000000000 +0000 @@ -13,11 +13,9 @@ src/modules/module-protocol-pulse/server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) -diff --git a/src/modules/module-protocol-pulse/server.c b/src/modules/module-protocol-pulse/server.c -index 6ae97b7..bbb790f 100644 --- a/src/modules/module-protocol-pulse/server.c +++ b/src/modules/module-protocol-pulse/server.c -@@ -408,7 +408,7 @@ on_connect(void *data, int fd, uint32_t mask) +@@ -408,7 +408,7 @@ client_access = server->client_access; if (server->addr.ss_family == AF_UNIX) { @@ -26,7 +24,7 @@ #ifdef HAVE_SNAP pw_sandbox_access_t snap_access; #endif -@@ -452,9 +452,9 @@ on_connect(void *data, int fd, uint32_t mask) +@@ -452,9 +452,9 @@ } // check SNAP permissions #ifdef HAVE_SNAP diff -Nru pipewire-1.0.4/debian/patches/snap/pipewire-pulse-add-snap-permissions-support.patch pipewire-1.0.5/debian/patches/snap/pipewire-pulse-add-snap-permissions-support.patch --- pipewire-1.0.4/debian/patches/snap/pipewire-pulse-add-snap-permissions-support.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/pipewire-pulse-add-snap-permissions-support.patch 2024-04-15 19:08:58.000000000 +0000 @@ -52,11 +52,9 @@ src/modules/module-protocol-pulse/server.c | 21 +++++++++++++++++++++ 5 files changed, 59 insertions(+), 7 deletions(-) -diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml -index e0fce1c..87b3852 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml -@@ -96,6 +96,7 @@ include: +@@ -96,6 +96,7 @@ debhelper-compat findutils git @@ -64,7 +62,7 @@ libasound2-dev libavcodec-dev libavfilter-dev -@@ -107,6 +108,7 @@ include: +@@ -107,6 +108,7 @@ libgstreamer-plugins-base1.0-dev libsbc-dev libsdl2-dev @@ -72,7 +70,7 @@ libudev-dev libva-dev libv4l-dev -@@ -247,7 +249,7 @@ build_on_ubuntu: +@@ -247,7 +249,7 @@ - .build stage: build variables: @@ -81,7 +79,7 @@ .build_on_fedora: extends: -@@ -274,6 +276,7 @@ build_on_fedora: +@@ -277,6 +279,7 @@ -Dsdl2=enabled -Dsndfile=enabled -Dsession-managers=[] @@ -89,7 +87,7 @@ artifacts: name: pipewire-$CI_COMMIT_SHA when: always -@@ -289,7 +292,7 @@ build_on_alpine: +@@ -333,7 +336,7 @@ - .build stage: build variables: @@ -98,7 +96,7 @@ # build with all auto() options enabled build_all: -@@ -308,6 +311,7 @@ build_all: +@@ -352,6 +355,7 @@ -Dsession-managers=[] -Dc_args=['-UFASTPATH'] -Dcpp_args=['-UFASTPATH'] @@ -106,7 +104,7 @@ parallel: matrix: - CC: [gcc, clang] -@@ -317,7 +321,7 @@ build_with_no_commandline_options: +@@ -361,7 +365,7 @@ extends: - .build_on_fedora variables: @@ -115,7 +113,7 @@ parallel: matrix: - CC: [gcc, clang] -@@ -353,7 +357,7 @@ build_release: +@@ -397,7 +401,7 @@ extends: - .build_on_fedora variables: @@ -124,7 +122,7 @@ parallel: matrix: - CC: [gcc, clang] -@@ -367,7 +371,7 @@ build_session_managers: +@@ -411,7 +415,7 @@ - meson compile -C "$BUILD_DIR" $COMPILE_ARGS - meson install -C "$BUILD_DIR" --no-rebuild variables: @@ -133,7 +131,7 @@ parallel: matrix: - SESSION_MANAGERS: ["[]", "wireplumber", "media-session", "media-session,wireplumber", "wireplumber,media-session" ] -@@ -384,7 +388,7 @@ build_meson_prerelease: +@@ -428,7 +432,7 @@ - meson compile -C "$BUILD_DIR" $COMPILE_ARGS - meson install -C "$BUILD_DIR" --no-rebuild variables: @@ -142,7 +140,7 @@ allow_failure: true build_meson_exact_release: -@@ -402,7 +406,7 @@ build_meson_exact_release: +@@ -446,7 +450,7 @@ - meson compile -C "$BUILD_DIR" $COMPILE_ARGS - meson install -C "$BUILD_DIR" --no-rebuild variables: @@ -151,11 +149,9 @@ valgrind: extends: -diff --git a/meson.build b/meson.build -index eb76fb9..ccdd998 100644 --- a/meson.build +++ b/meson.build -@@ -430,6 +430,22 @@ summary({'lilv (for lv2 plugins)': lilv_lib.found()}, bool_yn: true) +@@ -432,6 +432,22 @@ libffado_dep = dependency('libffado', required: get_option('libffado')) summary({'ffado': libffado_dep.found()}, bool_yn: true) @@ -178,11 +174,9 @@ check_functions = [ ['gettid', '#include ', ['-D_GNU_SOURCE'], []], -diff --git a/meson_options.txt b/meson_options.txt -index a4b0ab5..e0937b4 100644 --- a/meson_options.txt +++ b/meson_options.txt -@@ -330,3 +330,7 @@ option('libffado', +@@ -342,6 +342,10 @@ description: 'Enable code that depends on libffado', type: 'feature', value: 'auto') @@ -190,11 +184,12 @@ + description : 'Snap support is available.', + type : 'feature', + value : 'auto') -diff --git a/src/modules/meson.build b/src/modules/meson.build -index 1b434b7..0909f24 100644 + option('doc-prefix-value', + description : 'Installation prefix to show in documentation instead of the actual value.', + type : 'string', --- a/src/modules/meson.build +++ b/src/modules/meson.build -@@ -393,6 +393,13 @@ pipewire_module_protocol_pulse_sources = [ +@@ -393,6 +393,13 @@ 'module-protocol-pulse/modules/module-zeroconf-discover.c', ] @@ -208,8 +203,6 @@ if dbus_dep.found() pipewire_module_protocol_pulse_sources += [ 'module-protocol-pulse/dbus-name.c', -diff --git a/src/modules/module-protocol-pulse/server.c b/src/modules/module-protocol-pulse/server.c -index 53b1a7e..6ae97b7 100644 --- a/src/modules/module-protocol-pulse/server.c +++ b/src/modules/module-protocol-pulse/server.c @@ -42,6 +42,9 @@ @@ -222,7 +215,7 @@ #define LISTEN_BACKLOG 32 #define MAX_CLIENTS 64 -@@ -406,6 +409,9 @@ on_connect(void *data, int fd, uint32_t mask) +@@ -406,6 +409,9 @@ if (server->addr.ss_family == AF_UNIX) { spa_autofree char *app_id = NULL, *devices = NULL; @@ -232,7 +225,7 @@ #ifdef SO_PRIORITY val = 6; -@@ -444,6 +450,21 @@ on_connect(void *data, int fd, uint32_t mask) +@@ -444,6 +450,21 @@ else pw_properties_set(client->props, PW_KEY_MEDIA_CATEGORY, NULL); } diff -Nru pipewire-1.0.4/debian/patches/snap/snap-policy-Manage-ENOPROTOOPT-error-in-aa_getpeercon.patch pipewire-1.0.5/debian/patches/snap/snap-policy-Manage-ENOPROTOOPT-error-in-aa_getpeercon.patch --- pipewire-1.0.4/debian/patches/snap/snap-policy-Manage-ENOPROTOOPT-error-in-aa_getpeercon.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/snap-policy-Manage-ENOPROTOOPT-error-in-aa_getpeercon.patch 2024-04-15 19:08:58.000000000 +0000 @@ -11,11 +11,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index f027f5c..48084b8 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -65,7 +65,13 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -65,7 +65,13 @@ // if apparmor isn't enabled, we can safely assume that there are no SNAPs in the system return PW_SANDBOX_ACCESS_NOT_A_SANDBOX; } diff -Nru pipewire-1.0.4/debian/patches/snap/snap-policy-ensure-audio-works-with-.deb-snapd.patch pipewire-1.0.5/debian/patches/snap/snap-policy-ensure-audio-works-with-.deb-snapd.patch --- pipewire-1.0.4/debian/patches/snap/snap-policy-ensure-audio-works-with-.deb-snapd.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/snap-policy-ensure-audio-works-with-.deb-snapd.patch 2024-04-15 19:08:58.000000000 +0000 @@ -15,11 +15,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index 48084b8..40cbe46 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -185,8 +185,9 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -185,8 +185,9 @@ for (guint q = 0; q < slots->len; q++, slot++) { const gchar *slot_name = snapd_slot_ref_get_slot(*slot); const gchar *snap_name = snapd_slot_ref_get_snap(*slot); diff -Nru pipewire-1.0.4/debian/patches/snap/snap-policy-fix-memory-leak.patch pipewire-1.0.5/debian/patches/snap/snap-policy-fix-memory-leak.patch --- pipewire-1.0.4/debian/patches/snap/snap-policy-fix-memory-leak.patch 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/patches/snap/snap-policy-fix-memory-leak.patch 2024-04-15 19:08:58.000000000 +0000 @@ -10,11 +10,9 @@ src/modules/module-protocol-pulse/snap-policy.c | 1 + 1 file changed, 1 insertion(+) -diff --git a/src/modules/module-protocol-pulse/snap-policy.c b/src/modules/module-protocol-pulse/snap-policy.c -index 40cbe46..57f0dca 100644 --- a/src/modules/module-protocol-pulse/snap-policy.c +++ b/src/modules/module-protocol-pulse/snap-policy.c -@@ -83,6 +83,7 @@ pw_sandbox_access_t pw_snap_get_audio_permissions(struct client *client, int fd, +@@ -83,6 +83,7 @@ snap_id = g_strdup(aa_label + strlen(SNAP_LABEL_PREFIX)); separator = strchr(snap_id, '.'); if (separator == NULL) { diff -Nru pipewire-1.0.4/debian/rules pipewire-1.0.5/debian/rules --- pipewire-1.0.4/debian/rules 2024-03-14 09:12:07.000000000 +0000 +++ pipewire-1.0.5/debian/rules 2024-04-15 19:08:58.000000000 +0000 @@ -48,15 +48,19 @@ endif ifneq (,$(filter hurd-amd64 hurd-i386,$(DEB_HOST_ARCH))) -SNAP=disabled UDEVRULESDIR= else export UDEVRULESDIR=/usr/lib/udev/rules.d -SNAP=enabled # For pre-Trixie releases udev rules should go in: # export UDEVRULESDIR=/lib/udev/rules.d endif +ifneq (,$(filter amd64 arm64 armhf i386 powerpc ppc64el riscv64 s390x,$(DEB_HOST_ARCH))) +SNAP=enabled +else +SNAP=disabled +endif + override_dh_auto_configure: dh_auto_configure -- \ -Daudiotestsrc=enabled \ diff -Nru pipewire-1.0.4/doc/dox/config/pipewire-devices.7.md pipewire-1.0.5/doc/dox/config/pipewire-devices.7.md --- pipewire-1.0.4/doc/dox/config/pipewire-devices.7.md 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/doc/dox/config/pipewire-devices.7.md 2024-04-15 07:33:15.000000000 +0000 @@ -86,17 +86,17 @@ In addition: -@PAR@ device-param priority.driver +@PAR@ device-param priority.driver # integer \parblock The priority of choosing this device as the driver in the graph. The driver is selected from all linked devices by selecting the device with the highest priority. Normally, the session manager assigns higher priority to sources so that they become the driver in the graph. The reason for this is that adaptive resampling should be done on the sinks rather than the source to avoid signal distortion when capturing audio. \endparblock -@PAR@ device-param priority.session +@PAR@ device-param priority.session # integer The priority for selecting this device as the default device. -@PAR@ device-param clock.name +@PAR@ device-param clock.name # string \parblock The name of the clock. This name is auto generated from the card index and stream direction. Devices with the same clock name will not use a resampler to align the clocks. This can be used to link devices together with a shared word clock. @@ -112,7 +112,7 @@ These are common properties for devices. -@PAR@ device-param device.name +@PAR@ device-param device.name # string A (unique) name for the device. It can be used by command-line and other tools to identify the device. Other `device.*` properties: UNDOCUMENTED @@ -123,6 +123,8 @@ converter. See \ref client_conf__stream_properties "pipewire-client.conf(5) stream.properties" for explanations. +## Node properties + @PAR@ device-param clock.quantum-limit \ref pipewire_conf__default_clock_quantum-limit "See pipewire.conf(5)" @@ -195,93 +197,115 @@ # ALSA PROPERTIES @IDX@ device-param -ALSA node properties: +## Monitor properties + +@PAR@ device-param alsa.use-acp # boolean +Use \ref device-param__alsa_card_profiles "ALSA Card Profiles" (ACP) for device configuration. + +@PAR@ device-param alsa.udev.expose-busy # boolean +Expose the ALSA card even if it is busy/in use. Default false. This can be useful when some +of the PCMs are in use by other applications but the other free PCMs should still be exposed. + +## Device properties + +@PAR@ device-param api.alsa.path # string +ALSA device path as can be used in snd_pcm_open() and snd_ctl_open(). + +@PAR@ device-param api.acp.auto-port # boolean +Select reasonable port on device startup. Available for ACP devices. + +@PAR@ device-param api.acp.auto-profile # boolean +Select reasonable profile on device startup. Available for ACP devices. -@PAR@ device-param audio.channels +## Node properties + +@PAR@ device-param audio.channels # integer The number of audio channels to open the device with. Defaults depends on the profile of the device. -@PAR@ device-param audio.rate +@PAR@ device-param audio.rate # integer The audio rate to open the device with. Default is 0, which means to open the device with a rate as close to the graph rate as possible. -@PAR@ device-param audio.format +@PAR@ device-param audio.format # string The audio format to open the device in. By default this is "UNKNOWN", which will open the device in the best possible bits (32/24/16/8..). You can force a format like S16_LE or S32_LE. -@PAR@ device-param audio.position +@PAR@ device-param audio.position # JSON array of strings The audio position of the channels in the device. This is auto detected based on the profile. You can configure an array of channel positions, like "[ FL, FR ]". -@PAR@ device-param audio.allowed-rates +@PAR@ device-param audio.allowed-rates # JSON array of integers \parblock The allowed audio rates to open the device with. Default is "[ ]", which means the device can be opened in any supported rate. Only rates from the array will be used to open the device. When the graph is running with a rate not listed in the allowed-rates, the resampler will be used to resample to the nearest allowed rate. \endparblock -@PAR@ device-param api.alsa.period-size +@PAR@ device-param api.alsa.period-size # integer The period size to open the device in. By default this is 0, which will open the device in the default period size to minimize latency. -@PAR@ device-param api.alsa.period-num +@PAR@ device-param api.alsa.period-num # integer The amount of periods to use in the device. By default this is 0, which means to use as many as possible. -@PAR@ device-param api.alsa.headroom +@PAR@ device-param api.alsa.headroom # integer The amount of extra space to keep in the ringbuffer. The default is 0. Higher values can be configured when the device read and write pointers are not accurately reported. -@PAR@ device-param api.alsa.start-delay +@PAR@ device-param api.alsa.start-delay # integer Some devices require a startup period. The default is 0. Higher values can be set to send silence samples to the device first. -@PAR@ device-param api.alsa.disable-mmap +@PAR@ device-param api.alsa.disable-mmap # boolean Disable mmap operation of the device and use the ALSA read/write API instead. Default is false, mmap is preferred. -@PAR@ device-param api.alsa.disable-batch +@PAR@ device-param api.alsa.disable-batch # boolean Ignore the ALSA batch flag. If the batch flag is set, ALSA will need an extra period to update the read/write pointers. Ignore this flag from ALSA can reduce the latency. Default is false. -@PAR@ device-param api.alsa.use-chmap +@PAR@ device-param api.alsa.use-chmap # boolean Use the driver provided channel map. Default is false because many drivers don't report this correctly. -@PAR@ device-param api.alsa.multi-rate +@PAR@ device-param api.alsa.multi-rate # boolean Allow devices from the same card to be opened in multiple sample rates. Default is true. Some older drivers did not properly advertize the capabilities of the device and only really supported opening the device in one rate. -@PAR@ device-param api.alsa.htimestamp = false +@PAR@ device-param api.alsa.htimestamp = false # boolean Use ALSA htimestamps in scheduling, instead of the system clock. Some ALSA drivers produce bad timestamps, so this is not enabled by default and will be disabled at runtime if it looks like the ALSA timestamps are bad. -@PAR@ device-param api.alsa.htimestamp.max-errors +@PAR@ device-param api.alsa.htimestamp.max-errors # integer Specify the number of consecutive errors before htimestamp is disabled. Setting this to 0 makes htimestamp never get disabled. -@PAR@ device-param api.alsa.disable-tsched = false +@PAR@ device-param api.alsa.disable-tsched = false # boolean Disable timer-based scheduling, and use IRQ for scheduling instead. The "Pro Audio" profile will usually enable this setting, if it is expected it works on the hardware. -@PAR@ device-param api.alsa.auto-link = false +@PAR@ device-param api.alsa.auto-link = false # boolean Link follower PCM devices to the driver PCM device when using IRQ-based scheduling. The "Pro Audio" profile will usually enable this setting, if it is expected it works on the hardware. -@PAR@ device-param latency.internal.rate +@PAR@ device-param latency.internal.rate # integer Static set the device systemic latency, in samples at playback rate. -@PAR@ device-param latency.internal.ns +@PAR@ device-param latency.internal.ns # integer Static set the device systemic latency, in nanoseconds. -@PAR@ device-param api.alsa.path +@PAR@ device-param api.alsa.path # string UNDOCUMENTED -@PAR@ device-param api.alsa.open.ucm +@PAR@ device-param api.alsa.open.ucm # boolean Open device using UCM. -@PAR@ device-param api.alsa.bind-ctls +@PAR@ device-param api.alsa.bind-ctls # boolean UNDOCUMENTED -@PAR@ device-param iec958.codecs +@PAR@ device-param iec958.codecs # JSON array of string Enable only specific IEC958 codecs. This can be used to disable some codecs the hardware supports. Available values: PCM, AC3, DTS, MPEG, MPEG2-AAC, EAC3, TRUEHD, DTSHD # BLUETOOTH PROPERTIES @IDX@ device-param -The following are settings for the Bluetooth module, not device or +## Monitor properties + +The following are settings for the Bluetooth device monitor, not device or node properties: -@PAR@ device-param bluez5.roles +@PAR@ device-param bluez5.roles # JSON array of string \parblock Enabled roles (default: [ a2dp_sink a2dp_source bap_sink bap_source hfp_hf hfp_ag ]) @@ -299,35 +323,35 @@ - bap_source (LE Audio Basic Audio Profile Source) \endparblock -@PAR@ device-param bluez5.codecs +@PAR@ device-param bluez5.codecs # JSON array of string Enabled A2DP codecs (default: all). Possible values: sbc sbc_xq aac aac_eld aptx aptx_hd aptx_ll aptx_ll_duplex faststream faststream_duplex lc3plus_h3 ldac opus_05 opus_05_51 opus_05_71 opus_05_duplex opus_05_pro opus_g lc3 -@PAR@ device-param bluez5.default.rate +@PAR@ device-param bluez5.default.rate # integer Default audio rate. -@PAR@ device-param bluez5.default.channels +@PAR@ device-param bluez5.default.channels # integer Default audio channels. -@PAR@ device-param bluez5.hfphsp-backend +@PAR@ device-param bluez5.hfphsp-backend # integer HFP/HSP backend (default: native). Available values: any, none, hsphfpd, ofono, native -@PAR@ device-param bluez5.hfphsp-backend-native-modem +@PAR@ device-param bluez5.hfphsp-backend-native-modem # string -@PAR@ device-param bluez5.dummy-avrcp player +@PAR@ device-param bluez5.dummy-avrcp player # boolean Register dummy AVRCP player. Some devices have wrongly functioning volume or playback controls if this is not enabled. Default: false -@PAR@ device-param bluez5.enable-sbc-xq +@PAR@ device-param bluez5.enable-sbc-xq # boolean Override device quirk list and enable SBC-XQ for devices for which it is disabled. -@PAR@ device-param bluez5.enable-msbc +@PAR@ device-param bluez5.enable-msbc # boolean Override device quirk list and enable MSBC for devices for which it is disabled. -@PAR@ device-param bluez5.enable-hw-volume +@PAR@ device-param bluez5.enable-hw-volume # boolean Override device quirk list and enable hardware volume fo devices for which it is disabled. -@PAR@ device-param bluez5.hw-offload-sco +@PAR@ device-param bluez5.hw-offload-sco # boolean \parblock HFP/HSP hardware offload SCO support (default: false). @@ -336,50 +360,50 @@ Do not enable this setting if you don't know what all this means, as it won't work. \endparblock -@PAR@ device-param bluez5.a2dp.opus.pro.channels = 3 +@PAR@ device-param bluez5.a2dp.opus.pro.channels = 3 # integer PipeWire Opus Pro audio profile channel count. -@PAR@ device-param bluez5.a2dp.opus.pro.coupled-streams = 1 +@PAR@ device-param bluez5.a2dp.opus.pro.coupled-streams = 1 # integer PipeWire Opus Pro audio profile coupled stream count. -@PAR@ device-param bluez5.a2dp.opus.pro.locations = "FL,FR,LFE" +@PAR@ device-param bluez5.a2dp.opus.pro.locations = "FL,FR,LFE" # string PipeWire Opus Pro audio profile audio channel locations. -@PAR@ device-param bluez5.a2dp.opus.pro.max-bitrate = 600000 +@PAR@ device-param bluez5.a2dp.opus.pro.max-bitrate = 600000 # integer PipeWire Opus Pro audio profile max bitrate. -@PAR@ device-param bluez5.a2dp.opus.pro.frame-dms = 50 +@PAR@ device-param bluez5.a2dp.opus.pro.frame-dms = 50 # integer PipeWire Opus Pro audio profile frame duration (1/10 ms). -@PAR@ device-param bluez5.a2dp.opus.pro.bidi.channels = 1 +@PAR@ device-param bluez5.a2dp.opus.pro.bidi.channels = 1 # integer PipeWire Opus Pro audio profile duplex channels. -@PAR@ device-param bluez5.a2dp.opus.pro.bidi.coupled-streams = 0 +@PAR@ device-param bluez5.a2dp.opus.pro.bidi.coupled-streams = 0 # integer PipeWire Opus Pro audio profile duplex coupled stream count. -@PAR@ device-param bluez5.a2dp.opus.pro.bidi.locations = "FC" +@PAR@ device-param bluez5.a2dp.opus.pro.bidi.locations = "FC" # string PipeWire Opus Pro audio profile duplex coupled channel locations. -@PAR@ device-param bluez5.a2dp.opus.pro.bidi.max-bitrate = 160000 +@PAR@ device-param bluez5.a2dp.opus.pro.bidi.max-bitrate = 160000 # integer PipeWire Opus Pro audio profile duplex max bitrate. -@PAR@ device-param bluez5.a2dp.opus.pro.bidi.frame-dms = 400 +@PAR@ device-param bluez5.a2dp.opus.pro.bidi.frame-dms = 400 # integer PipeWire Opus Pro audio profile duplex frame duration (1/10 ms). ## Device properties -@PAR@ device-param bluez5.auto-connect +@PAR@ device-param bluez5.auto-connect # boolean Auto-connect devices on start up. Disabled by default if the property is not specified. -@PAR@ device-param bluez5.hw-volume = [ PROFILE1 PROFILE2... ] +@PAR@ device-param bluez5.hw-volume = [ PROFILE1 PROFILE2... ] # JSON array of string Profiles for which to enable hardware volume control (default: [ hfp_ag hsp_ag a2dp_source ]). -@PAR@ device-param bluez5.profile +@PAR@ device-param bluez5.profile # string Initial device profile. This usually has no effect as the session manager overrides it. -@PAR@ device-param bluez5.a2dp.ldac.quality +@PAR@ device-param bluez5.a2dp.ldac.quality # string LDAC encoding quality Available values: - auto (Adaptive Bitrate, default) @@ -387,19 +411,19 @@ - sq (Standard Quality, 660/606kbps) - mq (Mobile use Quality, 330/303kbps) -@PAR@ device-param bluez5.a2dp.aac.bitratemode +@PAR@ device-param bluez5.a2dp.aac.bitratemode # integer AAC variable bitrate mode. Available values: 0 (cbr, default), 1-5 (quality level) -@PAR@ device-param bluez5.a2dp.opus.pro.application = "audio" +@PAR@ device-param bluez5.a2dp.opus.pro.application = "audio" # string PipeWire Opus Pro Audio encoding mode: audio, voip, lowdelay -@PAR@ device-param bluez5.a2dp.opus.pro.bidi.application = "audio" +@PAR@ device-param bluez5.a2dp.opus.pro.bidi.application = "audio" # string PipeWire Opus Pro Audio duplex encoding mode: audio, voip, lowdelay ## Node properties -@PAR@ device-param bluez5.media-source-role +@PAR@ device-param bluez5.media-source-role # string \parblock Media source role for Bluetooth clients connecting to this instance. Available values: diff -Nru pipewire-1.0.4/doc/dox/config/pipewire-pulse.conf.5.md pipewire-1.0.5/doc/dox/config/pipewire-pulse.conf.5.md --- pipewire-1.0.4/doc/dox/config/pipewire-pulse.conf.5.md 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/doc/dox/config/pipewire-pulse.conf.5.md 2024-04-15 07:33:15.000000000 +0000 @@ -74,7 +74,7 @@ ## Example ```css -pulse.properties = { +stream.properties = { #node.latency = 1024/48000 #node.autoconnect = true #resample.disable = false diff -Nru pipewire-1.0.4/doc/dox/config/pipewire.conf.5.md pipewire-1.0.5/doc/dox/config/pipewire.conf.5.md --- pipewire-1.0.4/doc/dox/config/pipewire.conf.5.md 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/doc/dox/config/pipewire.conf.5.md 2024-04-15 07:33:15.000000000 +0000 @@ -247,6 +247,11 @@ Any property in the vm.overrides property object will override the property in the context.properties when PipeWire detects it is running in a VM. +@PAR@ pipewire.conf context.modules.allow-empty = false +By default, a warning is logged when there are no context.modules loaded because this +likely indicates there is a problem. Some applications might load the modules themselves +and when they set this property to true, no warning will be logged. + The context properties may also contain custom values. For example, the `context.modules` and `context.objects` sections can declare additional conditions that control whether a module or object is loaded diff -Nru pipewire-1.0.4/doc/meson.build pipewire-1.0.5/doc/meson.build --- pipewire-1.0.4/doc/meson.build 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/doc/meson.build 2024-04-15 07:33:15.000000000 +0000 @@ -7,14 +7,33 @@ doxyfile_conf.set('top_builddir', meson.project_build_root()) doxyfile_conf.set('output_directory', meson.current_build_dir()) +doc_prefix_value = get_option('doc-prefix-value') +doc_sysconfdir_value = get_option('doc-sysconfdir-value') + +if doc_prefix_value == '' and doc_sysconfdir_value == '' + doc_spa_plugindir = spa_plugindir + doc_pipewire_configdir = pipewire_configdir + doc_pipewire_confdatadir = pipewire_confdatadir +else + if doc_prefix_value == '' + doc_prefix_value = get_option('prefix') + endif + if doc_sysconfdir_value == '' + doc_sysconfdir_value = get_option('sysconfdir') + endif + doc_spa_plugindir = doc_prefix_value / get_option('libdir') / spa_name + doc_pipewire_configdir = doc_prefix_value / doc_sysconfdir_value / 'pipewire' + doc_pipewire_confdatadir = doc_prefix_value / get_option('datadir') / 'pipewire' +endif + doxygen_env = environment() doxygen_env.set('PACKAGE_NAME', meson.project_name()) doxygen_env.set('PACKAGE_VERSION', meson.project_version()) doxygen_env.set('PACKAGE_URL', 'https://pipewire.org') doxygen_env.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/pipewire/pipewire/issues') -doxygen_env.set('PIPEWIRE_CONFIG_DIR', pipewire_configdir) -doxygen_env.set('PIPEWIRE_CONFDATADIR', pipewire_confdatadir) -doxygen_env.set('SPA_PLUGINDIR', spa_plugindir) +doxygen_env.set('PIPEWIRE_CONFIG_DIR', doc_pipewire_configdir) +doxygen_env.set('PIPEWIRE_CONFDATADIR', doc_pipewire_confdatadir) +doxygen_env.set('SPA_PLUGINDIR', doc_spa_plugindir) doxygen_env.set('BUILD_DIR', meson.current_build_dir()) dot_found = find_program('dot', required: false).found() diff -Nru pipewire-1.0.4/meson.build pipewire-1.0.5/meson.build --- pipewire-1.0.4/meson.build 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/meson.build 2024-04-15 07:33:15.000000000 +0000 @@ -1,5 +1,5 @@ project('pipewire', ['c' ], - version : '1.0.4', + version : '1.0.5', license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ], meson_version : '>= 0.61.1', default_options : [ 'warning_level=3', diff -Nru pipewire-1.0.4/meson_options.txt pipewire-1.0.5/meson_options.txt --- pipewire-1.0.4/meson_options.txt 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/meson_options.txt 2024-04-15 07:33:15.000000000 +0000 @@ -342,3 +342,11 @@ description: 'Enable code that depends on libffado', type: 'feature', value: 'auto') +option('doc-prefix-value', + description : 'Installation prefix to show in documentation instead of the actual value.', + type : 'string', + value : '') +option('doc-sysconfdir-value', + description : 'Sysconf data directory to show in documentation instead of the actual value.', + type : 'string', + value : '') diff -Nru pipewire-1.0.4/pipewire-v4l2/src/meson.build pipewire-1.0.5/pipewire-v4l2/src/meson.build --- pipewire-1.0.4/pipewire-v4l2/src/meson.build 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/pipewire-v4l2/src/meson.build 2024-04-15 07:33:15.000000000 +0000 @@ -12,6 +12,7 @@ '-U_FILE_OFFSET_BITS', '-D_FILE_OFFSET_BITS=32', '-D_LARGEFILE64_SOURCE', + '-U_TIME_BITS', '-fvisibility=hidden', ] diff -Nru pipewire-1.0.4/spa/include/spa/support/log-impl.h pipewire-1.0.5/spa/include/spa/support/log-impl.h --- pipewire-1.0.4/spa/include/spa/support/log-impl.h 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/include/spa/support/log-impl.h 2024-04-15 07:33:15.000000000 +0000 @@ -108,6 +108,7 @@ spa_log_impl_logv, \ spa_log_impl_logt, \ spa_log_impl_logtv, \ + spa_log_impl_topic_init, \ } } #define SPA_LOG_IMPL(name) \ diff -Nru pipewire-1.0.4/spa/include/spa/utils/cleanup.h pipewire-1.0.5/spa/include/spa/utils/cleanup.h --- pipewire-1.0.4/spa/include/spa/utils/cleanup.h 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/include/spa/utils/cleanup.h 2024-04-15 07:33:15.000000000 +0000 @@ -7,10 +7,10 @@ #define spa_exchange(var, new_value) \ __extension__ ({ \ - __typeof__(var) *_ptr = &(var); \ - __typeof__(var) _old_value = *_ptr; \ - *_ptr = (new_value); \ - _old_value; \ + __typeof__(var) *_ptr_ = &(var); \ + __typeof__(var) _old_value_ = *_ptr_; \ + *_ptr_ = (new_value); \ + _old_value_; \ }) /* ========================================================================== */ diff -Nru pipewire-1.0.4/spa/include/spa/utils/json.h pipewire-1.0.5/spa/include/spa/utils/json.h --- pipewire-1.0.4/spa/include/spa/utils/json.h 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/include/spa/utils/json.h 2024-04-15 07:33:15.000000000 +0000 @@ -339,7 +339,7 @@ return -1; if (!spa_json_is_string(val, len)) { if (result != val) - strncpy(result, val, len); + memmove(result, val, len); result += len; } else { for (p = val+1; p < val + len; p++) { diff -Nru pipewire-1.0.4/spa/plugins/alsa/90-pipewire-alsa.rules pipewire-1.0.5/spa/plugins/alsa/90-pipewire-alsa.rules --- pipewire-1.0.4/spa/plugins/alsa/90-pipewire-alsa.rules 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/alsa/90-pipewire-alsa.rules 2024-04-15 07:33:15.000000000 +0000 @@ -133,6 +133,8 @@ ATTRS{idVendor}=="2f12", ATTRS{idProduct}=="0109", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" # ID 9886:002c is for the Astro A50 Gen4 ATTRS{idVendor}=="9886", ATTRS{idProduct}=="002c", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" +# ID 9886:0038 is for the Astro Mixamp Pro TR +ATTRS{idVendor}=="9886", ATTRS{idProduct}=="0038", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" # ID 9886:0045 is for the Astro A20 Gen2 ATTRS{idVendor}=="9886", ATTRS{idProduct}=="0045", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" # ID 1532:0520 is for the Razer Kraken Tournament Edition diff -Nru pipewire-1.0.4/spa/plugins/alsa/acp/alsa-util.c pipewire-1.0.5/spa/plugins/alsa/acp/alsa-util.c --- pipewire-1.0.4/spa/plugins/alsa/acp/alsa-util.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/alsa/acp/alsa-util.c 2024-04-15 07:33:15.000000000 +0000 @@ -929,7 +929,7 @@ } void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) { - char *cn, *lcn, *dn; + char *cn, *lcn, *dn, name[64]; pa_assert(p); pa_assert(card >= 0); @@ -951,6 +951,9 @@ pa_xfree(dn); } + snprintf(name, sizeof(name), "hw:%d", card); + pa_alsa_init_proplist_ctl(p, name); + #ifdef HAVE_UDEV pa_udev_get_info(card, p); #endif @@ -1037,7 +1040,6 @@ pa_alsa_init_proplist_pcm_info(c, p, info); } -#if 0 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name) { int err; snd_ctl_t *ctl; @@ -1065,9 +1067,13 @@ if ((t = snd_ctl_card_info_get_components(info)) && *t) pa_proplist_sets(p, "alsa.components", t); + if ((t = snd_ctl_card_info_get_id(info)) && *t) + pa_proplist_sets(p, "alsa.id", t); + snd_ctl_close(ctl); } +#if 0 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents) { snd_pcm_state_t state; snd_pcm_hw_params_t *hwparams; diff -Nru pipewire-1.0.4/spa/plugins/alsa/acp/alsa-util.h pipewire-1.0.5/spa/plugins/alsa/acp/alsa-util.h --- pipewire-1.0.4/spa/plugins/alsa/acp/alsa-util.h 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/alsa/acp/alsa-util.h 2024-04-15 07:33:15.000000000 +0000 @@ -123,9 +123,7 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info); void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card); void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm); -#if 0 void pa_alsa_init_proplist_ctl(pa_proplist *p, const char *name); -#endif bool pa_alsa_init_description(pa_proplist *p, pa_card *card); #if 0 diff -Nru pipewire-1.0.4/spa/plugins/alsa/alsa-pcm.c pipewire-1.0.5/spa/plugins/alsa/alsa-pcm.c --- pipewire-1.0.4/spa/plugins/alsa/alsa-pcm.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/alsa/alsa-pcm.c 2024-04-15 07:33:15.000000000 +0000 @@ -642,45 +642,85 @@ static void bind_ctl_event(struct spa_source *source) { - // We don't know if a bound element changed or not, so let's find out struct state *state = source->data; + snd_ctl_event_t *ev; + snd_ctl_elem_id_t *id, *bound_id; snd_ctl_elem_value_t *old_value; - bool changed = false; + unsigned short revents; + int err; - snd_ctl_elem_value_alloca(&old_value); + // Do the same demangling of revents we do for PCM pollfds + for (int i = 0; i < state->ctl_n_fds; i++) { + state->ctl_pfds[i].revents = state->ctl_sources[i].rmask; + state->ctl_sources[i].rmask = 0; + } - for (unsigned int i = 0; i < state->num_bind_ctls; i++) { - int err; + err = snd_ctl_poll_descriptors_revents(state->ctl, state->ctl_pfds, state->ctl_n_fds, &revents); + if (SPA_UNLIKELY(err < 0)) { + spa_log_warn(state->log, "Could not read ctl revents: %s", snd_strerror(err)); + return; + } - snd_ctl_elem_value_copy(old_value, state->bound_ctls[i].value); + if (!revents) { + spa_log_trace(state->log, "Got a bind ctl wakeup but no actual event"); + return; + } - err = snd_ctl_elem_read(state->ctl, state->bound_ctls[i].value); - if (err < 0) { - spa_log_warn(state->log, "Could not read ctl '%s': %s", - state->bound_ctls[i].name, snd_strerror(err)); + snd_ctl_event_alloca(&ev); + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_id_alloca(&bound_id); + snd_ctl_elem_value_alloca(&old_value); + + while ((err = snd_ctl_read(state->ctl, ev) > 0)) { + bool changed = false; + + if (snd_ctl_event_get_type(ev) != SND_CTL_EVENT_ELEM) continue; + + snd_ctl_event_elem_get_id(ev, id); + + for (unsigned int i = 0; i < state->num_bind_ctls; i++) { + int err; + + // Check if we have the right element + snd_ctl_elem_value_get_id(state->bound_ctls[i].value, bound_id); + if (snd_ctl_elem_id_compare_set(id, bound_id) || + snd_ctl_elem_id_compare_numid(id, bound_id)) { + continue; + } + + snd_ctl_elem_value_copy(old_value, state->bound_ctls[i].value); + + err = snd_ctl_elem_read(state->ctl, state->bound_ctls[i].value); + if (err < 0) { + spa_log_warn(state->log, "Could not read ctl '%s': %s", + state->bound_ctls[i].name, snd_strerror(err)); + continue; + } + + if (snd_ctl_elem_value_compare(old_value, state->bound_ctls[i].value) != 0) { + // We don't need to check all the ctls, if one changed, + // we'll emit a notification and they'll be read when + // the props are read + spa_log_debug(state->log, "bound ctl '%s' has changed", state->bound_ctls[i].name); + changed = true; + break; + } } - if (snd_ctl_elem_value_compare(old_value, state->bound_ctls[i].value) != 0) { - // We don't need to check all the ctls, if one changed, - // we'll emit a notification and they'll be read when - // the props are read - spa_log_debug(state->log, "bound ctl '%s' has changed", state->bound_ctls[i].name); - changed = true; - break; + if (changed) { + state->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + state->params[NODE_Props].user++; + spa_alsa_emit_node_info(state, false); } } - if (changed) { - state->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; - state->params[NODE_Props].user++; - spa_alsa_emit_node_info(state, false); - } + if (err < 0 && err != -EAGAIN) + spa_log_warn(state->log, "Could not read ctl: %s", snd_strerror(err)); } static void bind_ctls_for_params(struct state *state) { - struct pollfd pfds[16]; int err; if (state->num_bind_ctls == 0) @@ -706,7 +746,7 @@ state->ctl_n_fds = SPA_N_ELEMENTS(state->ctl_sources); } - if ((err = snd_ctl_poll_descriptors(state->ctl, pfds, state->ctl_n_fds)) < 0) { + if ((err = snd_ctl_poll_descriptors(state->ctl, state->ctl_pfds, state->ctl_n_fds)) < 0) { spa_log_warn(state->log, "Could not get poll descriptors: %s", snd_strerror(err)); return; } @@ -716,7 +756,7 @@ for (int i = 0; i < state->ctl_n_fds; i++) { state->ctl_sources[i].func = bind_ctl_event; state->ctl_sources[i].data = state; - state->ctl_sources[i].fd = pfds[i].fd; + state->ctl_sources[i].fd = state->ctl_pfds[i].fd; state->ctl_sources[i].mask = SPA_IO_IN; state->ctl_sources[i].rmask = 0; spa_loop_add_source(state->main_loop, &state->ctl_sources[i]); diff -Nru pipewire-1.0.4/spa/plugins/alsa/alsa-pcm.h pipewire-1.0.5/spa/plugins/alsa/alsa-pcm.h --- pipewire-1.0.4/spa/plugins/alsa/alsa-pcm.h 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/alsa/alsa-pcm.h 2024-04-15 07:33:15.000000000 +0000 @@ -258,6 +258,7 @@ /* ALSA ctls exposed as params */ unsigned int num_bind_ctls; struct bound_ctl bound_ctls[16]; + struct pollfd ctl_pfds[MAX_POLL]; struct spa_source ctl_sources[MAX_POLL]; int ctl_n_fds; diff -Nru pipewire-1.0.4/spa/plugins/alsa/alsa-udev.c pipewire-1.0.5/spa/plugins/alsa/alsa-udev.c --- pipewire-1.0.4/spa/plugins/alsa/alsa-udev.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/alsa/alsa-udev.c 2024-04-15 07:33:15.000000000 +0000 @@ -92,6 +92,7 @@ struct spa_source source; struct spa_source notify; unsigned int use_acp:1; + unsigned int expose_busy:1; }; static int impl_udev_open(struct impl *this) @@ -381,6 +382,8 @@ */ res = 0; + if (this->expose_busy) + return res; spa_scnprintf(path, sizeof(path), "/proc/asound/card%u", card->card_nr); @@ -1141,6 +1144,8 @@ if (info) { if ((str = spa_dict_lookup(info, "alsa.use-acp")) != NULL) this->use_acp = spa_atob(str); + else if ((str = spa_dict_lookup(info, "alsa.udev.expose-busy")) != NULL) + this->expose_busy = spa_atob(str); } return 0; diff -Nru pipewire-1.0.4/spa/plugins/audioconvert/audioconvert.c pipewire-1.0.5/spa/plugins/audioconvert/audioconvert.c --- pipewire-1.0.4/spa/plugins/audioconvert/audioconvert.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/audioconvert/audioconvert.c 2024-04-15 07:33:15.000000000 +0000 @@ -1826,6 +1826,52 @@ return 0; } +static uint32_t resample_update_rate_match(struct impl *this, bool passthrough, uint32_t size, uint32_t queued) +{ + uint32_t delay, match_size; + + if (passthrough) { + delay = 0; + match_size = size; + } else { + double rate = this->rate_scale / this->props.rate; + if (this->io_rate_match && + SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) + rate *= this->io_rate_match->rate; + resample_update_rate(&this->resample, rate); + delay = resample_delay(&this->resample); + if (this->direction == SPA_DIRECTION_INPUT) + match_size = resample_in_len(&this->resample, size); + else + match_size = resample_out_len(&this->resample, size); + } + match_size -= SPA_MIN(match_size, queued); + + spa_log_trace_fp(this->log, "%p: next match %u", this, match_size); + + if (this->io_rate_match) { + this->io_rate_match->delay = delay + queued; + this->io_rate_match->size = match_size; + } + return match_size; +} + +static inline bool resample_is_passthrough(struct impl *this) +{ + if (this->props.resample_disabled) + return true; + if (this->resample.i_rate != this->resample.o_rate) + return false; + if (this->rate_scale != 1.0) + return false; + if (this->rate_adjust) + return false; + if (this->io_rate_match != NULL && + SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) + return false; + return true; +} + static int setup_convert(struct impl *this) { struct dir *in, *out; @@ -2765,49 +2811,6 @@ return match_size; } -static uint32_t resample_update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued) -{ - uint32_t delay, match_size; - - if (passthrough) { - delay = 0; - match_size = out_size; - } else { - double rate = this->rate_scale / this->props.rate; - if (this->io_rate_match && - SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) - rate *= this->io_rate_match->rate; - resample_update_rate(&this->resample, rate); - delay = resample_delay(&this->resample); - match_size = resample_in_len(&this->resample, out_size); - } - match_size -= SPA_MIN(match_size, in_queued); - - spa_log_trace_fp(this->log, "%p: next match %u", this, match_size); - - if (this->io_rate_match) { - this->io_rate_match->delay = delay + in_queued; - this->io_rate_match->size = match_size; - } - return match_size; -} - -static inline bool resample_is_passthrough(struct impl *this) -{ - if (this->props.resample_disabled) - return true; - if (this->resample.i_rate != this->resample.o_rate) - return false; - if (this->rate_scale != 1.0) - return false; - if (this->rate_adjust) - return false; - if (this->io_rate_match != NULL && - SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) - return false; - return true; -} - static uint64_t get_time_ns(struct impl *impl) { struct timespec now; @@ -3272,10 +3275,20 @@ spa_log_trace_fp(this->log, "%p: no output buffer", this); } } - if (resample_update_rate_match(this, resample_passthrough, - max_out - this->out_offset, - max_in - this->in_offset) > 0) - res |= SPA_STATUS_NEED_DATA; + { + uint32_t size, queued; + + if (this->direction == SPA_DIRECTION_INPUT) { + size = max_out - this->out_offset; + queued = max_in - this->in_offset; + } else { + size = quant_samples; + queued = 0; + } + if (resample_update_rate_match(this, resample_passthrough, + size, queued) > 0) + res |= SPA_STATUS_NEED_DATA; + } return res; } diff -Nru pipewire-1.0.4/spa/plugins/audioconvert/resample-native.c pipewire-1.0.5/spa/plugins/audioconvert/resample-native.c --- pipewire-1.0.4/spa/plugins/audioconvert/resample-native.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/audioconvert/resample-native.c 2024-04-15 07:33:15.000000000 +0000 @@ -188,6 +188,20 @@ return in_len; } +static uint32_t impl_native_out_len(struct resample *r, uint32_t in_len) +{ + struct native_data *data = r->data; + uint32_t out_len; + + in_len = in_len - SPA_MIN(in_len, (data->n_taps - data->hist) + 1); + out_len = in_len * data->out_rate - data->phase; + out_len = (out_len + data->in_rate - 1) / data->in_rate; + + spa_log_trace_fp(r->log, "native %p: hist:%d %d->%d", r, data->hist, in_len, out_len); + + return out_len; +} + static void impl_native_process(struct resample *r, const void * SPA_RESTRICT src[], uint32_t *in_len, void * SPA_RESTRICT dst[], uint32_t *out_len) @@ -310,6 +324,7 @@ r->free = impl_native_free; r->update_rate = impl_native_update_rate; r->in_len = impl_native_in_len; + r->out_len = impl_native_out_len; r->process = impl_native_process; r->reset = impl_native_reset; r->delay = impl_native_delay; diff -Nru pipewire-1.0.4/spa/plugins/audioconvert/resample-peaks.c pipewire-1.0.5/spa/plugins/audioconvert/resample-peaks.c --- pipewire-1.0.4/spa/plugins/audioconvert/resample-peaks.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/audioconvert/resample-peaks.c 2024-04-15 07:33:15.000000000 +0000 @@ -89,6 +89,11 @@ return out_len; } +static uint32_t impl_peaks_out_len(struct resample *r, uint32_t in_len) +{ + return in_len; +} + static void impl_peaks_reset (struct resample *r) { struct peaks_data *d = r->data; @@ -119,6 +124,7 @@ r->reset = impl_peaks_reset; r->delay = impl_peaks_delay; r->in_len = impl_peaks_in_len; + r->out_len = impl_peaks_out_len; spa_log_debug(r->log, "peaks %p: in:%d out:%d features:%08x:%08x", r, r->i_rate, r->o_rate, r->cpu_flags, d->peaks.cpu_flags); diff -Nru pipewire-1.0.4/spa/plugins/bluez5/bluez5-dbus.c pipewire-1.0.5/spa/plugins/bluez5/bluez5-dbus.c --- pipewire-1.0.4/spa/plugins/bluez5/bluez5-dbus.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/bluez5/bluez5-dbus.c 2024-04-15 07:33:15.000000000 +0000 @@ -5328,6 +5328,11 @@ return; } + if (dbus_message_is_error(r, DBUS_ERROR_NAME_HAS_NO_OWNER)) { + spa_log_warn(monitor->log, "BlueZ system service is not available"); + return; + } + if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { spa_log_error(monitor->log, "GetManagedObjects() failed: %s", dbus_message_get_error_name(r)); diff -Nru pipewire-1.0.4/spa/plugins/support/node-driver.c pipewire-1.0.5/spa/plugins/support/node-driver.c --- pipewire-1.0.4/spa/plugins/support/node-driver.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/support/node-driver.c 2024-04-15 07:33:15.000000000 +0000 @@ -8,7 +8,7 @@ #include #include #include -#if !defined(__FreeBSD__) && !defined(__MidnightBSD__) +#ifdef __linux__ #include #include #endif diff -Nru pipewire-1.0.4/spa/plugins/support/null-audio-sink.c pipewire-1.0.5/spa/plugins/support/null-audio-sink.c --- pipewire-1.0.4/spa/plugins/support/null-audio-sink.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/support/null-audio-sink.c 2024-04-15 07:33:15.000000000 +0000 @@ -37,7 +37,6 @@ uint32_t format; uint32_t channels; uint32_t rate; - uint32_t n_pos; uint32_t pos[SPA_AUDIO_MAX_CHANNELS]; char clock_name[64]; unsigned int debug:1; @@ -49,7 +48,6 @@ props->format = 0; props->channels = 0; props->rate = 0; - props->n_pos = 0; strncpy(props->clock_name, DEFAULT_CLOCK_NAME, sizeof(props->clock_name)); props->debug = false; props->driver = true; @@ -469,10 +467,10 @@ SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(DEFAULT_CHANNELS, 1, INT32_MAX), 0); } - if (this->props.n_pos != 0) { + if (this->props.channels != 0) { spa_pod_builder_prop(builder, SPA_FORMAT_AUDIO_position, 0); spa_pod_builder_array(builder, sizeof(uint32_t), SPA_TYPE_Id, - this->props.n_pos, this->props.pos); + this->props.channels, this->props.pos); } *param = spa_pod_builder_pop(builder, &f[0]); break; @@ -888,10 +886,10 @@ if (spa_json_enter_array(&it[0], &it[1]) <= 0) spa_json_init(&it[1], val, len); - this->props.n_pos = 0; + this->props.channels = 0; while (spa_json_get_string(&it[1], v, sizeof(v)) > 0 && - this->props.n_pos < SPA_AUDIO_MAX_CHANNELS) { - this->props.pos[this->props.n_pos++] = channel_from_name(v); + this->props.channels < SPA_AUDIO_MAX_CHANNELS) { + this->props.pos[this->props.channels++] = channel_from_name(v); } } @@ -991,9 +989,6 @@ "%s", s); } } - if (this->props.n_pos > 0) - this->props.channels = this->props.n_pos; - spa_log_info(this->log, NAME " %p: initialized", this); return 0; diff -Nru pipewire-1.0.4/spa/plugins/v4l2/v4l2-source.c pipewire-1.0.5/spa/plugins/v4l2/v4l2-source.c --- pipewire-1.0.4/spa/plugins/v4l2/v4l2-source.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/v4l2/v4l2-source.c 2024-04-15 07:33:15.000000000 +0000 @@ -82,7 +82,6 @@ bool have_format; struct spa_video_info current_format; - struct spa_fraction rate; struct spa_v4l2_device dev; @@ -696,11 +695,19 @@ done: this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->params[PORT_Latency].flags ^= SPA_PARAM_INFO_SERIAL; if (port->have_format) { + uint64_t latency; + latency = port->info.rate.num * SPA_NSEC_PER_SEC / port->info.rate.denom; + this->latency[SPA_DIRECTION_OUTPUT] = + SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT, + .min_ns = latency, + .max_ns = latency); port->params[PORT_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE); port->params[PORT_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ); this->params[NODE_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READ); } else { + this->latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); port->params[PORT_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); port->params[PORT_Buffers] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); this->params[NODE_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, 0); diff -Nru pipewire-1.0.4/spa/plugins/v4l2/v4l2-utils.c pipewire-1.0.5/spa/plugins/v4l2/v4l2-utils.c --- pipewire-1.0.4/spa/plugins/v4l2/v4l2-utils.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/spa/plugins/v4l2/v4l2-utils.c 2024-04-15 07:33:15.000000000 +0000 @@ -386,9 +386,8 @@ return -ENOENT; val = spa_pod_get_values(&p->value, &n_values, &choice); - - if (val->type != SPA_TYPE_Id) - return -EINVAL; + if (val->type != SPA_TYPE_Id || n_values == 0) + return SPA_VIDEO_FORMAT_UNKNOWN; values = SPA_POD_BODY(val); @@ -614,7 +613,7 @@ goto do_frmsize; val = spa_pod_get_values(&p->value, &n_vals, &choice); - if (val->type != SPA_TYPE_Rectangle) + if (val->type != SPA_TYPE_Rectangle || n_vals == 0) goto enum_end; if (choice == SPA_CHOICE_None) { @@ -652,7 +651,7 @@ goto have_size; val = spa_pod_get_values(&p->value, &n_values, &choice); - if (val->type != SPA_TYPE_Rectangle) + if (val->type != SPA_TYPE_Rectangle || n_values == 0) goto have_size; values = SPA_POD_BODY_CONST(val); @@ -772,8 +771,7 @@ goto have_framerate; val = spa_pod_get_values(&p->value, &n_values, &choice); - - if (val->type != SPA_TYPE_Fraction) + if (val->type != SPA_TYPE_Fraction || n_values == 0) goto enum_end; values = SPA_POD_BODY(val); @@ -1012,10 +1010,6 @@ dev->have_format = true; size->width = fmt.fmt.pix.width; size->height = fmt.fmt.pix.height; - port->rate.denom = framerate->num = streamparm.parm.capture.timeperframe.denominator; - port->rate.num = framerate->denom = streamparm.parm.capture.timeperframe.numerator; - - probe_expbuf(this); port->fmt = fmt; port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_RATE; @@ -1023,7 +1017,10 @@ SPA_PORT_FLAG_LIVE | SPA_PORT_FLAG_PHYSICAL | SPA_PORT_FLAG_TERMINAL; - port->info.rate = SPA_FRACTION(port->rate.num, port->rate.denom); + port->info.rate.num = streamparm.parm.capture.timeperframe.numerator; + port->info.rate.denom = streamparm.parm.capture.timeperframe.denominator; + + probe_expbuf(this); return match ? 0 : 1; } @@ -1370,22 +1367,27 @@ if (xioctl(dev->fd, VIDIOC_DQBUF, &buf) < 0) return -errno; + /* Drop the first frame in order to work around common firmware + * timestamp issues */ + if (buf.sequence == 0) + return 0; + pts = SPA_TIMEVAL_TO_NSEC(&buf.timestamp); spa_log_trace(this->log, "v4l2 %p: have output %d", this, buf.index); if (this->clock) { /* FIXME, we should follow the driver clock and target_ values. * for now we ignore and use our own. */ - this->clock->target_rate = port->rate; + this->clock->target_rate = port->info.rate; this->clock->target_duration = 1; this->clock->nsec = pts; - this->clock->rate = port->rate; + this->clock->rate = port->info.rate; this->clock->position = buf.sequence; this->clock->duration = 1; this->clock->delay = 0; this->clock->rate_diff = 1.0; - this->clock->next_nsec = pts + 1000000000LL / port->rate.denom; + this->clock->next_nsec = pts + port->info.rate.num * SPA_NSEC_PER_SEC / port->info.rate.denom; } b = &port->buffers[buf.index]; diff -Nru pipewire-1.0.4/src/gst/gstpipewireformat.c pipewire-1.0.5/src/gst/gstpipewireformat.c --- pipewire-1.0.4/src/gst/gstpipewireformat.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/gst/gstpipewireformat.c 2024-04-15 07:33:15.000000000 +0000 @@ -729,7 +729,7 @@ uint32_t i, n_items, choice; val = spa_pod_get_values(&prop->value, &n_items, &choice); - if (val->type != SPA_TYPE_Id) + if (val->type != SPA_TYPE_Id || n_items == 0) return; id = SPA_POD_BODY(val); @@ -770,7 +770,7 @@ uint32_t i, n_items, choice; val = spa_pod_get_values(&prop->value, &n_items, &choice); - if (val->type != SPA_TYPE_Int) + if (val->type != SPA_TYPE_Int || n_items == 0) return; ints = SPA_POD_BODY(val); @@ -814,7 +814,7 @@ uint32_t i, n_items, choice; val = spa_pod_get_values(&prop->value, &n_items, &choice); - if (val->type != SPA_TYPE_Rectangle) + if (val->type != SPA_TYPE_Rectangle || n_items == 0) return; rect = SPA_POD_BODY(val); @@ -867,7 +867,7 @@ uint32_t i, n_items, choice; val = spa_pod_get_values(&prop->value, &n_items, &choice); - if (val->type != SPA_TYPE_Fraction) + if (val->type != SPA_TYPE_Fraction || n_items == 0) return; fract = SPA_POD_BODY(val); diff -Nru pipewire-1.0.4/src/gst/gstpipewiresrc.c pipewire-1.0.5/src/gst/gstpipewiresrc.c --- pipewire-1.0.4/src/gst/gstpipewiresrc.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/gst/gstpipewiresrc.c 2024-04-15 07:33:15.000000000 +0000 @@ -586,6 +586,9 @@ GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) + h->dts_offset; } GST_BUFFER_OFFSET (buf) = h->seq; + } else { + GST_BUFFER_PTS (buf) = b->time; + GST_BUFFER_DTS (buf) = b->time; } crop = data->crop; if (crop) { diff -Nru pipewire-1.0.4/src/modules/module-client-node/client-node.c pipewire-1.0.5/src/modules/module-client-node/client-node.c --- pipewire-1.0.4/src/modules/module-client-node/client-node.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/modules/module-client-node/client-node.c 2024-04-15 07:33:15.000000000 +0000 @@ -692,14 +692,18 @@ direction == SPA_DIRECTION_INPUT ? "input" : "output", port_id, mix_id, data, size); + old = pw_mempool_find_tag(impl->client_pool, tag, sizeof(tag)); + port = GET_PORT(impl, direction, port_id); - if (port == NULL) + if (port == NULL) { + pw_memmap_free(old); return data == NULL ? 0 : -EINVAL; + } - if ((mix = find_mix(port, mix_id)) == NULL) + if ((mix = find_mix(port, mix_id)) == NULL) { + pw_memmap_free(old); return -EINVAL; - - old = pw_mempool_find_tag(impl->client_pool, tag, sizeof(tag)); + } if (data) { mm = pw_mempool_import_map(impl->client_pool, @@ -1511,7 +1515,7 @@ if (port->direction != direction) return -ENOTSUP; - return impl_node_port_enum_params(&port->impl->node, seq, direction, port->id, + return impl_node_port_enum_params(port->impl, seq, direction, port->id, id, start, num, filter); } @@ -1583,7 +1587,7 @@ impl_mix_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id) { struct port *p = object; - return impl_node_port_reuse_buffer(&p->impl->node, p->id, buffer_id); + return impl_node_port_reuse_buffer(p->impl, p->id, buffer_id); } static int impl_mix_process(void *object) diff -Nru pipewire-1.0.4/src/modules/module-client-node/remote-node.c pipewire-1.0.5/src/modules/module-client-node/remote-node.c --- pipewire-1.0.4/src/modules/module-client-node/remote-node.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/modules/module-client-node/remote-node.c 2024-04-15 07:33:15.000000000 +0000 @@ -122,6 +122,7 @@ { struct link *l; uint32_t tag[5] = { data->remote_id, }; + struct pw_impl_node *node = data->node; struct pw_memmap *mm; if (!data->have_transport) @@ -132,13 +133,13 @@ while ((mm = pw_mempool_find_tag(data->pool, tag, sizeof(uint32_t))) != NULL) { if (mm->tag[1] == SPA_ID_INVALID) - spa_node_set_io(data->node->node, mm->tag[2], NULL, 0); + spa_node_set_io(node->node, mm->tag[2], NULL, 0); pw_memmap_free(mm); } pw_memmap_free(data->activation); - data->node->rt.target.activation = data->node->activation->map->ptr; + node->rt.target.activation = node->activation->map->ptr; spa_system_close(data->data_system, data->rtwritefd); data->have_transport = false; @@ -397,6 +398,7 @@ uint32_t size) { struct node_data *data = _data; + struct pw_impl_node *node = data->node; struct pw_proxy *proxy = (struct pw_proxy*)data->client_node; struct pw_memmap *old, *mm; void *ptr; @@ -430,10 +432,10 @@ data->position = size >= sizeof(*data->position) ? ptr : NULL; break; } - data->node->driving = data->clock && data->position && + node->driving = data->clock && data->position && data->position->clock.id == data->clock->id; - res = spa_node_set_io(data->node->node, id, ptr, size); + res = spa_node_set_io(node->node, id, ptr, size); pw_memmap_free(old); exit: @@ -455,6 +457,7 @@ static int client_node_command(void *_data, const struct spa_command *command) { struct node_data *data = _data; + struct pw_impl_node *node = data->node; struct pw_proxy *proxy = (struct pw_proxy*)data->client_node; int res; uint32_t id = SPA_NODE_COMMAND_ID(command); @@ -464,27 +467,27 @@ switch (id) { case SPA_NODE_COMMAND_Pause: - if ((res = pw_impl_node_set_state(data->node, PW_NODE_STATE_IDLE)) < 0) { + if ((res = pw_impl_node_set_state(node, PW_NODE_STATE_IDLE)) < 0) { pw_log_warn("node %p: pause failed", proxy); pw_proxy_error(proxy, res, "pause failed"); } break; case SPA_NODE_COMMAND_Start: - if ((res = pw_impl_node_set_state(data->node, PW_NODE_STATE_RUNNING)) < 0) { + if ((res = pw_impl_node_set_state(node, PW_NODE_STATE_RUNNING)) < 0) { pw_log_warn("node %p: start failed", proxy); pw_proxy_error(proxy, res, "start failed"); } break; case SPA_NODE_COMMAND_Suspend: - if ((res = pw_impl_node_set_state(data->node, PW_NODE_STATE_SUSPENDED)) < 0) { + if ((res = pw_impl_node_set_state(node, PW_NODE_STATE_SUSPENDED)) < 0) { pw_log_warn("node %p: suspend failed", proxy); pw_proxy_error(proxy, res, "suspend failed"); } break; case SPA_NODE_COMMAND_RequestProcess: - res = pw_impl_node_send_command(data->node, command); + res = pw_impl_node_send_command(node, command); break; default: pw_log_warn("unhandled node command %d (%s)", id, @@ -950,28 +953,29 @@ static void do_node_init(struct node_data *data) { + struct pw_impl_node *node = data->node; struct pw_impl_port *port; struct mix *mix; - pw_log_debug("%p: node %p init", data, data->node); + pw_log_debug("%p: node %p init", data, node); add_node_update(data, PW_CLIENT_NODE_UPDATE_PARAMS | PW_CLIENT_NODE_UPDATE_INFO, SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PROPS | SPA_NODE_CHANGE_MASK_PARAMS); - spa_list_for_each(port, &data->node->input_ports, link) { + spa_list_for_each(port, &node->input_ports, link) { mix = create_mix(data, port, SPA_ID_INVALID, SPA_ID_INVALID); if (mix == NULL) - pw_log_error("%p: failed to create port mix: %m", data->node); + pw_log_error("%p: failed to create port mix: %m", node); add_port_update(data, port, PW_CLIENT_NODE_PORT_UPDATE_PARAMS | PW_CLIENT_NODE_PORT_UPDATE_INFO); } - spa_list_for_each(port, &data->node->output_ports, link) { + spa_list_for_each(port, &node->output_ports, link) { mix = create_mix(data, port, SPA_ID_INVALID, SPA_ID_INVALID); if (mix == NULL) - pw_log_error("%p: failed to create port mix: %m", data->node); + pw_log_error("%p: failed to create port mix: %m", node); add_port_update(data, port, PW_CLIENT_NODE_PORT_UPDATE_PARAMS | PW_CLIENT_NODE_PORT_UPDATE_INFO); @@ -1125,21 +1129,22 @@ static void client_node_removed(void *_data) { struct node_data *data = _data; + struct pw_impl_node *node = data->node; pw_log_debug("%p: removed", data); spa_hook_remove(&data->proxy_client_node_listener); spa_hook_remove(&data->client_node_listener); - if (data->node) { + if (node) { spa_hook_remove(&data->node_listener); - pw_impl_node_remove_rt_listener(data->node, + pw_impl_node_remove_rt_listener(node, &data->node_rt_listener); - pw_impl_node_set_state(data->node, PW_NODE_STATE_SUSPENDED); + pw_impl_node_set_state(node, PW_NODE_STATE_SUSPENDED); clean_node(data); if (data->do_free) - pw_impl_node_destroy(data->node); + pw_impl_node_destroy(node); } data->client_node = NULL; } diff -Nru pipewire-1.0.4/src/modules/module-echo-cancel.c pipewire-1.0.5/src/modules/module-echo-cancel.c --- pipewire-1.0.4/src/modules/module-echo-cancel.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/modules/module-echo-cancel.c 2024-04-15 07:33:15.000000000 +0000 @@ -524,17 +524,38 @@ enum pw_stream_state state, const char *error) { struct impl *impl = data; + int res; + switch (state) { case PW_STREAM_STATE_PAUSED: pw_stream_flush(impl->source, false); pw_stream_flush(impl->capture, false); + + if (old == PW_STREAM_STATE_STREAMING) { + if (pw_stream_get_state(impl->sink, NULL) != PW_STREAM_STATE_STREAMING) { + pw_log_debug("%p: deactivate %s", impl, impl->aec->name); + res = spa_audio_aec_deactivate(impl->aec); + if (res < 0 && res != -EOPNOTSUPP) { + pw_log_error("aec plugin %s deactivate failed: %s", impl->aec->name, spa_strerror(res)); + } + } + } + break; + case PW_STREAM_STATE_STREAMING: + if (pw_stream_get_state(impl->sink, NULL) == PW_STREAM_STATE_STREAMING) { + pw_log_debug("%p: activate %s", impl, impl->aec->name); + res = spa_audio_aec_activate(impl->aec); + if (res < 0 && res != -EOPNOTSUPP) { + pw_log_error("aec plugin %s activate failed: %s", impl->aec->name, spa_strerror(res)); + } + } break; case PW_STREAM_STATE_UNCONNECTED: - pw_log_info("%p: input unconnected", impl); + pw_log_info("%p: capture unconnected", impl); pw_impl_module_schedule_destroy(impl->module); break; case PW_STREAM_STATE_ERROR: - pw_log_info("%p: input error: %s", impl, error); + pw_log_info("%p: capture error: %s", impl, error); break; default: break; @@ -545,34 +566,18 @@ enum pw_stream_state state, const char *error) { struct impl *impl = data; - int res; switch (state) { case PW_STREAM_STATE_PAUSED: pw_stream_flush(impl->source, false); pw_stream_flush(impl->capture, false); - - if (old == PW_STREAM_STATE_STREAMING) { - pw_log_debug("%p: deactivate %s", impl, impl->aec->name); - res = spa_audio_aec_deactivate(impl->aec); - if (res < 0 && res != -EOPNOTSUPP) { - pw_log_error("aec plugin %s deactivate failed: %s", impl->aec->name, spa_strerror(res)); - } - } - break; - case PW_STREAM_STATE_STREAMING: - pw_log_debug("%p: activate %s", impl, impl->aec->name); - res = spa_audio_aec_activate(impl->aec); - if (res < 0 && res != -EOPNOTSUPP) { - pw_log_error("aec plugin %s activate failed: %s", impl->aec->name, spa_strerror(res)); - } break; case PW_STREAM_STATE_UNCONNECTED: - pw_log_info("%p: input unconnected", impl); + pw_log_info("%p: source unconnected", impl); pw_impl_module_schedule_destroy(impl->module); break; case PW_STREAM_STATE_ERROR: - pw_log_info("%p: input error: %s", impl, error); + pw_log_info("%p: source error: %s", impl, error); break; default: break; @@ -739,7 +744,7 @@ .param_changed = input_param_changed }; -static void output_state_changed(void *data, enum pw_stream_state old, +static void playback_state_changed(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { struct impl *impl = data; @@ -753,11 +758,55 @@ } break; case PW_STREAM_STATE_UNCONNECTED: - pw_log_info("%p: output unconnected", impl); + pw_log_info("%p: playback unconnected", impl); + pw_impl_module_schedule_destroy(impl->module); + break; + case PW_STREAM_STATE_ERROR: + pw_log_info("%p: playback error: %s", impl, error); + break; + default: + break; + } +} + +static void sink_state_changed(void *data, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + struct impl *impl = data; + int res; + + switch (state) { + case PW_STREAM_STATE_PAUSED: + pw_stream_flush(impl->sink, false); + if (impl->playback != NULL) + pw_stream_flush(impl->playback, false); + if (old == PW_STREAM_STATE_STREAMING) { + impl->current_delay = 0; + + if (pw_stream_get_state(impl->capture, NULL) != PW_STREAM_STATE_STREAMING) { + pw_log_debug("%p: deactivate %s", impl, impl->aec->name); + res = spa_audio_aec_deactivate(impl->aec); + if (res < 0 && res != -EOPNOTSUPP) { + pw_log_error("aec plugin %s deactivate failed: %s", impl->aec->name, spa_strerror(res)); + } + } + } + break; + case PW_STREAM_STATE_STREAMING: + if (pw_stream_get_state(impl->capture, NULL) == PW_STREAM_STATE_STREAMING) { + pw_log_debug("%p: activate %s", impl, impl->aec->name); + res = spa_audio_aec_activate(impl->aec); + if (res < 0 && res != -EOPNOTSUPP) { + pw_log_error("aec plugin %s activate failed: %s", impl->aec->name, spa_strerror(res)); + } + } + break; + case PW_STREAM_STATE_UNCONNECTED: + pw_log_info("%p: sink unconnected", impl); pw_impl_module_schedule_destroy(impl->module); break; case PW_STREAM_STATE_ERROR: - pw_log_info("%p: output error: %s", impl, error); + pw_log_info("%p: sink error: %s", impl, error); break; default: break; @@ -904,14 +953,14 @@ static const struct pw_stream_events playback_events = { PW_VERSION_STREAM_EVENTS, .destroy = playback_destroy, - .state_changed = output_state_changed, + .state_changed = playback_state_changed, .param_changed = output_param_changed }; static const struct pw_stream_events sink_events = { PW_VERSION_STREAM_EVENTS, .destroy = sink_destroy, .process = sink_process, - .state_changed = output_state_changed, + .state_changed = sink_state_changed, .param_changed = output_param_changed }; diff -Nru pipewire-1.0.4/src/modules/module-ffado-driver.c pipewire-1.0.5/src/modules/module-ffado-driver.c --- pipewire-1.0.4/src/modules/module-ffado-driver.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/modules/module-ffado-driver.c 2024-04-15 07:33:15.000000000 +0000 @@ -138,8 +138,15 @@ { PW_KEY_MODULE_VERSION, PACKAGE_VERSION }, }; +struct port_data { + struct port *port; +}; + struct port { enum spa_direction direction; + ffado_streaming_stream_type stream_type; + char name[280]; + struct spa_latency_info latency[2]; bool latency_changed[2]; unsigned int is_midi:1; @@ -153,6 +160,7 @@ uint32_t event_pos; int event_pending; + struct port_data *data; }; struct volume { @@ -238,6 +246,8 @@ unsigned int new_xrun:1; }; +static int stop_ffado_device(struct impl *impl); +static int start_ffado_device(struct impl *impl); static void schedule_reset_ffado_device(struct impl *impl); static void reset_volume(struct volume *vol, uint32_t n_volumes) @@ -491,37 +501,6 @@ return 0; } -static int start_ffado_device(struct impl *impl) -{ - if (impl->started) - return 0; - - if (ffado_streaming_start(impl->dev)) { - pw_log_warn("Could not start FFADO streaming, try reset"); - schedule_reset_ffado_device(impl); - return -EIO; - } - pw_log_info("FFADO started streaming"); - impl->started = true; - impl->done = true; - set_timeout(impl, get_time_ns(impl)); - return 0; -} - -static int stop_ffado_device(struct impl *impl) -{ - if (!impl->started) - return 0; - - impl->started = false; - set_timeout(impl, 0); - if (ffado_streaming_stop(impl->dev)) - pw_log_error("Could not stop FFADO streaming"); - else - pw_log_info("FFADO stopped streaming"); - return 0; -} - static void stream_destroy(void *d) { struct stream *s = d; @@ -531,7 +510,7 @@ if (p != NULL) { s->ports[i] = NULL; free(p->buffer); - spa_zero(*p); + free(p); } } s->n_ports = 0; @@ -557,8 +536,8 @@ stop_ffado_device(impl); break; case PW_FILTER_STATE_STREAMING: - s->running = true; - start_ffado_device(impl); + if (start_ffado_device(impl) >= 0) + s->running = true; break; default: break; @@ -580,10 +559,10 @@ for (i = 0; i < s->n_ports; i++) { struct port *p = s->ports[i]; float *src; - if (p == NULL) + if (p == NULL || p->data == NULL) continue; - src = pw_filter_get_dsp_buffer(p, n_samples); + src = pw_filter_get_dsp_buffer(p->data, n_samples); if (src == NULL) { clear_port_buffer(p, n_samples); continue; @@ -641,10 +620,10 @@ struct port *p = s->ports[i]; float *dst; - if (p == NULL || p->buffer == NULL) + if (p == NULL || p->data == NULL || p->buffer == NULL) continue; - dst = pw_filter_get_dsp_buffer(p, n_samples); + dst = pw_filter_get_dsp_buffer(p->data, n_samples); if (dst == NULL) continue; @@ -671,8 +650,9 @@ } static void param_latency_changed(struct stream *s, const struct spa_pod *param, - struct port *port) + struct port_data *data) { + struct port *port = data->port; struct spa_latency_info latency; bool update = false; enum spa_direction direction = port->direction; @@ -690,7 +670,6 @@ { struct impl *impl = s->impl; struct pw_properties *props; - char name[512]; uint8_t buffer[1024]; struct spa_pod_builder b; struct spa_latency_info latency; @@ -700,35 +679,25 @@ for (i = 0; i < s->n_ports; i++) { struct port *port = s->ports[i]; - if (port != NULL) { - s->ports[i] = NULL; + if (port->data != NULL) { free(port->buffer); - pw_filter_remove_port(port); + pw_filter_remove_port(port->data); + port->data = NULL; } } for (i = 0; i < s->n_ports; i++) { struct port *port = s->ports[i]; - ffado_streaming_stream_type stream_type; - char portname[256], channel[32]; + char channel[32]; - if (s->direction == PW_DIRECTION_INPUT) { - ffado_streaming_get_playback_stream_name(impl->dev, i, portname, sizeof(portname)); - stream_type = ffado_streaming_get_playback_stream_type(impl->dev, i); - snprintf(name, sizeof(name), "%s_out", portname); - } else { - ffado_streaming_get_capture_stream_name(impl->dev, i, portname, sizeof(portname)); - stream_type = ffado_streaming_get_capture_stream_type(impl->dev, i); - snprintf(name, sizeof(name), "%s_in", portname); - } snprintf(channel, sizeof(channel), "AUX%u", n_channels % SPA_AUDIO_MAX_CHANNELS); - switch (stream_type) { + switch (port->stream_type) { case ffado_stream_type_audio: props = pw_properties_new( PW_KEY_FORMAT_DSP, "32 bit float mono audio", PW_KEY_PORT_PHYSICAL, "true", PW_KEY_PORT_TERMINAL, "true", - PW_KEY_PORT_NAME, name, + PW_KEY_PORT_NAME, port->name, PW_KEY_AUDIO_CHANNEL, channel, NULL); is_midi = false; @@ -737,7 +706,7 @@ case ffado_stream_type_midi: props = pw_properties_new( PW_KEY_FORMAT_DSP, "8 bit raw midi", - PW_KEY_PORT_NAME, name, + PW_KEY_PORT_NAME, port->name, PW_KEY_PORT_PHYSICAL, "true", PW_KEY_PORT_TERMINAL, "true", PW_KEY_PORT_CONTROL, "true", @@ -747,7 +716,7 @@ break; default: pw_log_info("not registering unknown stream %d %s (type %d)", i, - name, stream_type); + port->name, port->stream_type); continue; } @@ -761,15 +730,15 @@ n_params = 0; params[n_params++] = spa_latency_build(&b, SPA_PARAM_Latency, &latency); - port = pw_filter_add_port(s->filter, + port->data = pw_filter_add_port(s->filter, s->direction, PW_FILTER_PORT_FLAG_MAP_BUFFERS, - sizeof(struct port), - props, params, n_params); - if (port == NULL) { + sizeof(struct port_data), props, params, n_params); + if (port->data == NULL) { pw_log_error("Can't create port: %m"); return; } + port->data->port = port; port->latency[s->direction] = latency; port->is_midi = is_midi; @@ -778,21 +747,28 @@ pw_log_error("Can't create port buffer: %m"); return; } + } +} + +static void setup_stream_ports(struct stream *s) +{ + struct impl *impl = s->impl; + uint32_t i; + for (i = 0; i < s->n_ports; i++) { + struct port *port = s->ports[i]; if (s->direction == PW_DIRECTION_INPUT) { if (ffado_streaming_set_playback_stream_buffer(impl->dev, i, port->buffer)) - pw_log_error("cannot configure port buffer for %s", name); + pw_log_error("cannot configure port buffer for %s", port->name); if (ffado_streaming_playback_stream_onoff(impl->dev, i, 1)) - pw_log_error("cannot enable port %s", name); + pw_log_error("cannot enable port %s", port->name); } else { if (ffado_streaming_set_capture_stream_buffer(impl->dev, i, port->buffer)) - pw_log_error("cannot configure port buffer for %s", name); + pw_log_error("cannot configure port buffer for %s", port->name); if (ffado_streaming_capture_stream_onoff(impl->dev, i, 1)) - pw_log_error("cannot enable port %s", name); + pw_log_error("cannot enable port %s", port->name); } - - s->ports[i] = port; } } @@ -986,6 +962,21 @@ if (impl->position) { struct spa_io_clock *c = &impl->position->clock; +#if 0 + if (c->target_duration != (uint64_t) impl->period_size) { + ffado_streaming_transfer_capture_buffers(impl->dev); + silence_playback(impl); + + if (ffado_streaming_set_period_size(impl->dev, c->target_duration) != 0) { + pw_log_warn("can't change period size"); + } else { + sleep(1); + impl->period_size = c->target_duration; + } + goto again; + } +#endif + c->nsec = nsec; c->rate = SPA_FRACTION(1, impl->sample_rate); c->position += impl->period_size; @@ -1013,19 +1004,41 @@ } } +static void close_ffado_device(struct impl *impl) +{ + if (impl->dev == NULL) + return; + + stop_ffado_device(impl); + ffado_streaming_finish(impl->dev); + impl->dev = NULL; + + pw_log_info("closed FFADO device %s", impl->devices[0]); +} + static int open_ffado_device(struct impl *impl) { - ffado_streaming_stream_type stream_type; - uint32_t i, n_channels; - int res; + int32_t target_rate, target_period; + + if (impl->dev != NULL) + return 0; + + if (impl->position) { + struct spa_io_clock *c = &impl->position->clock; + target_rate = c->target_rate.denom; + target_period = c->target_duration; + } else { + target_rate = impl->sample_rate; + target_period = impl->period_size; + } spa_zero(impl->device_info); impl->device_info.device_spec_strings = impl->devices; impl->device_info.nb_device_spec_strings = impl->n_devices; spa_zero(impl->device_options); - impl->device_options.sample_rate = impl->sample_rate; - impl->device_options.period_size = impl->period_size; + impl->device_options.sample_rate = target_rate; + impl->device_options.period_size = target_period; impl->device_options.nb_buffers = impl->n_periods; impl->device_options.realtime = 1; impl->device_options.packetizer_priority = RTPRIO_SERVER + FFADO_RT_PRIORITY_PACKETIZER_RELATIVE; @@ -1049,21 +1062,54 @@ ffado_streaming_set_audio_datatype(impl->dev, ffado_audio_datatype_float); impl->sample_rate = impl->device_options.sample_rate; + impl->period_size = impl->device_options.period_size; impl->source.info.rate = impl->sample_rate; impl->sink.info.rate = impl->sample_rate; impl->source.n_ports = ffado_streaming_get_nb_capture_streams(impl->dev); + impl->sink.n_ports = ffado_streaming_get_nb_playback_streams(impl->dev); + + if (impl->source.n_ports == 0 && impl->sink.n_ports == 0) { + close_ffado_device(impl); + return -EIO; + } + + pw_log_info("opened FFADO device %s source:%d sink:%d rate:%d period:%d %p", + impl->devices[0], impl->source.n_ports, impl->sink.n_ports, + impl->sample_rate, impl->period_size, impl->position); + + return 0; +} + +static int probe_ffado_device(struct impl *impl) +{ + int res; + uint32_t i, n_channels; + struct port *port; + char name[256]; + + if ((res = open_ffado_device(impl)) < 0) + return res; n_channels = 0; for (i = 0; i < impl->source.n_ports; i++) { - stream_type = ffado_streaming_get_capture_stream_type(impl->dev, i); - switch (stream_type) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + + port->direction = impl->source.direction; + port->stream_type = ffado_streaming_get_capture_stream_type(impl->dev, i); + ffado_streaming_get_capture_stream_name(impl->dev, i, name, sizeof(name)); + snprintf(port->name, sizeof(port->name), "%s_out", name); + + switch (port->stream_type) { case ffado_stream_type_audio: n_channels++; break; default: break; } + impl->source.ports[i] = port; } if (impl->source.info.channels != n_channels) { impl->source.info.channels = n_channels; @@ -1072,54 +1118,96 @@ } n_channels = 0; - impl->sink.n_ports = ffado_streaming_get_nb_playback_streams(impl->dev); for (i = 0; i < impl->sink.n_ports; i++) { - stream_type = ffado_streaming_get_playback_stream_type(impl->dev, i); - switch (stream_type) { + port = calloc(1, sizeof(struct port)); + if (port == NULL) + return -errno; + + port->direction = impl->sink.direction; + port->stream_type = ffado_streaming_get_playback_stream_type(impl->dev, i); + ffado_streaming_get_playback_stream_name(impl->dev, i, name, sizeof(name)); + snprintf(port->name, sizeof(port->name), "%s_in", name); + + switch (port->stream_type) { case ffado_stream_type_audio: n_channels++; break; default: break; } + impl->sink.ports[i] = port; } if (impl->sink.info.channels != n_channels) { impl->sink.info.channels = n_channels; for (i = 0; i < SPA_MIN(impl->sink.info.channels, SPA_AUDIO_MAX_CHANNELS); i++) impl->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i; } - if (ffado_streaming_prepare(impl->dev)) { - pw_log_error("Could not prepare streaming"); - res = -EIO; - goto error; - } + if (impl->mode & MODE_SINK) { if ((res = make_stream(&impl->sink, "FFADO Sink")) < 0) - goto error; + goto exit; } if (impl->mode & MODE_SOURCE) { if ((res = make_stream(&impl->source, "FFADO Source")) < 0) - goto error; + goto exit; } - return 0; +exit: + close_ffado_device(impl); -error: - ffado_streaming_finish(impl->dev); - impl->dev = NULL; return res; } -static void close_ffado_device(struct impl *impl) + +static int start_ffado_device(struct impl *impl) { - destroy_stream(&impl->source); - destroy_stream(&impl->sink); - if (impl->dev) { - stop_ffado_device(impl); - ffado_streaming_finish(impl->dev); - impl->dev = NULL; + int res; + + if (impl->started) + return 0; + + if ((res = open_ffado_device(impl)) < 0) + return res; + + setup_stream_ports(&impl->source); + setup_stream_ports(&impl->sink); + + if (ffado_streaming_prepare(impl->dev)) { + pw_log_error("Could not prepare streaming"); + schedule_reset_ffado_device(impl); + return -EIO; + } + + if (ffado_streaming_start(impl->dev)) { + pw_log_warn("Could not start FFADO streaming, try reset"); + schedule_reset_ffado_device(impl); + return -EIO; } + pw_log_info("FFADO started streaming"); + + impl->started = true; + impl->done = true; + set_timeout(impl, get_time_ns(impl)); + return 0; } +static int stop_ffado_device(struct impl *impl) +{ + if (!impl->started) + return 0; + + impl->started = false; + set_timeout(impl, 0); + if (ffado_streaming_stop(impl->dev)) + pw_log_error("Could not stop FFADO streaming"); + else + pw_log_info("FFADO stopped streaming"); + + close_ffado_device(impl); + + return 0; +} + + static void do_reset_ffado(void *obj, void *data, int res, uint32_t id) { struct impl *impl = obj; @@ -1176,6 +1264,9 @@ close_ffado_device(impl); + destroy_stream(&impl->source); + destroy_stream(&impl->sink); + if (impl->core && impl->do_disconnect) pw_core_disconnect(impl->core); if (impl->ffado_timer) @@ -1421,7 +1512,7 @@ &impl->core_listener, &core_events, impl); - if ((res = open_ffado_device(impl)) < 0) + if ((res = probe_ffado_device(impl)) < 0) goto error; pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl); diff -Nru pipewire-1.0.4/src/modules/module-filter-chain.c pipewire-1.0.5/src/modules/module-filter-chain.c --- pipewire-1.0.4/src/modules/module-filter-chain.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/modules/module-filter-chain.c 2024-04-15 07:33:15.000000000 +0000 @@ -1955,8 +1955,11 @@ return -EINVAL; } } - else if (spa_json_next(json, &val) < 0) - break; + else { + pw_log_error("unexpected link key '%s'", key); + if (spa_json_next(json, &val) < 0) + break; + } } def_out_node = spa_list_first(&graph->node_list, struct node, link); def_in_node = spa_list_last(&graph->node_list, struct node, link); @@ -2066,8 +2069,11 @@ return -EINVAL; } } - else if (spa_json_next(json, &val) < 0) - break; + else { + pw_log_error("unexpected volume key '%s'", key); + if (spa_json_next(json, &val) < 0) + break; + } } if (capture) def_control = spa_list_first(&graph->node_list, struct node, link); @@ -2162,12 +2168,18 @@ have_config = true; if (spa_json_next(json, &val) < 0) break; - } else if (spa_json_next(json, &val) < 0) - break; + } else { + pw_log_warn("unexpected node key '%s'", key); + if (spa_json_next(json, &val) < 0) + break; + } } - if (spa_streq(type, "builtin")) snprintf(plugin, sizeof(plugin), "%s", "builtin"); + else if (spa_streq(type, "")) { + pw_log_error("missing plugin type"); + return -EINVAL; + } pw_log_info("loading type:%s plugin:%s label:%s", type, plugin, label); @@ -2756,8 +2768,11 @@ return -EINVAL; } ppvolumes = &pvolumes; - } else if (spa_json_next(&it[1], &val) < 0) - break; + } else { + pw_log_warn("unexpected graph key '%s'", key); + if (spa_json_next(&it[1], &val) < 0) + break; + } } if (pnodes == NULL) { pw_log_error("filter.graph is missing a nodes array"); diff -Nru pipewire-1.0.4/src/modules/module-protocol-pulse/format.c pipewire-1.0.5/src/modules/module-protocol-pulse/format.c --- pipewire-1.0.4/src/modules/module-protocol-pulse/format.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/modules/module-protocol-pulse/format.c 2024-04-15 07:33:15.000000000 +0000 @@ -687,6 +687,9 @@ if (val->type != SPA_TYPE_Int) return -ENOTSUP; + if (n_values == 0) + return -ENOENT; + values = SPA_POD_BODY(val); switch (choice) { diff -Nru pipewire-1.0.4/src/modules/module-raop-sink.c pipewire-1.0.5/src/modules/module-raop-sink.c --- pipewire-1.0.4/src/modules/module-raop-sink.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/modules/module-raop-sink.c 2024-04-15 07:33:15.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include +#include #include "config.h" diff -Nru pipewire-1.0.4/src/pipewire/conf.c pipewire-1.0.5/src/pipewire/conf.c --- pipewire-1.0.4/src/pipewire/conf.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/pipewire/conf.c 2024-04-15 07:33:15.000000000 +0000 @@ -551,6 +551,7 @@ struct pw_context *context = d->context; struct spa_json it[2]; char key[512], value[512]; + int res; spa_json_init(&it[0], str, len); if (spa_json_enter_object(&it[0], &it[1]) < 0) { @@ -560,8 +561,14 @@ while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) { if (spa_json_get_string(&it[1], value, sizeof(value)) > 0) { - pw_context_add_spa_lib(context, key, value); + if ((res = pw_context_add_spa_lib(context, key, value)) < 0) { + pw_log_error("error adding spa-libs for '%s' in '%.*s': %s", + key, (int)len, str, spa_strerror(res)); + return res; + } d->count++; + } else { + pw_log_warn("config file error: missing spa-libs library name for '%s'", key); } } return 0; @@ -716,18 +723,19 @@ break; spa_json_enter(&it[2], &it[3]); have_match = find_match(&it[3], &context->properties->dict); + } else { + pw_log_warn("unknown module key '%s'", key); } } if (!have_match) continue; - if (name != NULL) + if (name != NULL) { res = load_module(context, name, args, flags); - - if (res < 0) - break; - - d->count++; + if (res < 0) + break; + d->count++; + } } return res; @@ -816,17 +824,19 @@ break; spa_json_enter(&it[2], &it[3]); have_match = find_match(&it[3], &context->properties->dict); + } else { + pw_log_warn("unknown object key '%s'", key); } } if (!have_match) continue; - if (factory != NULL) + if (factory != NULL) { res = create_object(context, factory, args, flags); - - if (res < 0) - break; - d->count++; + if (res < 0) + break; + d->count++; + } } return res; @@ -924,18 +934,19 @@ break; spa_json_enter(&it[2], &it[3]); have_match = find_match(&it[3], &context->properties->dict); + } else { + pw_log_warn("unknown exec key '%s'", key); } } if (!have_match) continue; - if (path != NULL) + if (path != NULL) { res = do_exec(context, path, args); - - if (res < 0) - break; - - d->count++; + if (res < 0) + break; + d->count++; + } } return res; @@ -1134,8 +1145,11 @@ if (spa_json_enter_object(&it[2], &actions) > 0) have_actions = true; } - else if (spa_json_next(&it[2], &val) <= 0) - break; + else { + pw_log_warn("unknown match key '%s'", key); + if (spa_json_next(&it[2], &val) <= 0) + break; + } } if (!have_match || !have_actions) continue; diff -Nru pipewire-1.0.4/src/pipewire/context.c pipewire-1.0.5/src/pipewire/context.c --- pipewire-1.0.4/src/pipewire/context.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/pipewire/context.c 2024-04-15 07:33:15.000000000 +0000 @@ -348,7 +348,7 @@ pw_log_info("%p: parsed %d context.spa-libs items", this, res); if ((res = pw_context_parse_conf_section(this, conf, "context.modules")) < 0) goto error_free; - if (res > 0) + if (res > 0 || pw_properties_get_bool(properties, "context.modules.allow-empty", false)) pw_log_info("%p: parsed %d context.modules items", this, res); else pw_log_warn("%p: no modules loaded from context.modules", this); diff -Nru pipewire-1.0.4/src/pipewire/filter.c pipewire-1.0.5/src/pipewire/filter.c --- pipewire-1.0.4/src/pipewire/filter.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/pipewire/filter.c 2024-04-15 07:33:15.000000000 +0000 @@ -779,9 +779,12 @@ if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_MAPPED)) { for (j = 0; j < b->this.buffer->n_datas; j++) { struct spa_data *d = &b->this.buffer->datas[j]; - pw_log_debug("%p: clear buffer %d mem", - impl, b->id); - unmap_data(impl, d); + if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_MAPPABLE) || + (mappable_dataTypes & (1<type)) > 0) { + pw_log_debug("%p: clear buffer %d mem", + impl, b->id); + unmap_data(impl, d); + } } } } @@ -944,7 +947,8 @@ if (SPA_FLAG_IS_SET(impl_flags, PW_FILTER_PORT_FLAG_MAP_BUFFERS)) { for (j = 0; j < buffers[i]->n_datas; j++) { struct spa_data *d = &buffers[i]->datas[j]; - if ((mappable_dataTypes & (1<type)) > 0) { + if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_MAPPABLE) || + (mappable_dataTypes & (1<type)) > 0) { if ((res = map_data(impl, d, prot)) < 0) return res; SPA_FLAG_SET(b->flags, BUFFER_FLAG_MAPPED); @@ -1254,10 +1258,12 @@ spa_hook_list_init(&impl->hooks); this->properties = props; - if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL && extra) { - str = pw_properties_get(extra, PW_KEY_APP_NAME); - if (str == NULL) - str = pw_properties_get(extra, PW_KEY_APP_PROCESS_BINARY); + if ((str = pw_properties_get(props, PW_KEY_NODE_NAME)) == NULL) { + if (extra) { + str = pw_properties_get(extra, PW_KEY_APP_NAME); + if (str == NULL) + str = pw_properties_get(extra, PW_KEY_APP_PROCESS_BINARY); + } if (str == NULL) str = name; pw_properties_set(props, PW_KEY_NODE_NAME, str); diff -Nru pipewire-1.0.4/src/pipewire/stream.c pipewire-1.0.5/src/pipewire/stream.c --- pipewire-1.0.4/src/pipewire/stream.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/pipewire/stream.c 2024-04-15 07:33:15.000000000 +0000 @@ -100,6 +100,7 @@ struct spa_io_buffers *io; struct spa_io_rate_match *rate_match; uint32_t rate_queued; + uint64_t rate_size; struct { struct spa_io_position *position; } rt; @@ -420,9 +421,8 @@ static inline uint32_t update_requested(struct stream *impl) { - uint32_t index, id, res = 0; + uint32_t index, id; struct buffer *buffer; - struct spa_io_rate_match *r = impl->rate_match; if (spa_ringbuffer_get_read_index(&impl->dequeued.ring, &index) < 1) { pw_log_debug("%p: no free buffers %d", impl, impl->n_buffers); @@ -431,15 +431,11 @@ id = impl->dequeued.ids[index & MASK_BUFFERS]; buffer = &impl->buffers[id]; - if (r) { - buffer->this.requested = r->size; - res = r->size > 0 ? 1 : 0; - } else { - buffer->this.requested = impl->quantum; - res = 1; - } + buffer->this.requested = impl->rate_size; + pw_log_trace_fp("%p: update buffer:%u req:%"PRIu64, impl, id, buffer->this.requested); - return res; + + return buffer->this.requested > 0 ? 1 : 0; } static int @@ -683,8 +679,13 @@ impl->time.queued = queued; impl->quantum = p->clock.duration; } - if (SPA_LIKELY(impl->rate_match != NULL)) + if (SPA_LIKELY(impl->rate_match != NULL)) { impl->rate_queued = impl->rate_match->delay; + impl->rate_size = impl->rate_match->size; + } else { + impl->rate_queued = 0; + impl->rate_size = impl->quantum; + } SPA_SEQ_WRITE(impl->seq); } @@ -717,11 +718,11 @@ if (impl->io != NULL) impl->io->status = SPA_STATUS_NEED_DATA; } - else if (!impl->process_rt && !impl->driving) { + else { copy_position(impl, impl->queued.incount); - call_process(impl); + if (!impl->process_rt && !impl->driving) + call_process(impl); } - stream_set_state(stream, PW_STREAM_STATE_STREAMING, 0, NULL); } break; @@ -856,9 +857,12 @@ if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_MAPPED)) { for (j = 0; j < b->this.buffer->n_datas; j++) { struct spa_data *d = &b->this.buffer->datas[j]; - pw_log_debug("%p: clear buffer %d mem", - stream, b->id); - unmap_data(impl, d); + if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_MAPPABLE) || + (mappable_dataTypes & (1<type)) > 0) { + pw_log_debug("%p: clear buffer %d mem", + stream, b->id); + unmap_data(impl, d); + } } } } @@ -1035,7 +1039,7 @@ struct stream *impl = object; struct pw_stream *stream = &impl->this; struct spa_io_buffers *io = impl->io; - struct buffer *b; + struct buffer *b = NULL; if (io == NULL) return -EIO; @@ -1052,10 +1056,13 @@ SPA_ATOMIC_INC(b->busy->count); } } - if (!queue_is_empty(impl, &impl->dequeued)) { - copy_position(impl, impl->dequeued.incount); + + copy_position(impl, impl->dequeued.incount); + if (b != NULL) + b->this.time = impl->time.now; + + if (!queue_is_empty(impl, &impl->dequeued)) call_process(impl); - } if (io->status != SPA_STATUS_NEED_DATA || io->buffer_id == SPA_ID_INVALID) { /* pop buffer to recycle */ @@ -1264,6 +1271,10 @@ } pod = spa_pod_get_values(type, &n_vals, &choice); + if (n_vals == 0) { + free(c); + return -EINVAL; + } c->type = SPA_POD_TYPE(pod); if (spa_pod_is_float(pod)) @@ -1523,10 +1534,12 @@ if (pw_properties_get(props, PW_KEY_STREAM_IS_LIVE) == NULL) pw_properties_set(props, PW_KEY_STREAM_IS_LIVE, "true"); - if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL && extra) { - str = pw_properties_get(extra, PW_KEY_APP_NAME); - if (str == NULL) - str = pw_properties_get(extra, PW_KEY_APP_PROCESS_BINARY); + if ((str = pw_properties_get(props, PW_KEY_NODE_NAME)) == NULL) { + if (extra) { + str = pw_properties_get(extra, PW_KEY_APP_NAME); + if (str == NULL) + str = pw_properties_get(extra, PW_KEY_APP_PROCESS_BINARY); + } if (str == NULL) str = name; pw_properties_set(props, PW_KEY_NODE_NAME, str); @@ -2347,13 +2360,14 @@ { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); uintptr_t seq1, seq2; - uint32_t buffered, quantum, index; + uint32_t buffered, quantum, index, rate_size; int32_t avail_buffers; do { seq1 = SPA_SEQ_READ(impl->seq); memcpy(time, &impl->time, SPA_MIN(size, sizeof(struct pw_time))); buffered = impl->rate_queued; + rate_size = impl->rate_size; quantum = impl->quantum; seq2 = SPA_SEQ_READ(impl->seq); } while (!SPA_SEQ_READ_SUCCESS(seq1, seq2)); @@ -2374,8 +2388,10 @@ time->buffered = buffered; if (size >= offsetof(struct pw_time, avail_buffers)) time->queued_buffers = impl->n_buffers - avail_buffers; - if (size >= sizeof(struct pw_time)) + if (size >= offsetof(struct pw_time, size)) time->avail_buffers = avail_buffers; + if (size >= sizeof(struct pw_time)) + time->size = rate_size; pw_log_trace_fp("%p: %"PRIi64" %"PRIi64" %"PRIu64" %d/%d %"PRIu64" %" PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %d/%d", stream, diff -Nru pipewire-1.0.4/src/pipewire/stream.h pipewire-1.0.5/src/pipewire/stream.h --- pipewire-1.0.4/src/pipewire/stream.h 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/pipewire/stream.h 2024-04-15 07:33:15.000000000 +0000 @@ -187,12 +187,17 @@ }; /** a buffer structure obtained from pw_stream_dequeue_buffer(). The size of this - * structure can grow as more field are added in the future */ + * structure can grow as more fields are added in the future */ struct pw_buffer { struct spa_buffer *buffer; /**< the spa buffer */ - void *user_data; /**< user data attached to the buffer */ + void *user_data; /**< user data attached to the buffer. The user of + * the stream can set custom data associated with the + * buffer, typically in the add_buffer event. Any + * cleanup should be performed in the remove_buffer + * event. The user data is returned unmodified each + * time a buffer is dequeued. */ uint64_t size; /**< This field is set by the user and the sum of - * all queued buffer is returned in the time info. + * all queued buffers is returned in the time info. * For audio, it is advised to use the number of * samples in the buffer for this field. */ uint64_t requested; /**< For playback streams, this field contains the @@ -200,6 +205,11 @@ * streams this will be the amount of samples * required by the resampler. This field is 0 * when no suggestion is provided. Since 0.3.49 */ + uint64_t time; /**< For capture streams, this field contains the + * cycle time in nanoseconds when this buffer was + * queued in the stream. It can be compared against + * the pw_time values or pw_stream_get_nsec() + * Since 1.0.5 */ }; struct pw_stream_control { @@ -287,12 +297,12 @@ *\endcode */ struct pw_time { - int64_t now; /**< the monotonic time in nanoseconds. This is the time - * when this time report was updated. It is usually - * updated every graph cycle. You can use the current - * monotonic time to calculate the elapsed time between - * this report and the current state and calculate - * updated ticks and delay values. */ + int64_t now; /**< the time in nanoseconds. This is the time when this + * time report was updated. It is usually updated every + * graph cycle. You can use pw_stream_get_nsec() to + * calculate the elapsed time between this report and + * the current time and calculate updated ticks and delay + * values. */ struct spa_fraction rate; /**< the rate of \a ticks and delay. This is usually * expressed in 1/. */ uint64_t ticks; /**< the ticks at \a now. This is the current time that @@ -313,8 +323,12 @@ uint64_t buffered; /**< for audio/raw streams, this contains the extra * number of samples buffered in the resampler. * Since 0.3.50. */ - uint32_t queued_buffers; /**< The number of buffers that are queued. Since 0.3.50 */ - uint32_t avail_buffers; /**< The number of buffers that can be dequeued. Since 0.3.50 */ + uint32_t queued_buffers; /**< the number of buffers that are queued. Since 0.3.50 */ + uint32_t avail_buffers; /**< the number of buffers that can be dequeued. Since 0.3.50 */ + uint64_t size; /**< for audio/raw playback streams, this contains the number of + * samples requested by the resampler for the current + * quantum. for audio/raw capture streams this will be the number + * of samples available for the current quantum. Since 1.0.5 */ }; #include diff -Nru pipewire-1.0.4/src/tests/test-stream.c pipewire-1.0.5/src/tests/test-stream.c --- pipewire-1.0.4/src/tests/test-stream.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/tests/test-stream.c 2024-04-15 07:33:15.000000000 +0000 @@ -47,8 +47,8 @@ TEST_FUNC(ev, test, trigger_done); #if defined(__x86_64__) && defined(__LP64__) - spa_assert_se(sizeof(struct pw_buffer) == 32); - spa_assert_se(sizeof(struct pw_time) == 56); + spa_assert_se(sizeof(struct pw_buffer) == 40); + spa_assert_se(sizeof(struct pw_time) == 64); #else fprintf(stderr, "%zd\n", sizeof(struct pw_buffer)); fprintf(stderr, "%zd\n", sizeof(struct pw_time)); diff -Nru pipewire-1.0.4/src/tools/pw-cat.c pipewire-1.0.5/src/tools/pw-cat.c --- pipewire-1.0.4/src/tools/pw-cat.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/tools/pw-cat.c 2024-04-15 07:33:15.000000000 +0000 @@ -931,11 +931,11 @@ pw_stream_get_time_n(data->stream, &time, sizeof(time)); printf("stream time: now:%"PRIi64" rate:%u/%u ticks:%"PRIu64 " delay:%"PRIi64" queued:%"PRIu64 - " buffered:%"PRIi64" buffers:%u avail:%u\n", + " buffered:%"PRIi64" buffers:%u avail:%u size:%"PRIu64"\n", time.now, time.rate.num, time.rate.denom, time.ticks, time.delay, time.queued, time.buffered, - time.queued_buffers, time.avail_buffers); + time.queued_buffers, time.avail_buffers, time.size); } enum { diff -Nru pipewire-1.0.4/src/tools/pw-top.c pipewire-1.0.5/src/tools/pw-top.c --- pipewire-1.0.4/src/tools/pw-top.c 2024-03-13 08:22:08.000000000 +0000 +++ pipewire-1.0.5/src/tools/pw-top.c 2024-04-15 07:33:15.000000000 +0000 @@ -420,9 +420,11 @@ snprintf(buf, len, " --- "); } else if (val == (uint64_t)-2) { snprintf(buf, len, " +++ "); + } else if (quantum == 0.0f) { + snprintf(buf, len, " ??? "); } else { float frac = val / 1000000000.f; - snprintf(buf, len, "%5.2f", quantum == 0.0f ? 0.0f : frac/quantum); + snprintf(buf, len, "%5.2f", frac/quantum); } return buf; } @@ -467,7 +469,7 @@ if (i->clock.rate.denom) quantum = (float)i->clock.duration * i->clock.rate.num / (float)i->clock.rate.denom; else - quantum = 0.0; + quantum = 0.0f; if (n->measurement.awake >= n->measurement.signal) waiting = n->measurement.awake - n->measurement.signal;