Overview

Request 5508 (accepted)

New upstream release

Submit package home:zaitor:...s:Essentials / pipewire-aptx to package Essentials / pipewire-aptx

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,10 @@
2
 -------------------------------------------------------------------
3
+Fri Feb  4 06:41:51 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.45
6
+  * Add explicit pipewire-spa-plugins-0_2 Requires.
7
+
8
+-------------------------------------------------------------------
9
 Sun Jan 30 16:36:30 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
10
 
11
 - Update to version 0.3.44
12
pipewire-aptx.spec Changed
27
 
1
@@ -7,7 +7,7 @@
2
 %define soversion 0_2
3
 
4
 Name:           pipewire-aptx
5
-Version:        0.3.44
6
+Version:        0.3.45
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
@@ -16,7 +16,7 @@
11
 
12
 BuildRequires:  c++_compiler
13
 BuildRequires:  c_compiler
14
-BuildRequires:  meson >= 0.49.0
15
+BuildRequires:  meson >= 0.59.0
16
 BuildRequires:  pkgconfig
17
 BuildRequires:  pkgconfig(bluez)
18
 BuildRequires:  pkgconfig(dbus-1)
19
@@ -24,6 +24,7 @@
20
 BuildRequires:  pkgconfig(sbc)
21
 
22
 Requires:       pipewire >= %{version}
23
+Requires:       pipewire-spa-plugins-%{soversion} >= %{version}
24
 Supplements:    (pipewire and pipewire-spa-plugins-%{soversion})
25
 
26
 %description
27
pipewire-0.3.44.tar.gz/.gitlab-ci.yml -> pipewire-0.3.45.tar.gz/.gitlab-ci.yml Changed
124
 
1
@@ -18,18 +18,23 @@
2
   - project: 'freedesktop/ci-templates'
3
     ref: *templates_sha
4
     file: '/templates/ubuntu.yml'
5
+  - project: 'freedesktop/ci-templates'
6
+    ref: *templates_sha
7
+    file: '/templates/alpine.yml'
8
 
9
 .fedora:
10
   variables:
11
     # Update this tag when you want to trigger a rebuild
12
-    FDO_DISTRIBUTION_TAG: '2022-01-27.1'
13
+    FDO_DISTRIBUTION_TAG: '2022-01-28.0'
14
     FDO_DISTRIBUTION_VERSION: '35'
15
     FDO_DISTRIBUTION_PACKAGES: >-
16
       alsa-lib-devel
17
+      avahi-devel
18
       bluez-libs-devel
19
       clang
20
       dbus-devel
21
       doxygen
22
+      fdk-aac-free-devel
23
       findutils
24
       gcc
25
       gcc-c++
26
@@ -39,10 +44,15 @@
27
       gstreamer1-devel
28
       gstreamer1-plugins-base-devel
29
       jack-audio-connection-kit-devel
30
+      libcanberra-devel
31
+      libldac-devel
32
       libsndfile-devel
33
+      libusb-devel
34
+      lilv-devel
35
       libv4l-devel
36
       libva-devel
37
       libX11-devel
38
+      openssl-devel
39
       pulseaudio-libs-devel
40
       python3-docutils
41
       sbc-devel
42
@@ -90,6 +100,39 @@
43
     FDO_DISTRIBUTION_EXEC: >-
44
       pip3 install meson
45
 
46
+.alpine:
47
+  variables:
48
+    # Update this tag when you want to trigger a rebuild
49
+    FDO_DISTRIBUTION_TAG: '2022-01-28.2'
50
+    FDO_DISTRIBUTION_VERSION: '3.15'
51
+    FDO_DISTRIBUTION_PACKAGES: >-
52
+      alsa-lib-dev
53
+      avahi-dev
54
+      bash
55
+      bluez-dev
56
+      gcc
57
+      g++
58
+      dbus-dev
59
+      doxygen
60
+      eudev-dev
61
+      fdk-aac-dev
62
+      git
63
+      glib-dev
64
+      graphviz
65
+      gst-plugins-base-dev
66
+      gstreamer-dev
67
+      jack-dev
68
+      libfreeaptx-dev
69
+      libusb-dev
70
+      libx11-dev
71
+      meson
72
+      ncurses-dev
73
+      pulseaudio-dev
74
+      readline-dev
75
+      sbc-dev
76
+      vulkan-loader-dev
77
+      xmltoman
78
+
79
 .coverity:
80
   variables:
81
     FDO_REPO_SUFFIX: 'coverity'
82
@@ -154,6 +197,14 @@
83
   variables:
84
     GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
85
 
86
+container_alpine:
87
+  extends:
88
+    - .alpine
89
+    - .fdo.container-build@alpine
90
+  stage: container
91
+  variables:
92
+    GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
93
+
94
 container_coverity:
95
   extends:
96
     - .fedora
97
@@ -202,6 +253,26 @@
98
       - build-*/meson-logs
99
       - prefix-*
100
 
101
+build_on_alpine:
102
+  extends:
103
+    - .alpine
104
+    - .not_coverity
105
+    - .fdo.distribution-image@alpine
106
+    - .build
107
+  stage: build
108
+
109
+# build with all auto() options enabled
110
+build_all:
111
+  extends:
112
+    - .build_on_fedora
113
+  variables:
114
+    # Fedora doesn't have libfreeaptx or roc
115
+    # libcamera has no stable API, so let's not chase that target
116
+    MESON_OPTIONS: "-Dauto_features=enabled -Dbluez5-codec-aptx=disabled -Droc=disabled -Dlibcamera=disabled"
117
+  parallel:
118
+    matrix:
119
+      - CC: [gcc, clang]
120
+
121
 # build with all options on auto() or their default values
122
 build_with_no_commandline_options:
123
   extends:
124
pipewire-0.3.44.tar.gz/NEWS -> pipewire-0.3.45.tar.gz/NEWS Changed
82
 
1
@@ -1,3 +1,70 @@
2
+# PipeWire 0.3.45 (2022-02-03)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+  - Zoom, telegram and other apps should be able to play sound again.
9
+  - Implement a better way to force and lock JACK buffersize.
10
+  - Default sink and source names and properties are improved.
11
+  - The config loader can now load and merge fragments in conf.d directories
12
+    for easier user configuration of config files.
13
+  - Many small bug fixes and improvements.
14
+
15
+## PipeWire
16
+  - pw-cli can now also send Commands to nodes. This can be used to Suspend
17
+    a device, for example.
18
+  - The eventfd was removed from loops and invoke is now used to stop the loop,
19
+    this saves an fd.
20
+  - New Alpine CI target to test musl builds, various build fixes.
21
+  - Add force-quantum and force-rate properties.
22
+  - The config loader can now load and merge fragments in conf.d directories.
23
+    (#207)
24
+  - resource error methods can be called without a resource and then just
25
+    log an error message.
26
+  - link-factory can now also work from the config. (#2095)
27
+
28
+## modules
29
+  - module-simple-protocol has better argument parsing and can handle
30
+    channelmap now. (#2068) It's also possible to configure latency and
31
+    rate.
32
+  - The native protocol now does extra checks for invalid data. (#2070)
33
+
34
+## ALSA
35
+  - TI2902 chips as found in various Behringer cards should have inputs
36
+    again.
37
+  - Better handling of busy devices in udev, retry when the inotify close
38
+    event is emited.
39
+
40
+## SPA
41
+  - plugins now handle alignment properly and only expect the max alignment
42
+    required for the CPU. (#2074)
43
+
44
+## Bluetooth
45
+  - SBC-XQ is now enabled for the JBL Endurance RUN BT headset.
46
+  - Support for non-hexadecimal XAPL version strings to improve compatibility.
47
+  - Use HCI commands again to probe the adapter msbc capability. This improves
48
+    compatibility with some adapters. (#2030)
49
+  - Set the right startup volume.
50
+  - Better A2DP source idle handling.
51
+  - Fix a timer bug in SCO sink that could cause busy looping.
52
+
53
+## pulse-server
54
+  - A playback issue when the tlength > maxlength was fixed. (#2069) This
55
+    affected Zoom and other applications.
56
+  - The STREAM_BUFFER_ATTR command is now implemented.
57
+  - Module names are improved. (#2076)
58
+  - Many small fixes and improvements.
59
+  - Fix a pavucontrol crash with invalid channels. (#1442)
60
+
61
+## JACK
62
+  - Use the new force-quantum and force-rate properties in the JACK API to
63
+    switch quantum and ensure it can't change for the lifetime of the JACK
64
+    app. (#2079)
65
+
66
+Older versions:
67
+
68
+
69
 # PipeWire 0.3.44 (2022-01-27)
70
 
71
 This is a bugfix release that is API and ABI compatible with previous
72
@@ -133,9 +200,6 @@
73
     properties can also be configured.
74
   - Fix a regression in telegram sounds not playing.
75
 
76
-
77
-Older versions:
78
-
79
 # PipeWire 0.3.43 (2022-01-05)
80
 
81
 This is a bugfix release that is API and ABI compatible with previous
82
pipewire-0.3.44.tar.gz/meson.build -> pipewire-0.3.45.tar.gz/meson.build Changed
34
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', ['c' ],
3
-  version : '0.3.44',
4
+  version : '0.3.45',
5
   license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
6
   meson_version : '>= 0.59.0',
7
   default_options : [ 'warning_level=3',
8
@@ -77,10 +77,12 @@
9
   '-Wmissing-braces',
10
   '-Wtype-limits',
11
   '-Wvariadic-macros',
12
+  '-Wmaybe-uninitialized',
13
   '-Wno-missing-field-initializers',
14
   '-Wno-unused-parameter',
15
   '-Wno-pedantic',
16
   '-Wold-style-declaration',
17
+  '-Wdeprecated-declarations',
18
   '-Wunused-result',
19
 ]
20
 
21
@@ -424,10 +426,9 @@
22
     : dependency('', required: false))
23
 
24
 # On FreeBSD, libintl library is required for gettext
25
-libintl_dep = dependency('intl', required: false)
26
-
27
+libintl_dep = cc.find_library('intl', required: false)
28
 if not libintl_dep.found()
29
-    libintl_dep = cc.find_library('intl', required: false)
30
+    libintl_dep = dependency('intl', required: false)
31
 endif
32
 summary({'intl support': libintl_dep.found()}, bool_yn: true)
33
 
34
pipewire-0.3.44.tar.gz/pipewire-jack/src/match-rules.c -> pipewire-0.3.45.tar.gz/pipewire-jack/src/match-rules.c Changed
10
 
1
@@ -89,7 +89,7 @@
2
 }
3
 
4
 int pw_jack_match_rules(const char *rules, size_t size, const struct spa_dict *props,
5
-       int (*matched) (void *data, const char *action, const char *val, int len),
6
+       int (*matched) (void *data, const char *action, const char *val, size_t len),
7
        void *data)
8
 {
9
    const char *val;
10
pipewire-0.3.44.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.45.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
110
 
1
@@ -274,6 +274,7 @@
2
 
3
 struct metadata {
4
    struct pw_metadata *proxy;
5
+   struct spa_hook proxy_listener;
6
    struct spa_hook listener;
7
 
8
    char default_audio_sink[1024];
9
@@ -862,6 +863,8 @@
10
        pw_log_warn("sync requested from callback");
11
        return 0;
12
    }
13
+   if (client->error)
14
+       return client->last_res;
15
 
16
    client->pending_sync = pw_proxy_sync((struct pw_proxy*)client->core, client->pending_sync);
17
 
18
@@ -2593,6 +2596,26 @@
19
    .property = metadata_property
20
 };
21
 
22
+static void metadata_proxy_removed(void *data)
23
+{
24
+   struct client *c = data;
25
+   pw_proxy_destroy((struct pw_proxy*)c->metadata->proxy);
26
+}
27
+
28
+static void metadata_proxy_destroy(void *data)
29
+{
30
+   struct client *c = data;
31
+   spa_hook_remove(&c->metadata->proxy_listener);
32
+   spa_hook_remove(&c->metadata->listener);
33
+   c->metadata = NULL;
34
+}
35
+
36
+static const struct pw_proxy_events metadata_proxy_events = {
37
+   PW_VERSION_PROXY_EVENTS,
38
+   .removed = metadata_proxy_removed,
39
+   .destroy = metadata_proxy_destroy,
40
+};
41
+
42
 static void proxy_removed(void *data)
43
 {
44
    struct object *o = data;
45
@@ -2917,6 +2940,9 @@
46
        c->metadata->default_audio_sink[0] = '\0';
47
        c->metadata->default_audio_source[0] = '\0';
48
 
49
+       pw_proxy_add_listener(proxy,
50
+               &c->metadata->proxy_listener,
51
+               &metadata_proxy_events, c);
52
        pw_metadata_add_listener(proxy,
53
                &c->metadata->listener,
54
                &metadata_events, c);
55
@@ -3069,6 +3095,19 @@
56
    return 1;
57
 }
58
 
59
+static int apply_jack_rules(void *data, const char *location, const char *section,
60
+       const char *str, size_t len)
61
+{
62
+   struct client *client = data;
63
+   const struct pw_properties *p =
64
+       pw_context_get_properties(client->context.context);
65
+
66
+   if (p != NULL)
67
+       pw_jack_match_rules(str, len, &p->dict, execute_match, client);
68
+
69
+   return 0;
70
+}
71
+
72
 SPA_EXPORT
73
 jack_client_t * jack_client_open (const char *client_name,
74
                                   jack_options_t options,
75
@@ -3126,22 +3165,15 @@
76
    client->allow_mlock = client->context.context->settings.mem_allow_mlock;
77
    client->warn_mlock = client->context.context->settings.mem_warn_mlock;
78
 
79
-   if ((str = pw_context_get_conf_section(client->context.context,
80
-                   "jack.properties")) != NULL)
81
-       pw_properties_update_string(client->props, str, strlen(str));
82
+   pw_context_conf_update_props(client->context.context,
83
+           "jack.properties", client->props);
84
 
85
         if ((str = getenv("PIPEWIRE_PROPS")) != NULL)
86
        pw_properties_update_string(client->props, str, strlen(str));
87
 
88
 
89
-   if ((str = pw_context_get_conf_section(client->context.context,
90
-                   "jack.rules")) != NULL) {
91
-       const struct pw_properties *p =
92
-           pw_context_get_properties(client->context.context);
93
-       if (p != NULL)
94
-           pw_jack_match_rules(str, strlen(str), &p->dict,
95
-               execute_match, client);
96
-   }
97
+   pw_context_conf_section_for_each(client->context.context, "jack.rules",
98
+           apply_jack_rules, client);
99
 
100
    client->show_monitor = pw_properties_get_bool(client->props, "jack.show-monitor", true);
101
    client->merge_monitor = pw_properties_get_bool(client->props, "jack.merge-monitor", false);
102
@@ -3973,6 +4005,7 @@
103
 
104
    pw_thread_loop_lock(c->context.loop);
105
    pw_properties_set(c->props, PW_KEY_NODE_LATENCY, latency);
106
+   pw_properties_setf(c->props, PW_KEY_NODE_FORCE_QUANTUM, "%u", nframes);
107
 
108
    c->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS;
109
    c->info.props = &c->props->dict;
110
pipewire-0.3.44.tar.gz/spa/include/spa/monitor/type-info.h -> pipewire-0.3.45.tar.gz/spa/include/spa/monitor/type-info.h Changed
10
 
1
@@ -45,7 +45,7 @@
2
 #define SPA_TYPE_INFO_DEVICE_EVENT_ID_BASE SPA_TYPE_INFO_DeviceEventId ":"
3
 
4
 static const struct spa_type_info spa_type_device_event_id[] = {
5
-   { SPA_DEVICE_EVENT_ObjectConfig, SPA_TYPE_Int, SPA_TYPE_INFO_DEVICE_EVENT_ID_BASE "ObjectConfig", NULL },
6
+   { SPA_DEVICE_EVENT_ObjectConfig, SPA_TYPE_EVENT_Device, SPA_TYPE_INFO_DEVICE_EVENT_ID_BASE "ObjectConfig", NULL },
7
    { 0, 0, NULL, NULL },
8
 };
9
 
10
pipewire-0.3.44.tar.gz/spa/include/spa/node/type-info.h -> pipewire-0.3.45.tar.gz/spa/include/spa/node/type-info.h Changed
45
 
1
@@ -61,10 +61,10 @@
2
 #define SPA_TYPE_INFO_NODE_EVENT_BASE      SPA_TYPE_INFO_NodeEvent ":"
3
 
4
 static const struct spa_type_info spa_type_node_event_id[] = {
5
-   { SPA_NODE_EVENT_Error,      SPA_TYPE_Int, SPA_TYPE_INFO_NODE_EVENT_BASE "Error",   NULL },
6
-   { SPA_NODE_EVENT_Buffering,  SPA_TYPE_Int, SPA_TYPE_INFO_NODE_EVENT_BASE "Buffering", NULL },
7
-   { SPA_NODE_EVENT_RequestRefresh, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_EVENT_BASE "RequestRefresh", NULL },
8
-   { SPA_NODE_EVENT_RequestProcess, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_EVENT_BASE "RequestProcess", NULL },
9
+   { SPA_NODE_EVENT_Error,      SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "Error",   NULL },
10
+   { SPA_NODE_EVENT_Buffering,  SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "Buffering", NULL },
11
+   { SPA_NODE_EVENT_RequestRefresh, SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "RequestRefresh", NULL },
12
+   { SPA_NODE_EVENT_RequestProcess, SPA_TYPE_EVENT_Node, SPA_TYPE_INFO_NODE_EVENT_BASE "RequestProcess", NULL },
13
    { 0, 0, NULL, NULL },
14
 };
15
 
16
@@ -77,17 +77,17 @@
17
 #define SPA_TYPE_INFO_NODE_COMMAND_BASE        SPA_TYPE_INFO_NodeCommand ":"
18
 
19
 static const struct spa_type_info spa_type_node_command_id[] = {
20
-   { SPA_NODE_COMMAND_Suspend, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Suspend", NULL },
21
-   { SPA_NODE_COMMAND_Pause,   SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Pause",   NULL },
22
-   { SPA_NODE_COMMAND_Start,   SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Start",   NULL },
23
-   { SPA_NODE_COMMAND_Enable,  SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Enable",  NULL },
24
-   { SPA_NODE_COMMAND_Disable, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Disable", NULL },
25
-   { SPA_NODE_COMMAND_Flush,   SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Flush",   NULL },
26
-   { SPA_NODE_COMMAND_Drain,   SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Drain",   NULL },
27
-   { SPA_NODE_COMMAND_Marker,  SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "Marker",  NULL },
28
-   { SPA_NODE_COMMAND_ParamBegin,  SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "ParamBegin",  NULL },
29
-   { SPA_NODE_COMMAND_ParamEnd,    SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "ParamEnd",  NULL },
30
-   { SPA_NODE_COMMAND_RequestProcess, SPA_TYPE_Int, SPA_TYPE_INFO_NODE_COMMAND_BASE "RequestProcess",  NULL },
31
+   { SPA_NODE_COMMAND_Suspend, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Suspend", NULL },
32
+   { SPA_NODE_COMMAND_Pause,   SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Pause",   NULL },
33
+   { SPA_NODE_COMMAND_Start,   SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Start",   NULL },
34
+   { SPA_NODE_COMMAND_Enable,  SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Enable",  NULL },
35
+   { SPA_NODE_COMMAND_Disable, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Disable", NULL },
36
+   { SPA_NODE_COMMAND_Flush,   SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Flush",   NULL },
37
+   { SPA_NODE_COMMAND_Drain,   SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Drain",   NULL },
38
+   { SPA_NODE_COMMAND_Marker,  SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "Marker",  NULL },
39
+   { SPA_NODE_COMMAND_ParamBegin,  SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "ParamBegin",  NULL },
40
+   { SPA_NODE_COMMAND_ParamEnd,    SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "ParamEnd",  NULL },
41
+   { SPA_NODE_COMMAND_RequestProcess, SPA_TYPE_COMMAND_Node, SPA_TYPE_INFO_NODE_COMMAND_BASE "RequestProcess",  NULL },
42
    { 0, 0, NULL, NULL },
43
 };
44
 
45
pipewire-0.3.44.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules -> pipewire-0.3.45.tar.gz/spa/plugins/alsa/90-pipewire-alsa.rules Changed
10
 
1
@@ -113,7 +113,7 @@
2
 ATTRS{idVendor}=="041e", ATTRS{idProduct}=="322c", ENV{ACP_PROFILE_SET}="sb-omni-surround-5.1.conf"
3
 ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="4014", ENV{ACP_PROFILE_SET}="dell-dock-tb16-usb-audio.conf"
4
 ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="402e", ENV{ACP_PROFILE_SET}="dell-dock-tb16-usb-audio.conf"
5
-#ATTRS{idVendor}=="08bb", ATTRS{idProduct}=="2902", ENV{ACP_PROFILE_SET}="texas-instruments-pcm2902.conf"
6
+ATTRS{idVendor}=="08bb", ATTRS{idProduct}=="2902", ENV{ACP_PROFILE_SET}="texas-instruments-pcm2902.conf"
7
 ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0269", ENV{ACP_PROFILE_SET}="hp-tbt-dock-120w-g2.conf"
8
 ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="0567", ENV{ACP_PROFILE_SET}="hp-tbt-dock-audio-module.conf"
9
 
10
pipewire-0.3.44.tar.gz/spa/plugins/alsa/alsa-udev.c -> pipewire-0.3.45.tar.gz/spa/plugins/alsa/alsa-udev.c Changed
414
 
1
@@ -29,6 +29,7 @@
2
 #include <sys/stat.h>
3
 #include <sys/inotify.h>
4
 #include <fcntl.h>
5
+#include <dirent.h>
6
 
7
 #include <libudev.h>
8
 #include <alsa/asoundlib.h>
9
@@ -47,9 +48,6 @@
10
 
11
 #define MAX_DEVICES    64
12
 
13
-#define RETRY_COUNT    1
14
-#define RETRY_MSEC 2000
15
-
16
 #define ACTION_ADD 0
17
 #define ACTION_REMOVE  1
18
 #define ACTION_DISABLE 2
19
@@ -57,7 +55,7 @@
20
 struct device {
21
    uint32_t id;
22
    struct udev_device *dev;
23
-   uint8_t retry;
24
+   unsigned int unavailable:1;
25
    unsigned int accessible:1;
26
    unsigned int ignored:1;
27
    unsigned int emitted:1;
28
@@ -84,7 +82,6 @@
29
 
30
    struct spa_source source;
31
    struct spa_source notify;
32
-   struct spa_source retry_timer;
33
    unsigned int use_acp:1;
34
 };
35
 
36
@@ -184,7 +181,7 @@
37
 {
38
    const char *s;
39
    char *d;
40
-   int h1, h2;
41
+   int h1 = 0, h2 = 0;
42
    enum { TEXT, BACKSLASH, EX, FIRST } state = TEXT;
43
 
44
    for (s = src, d = dst; *s; s++) {
45
@@ -249,37 +246,94 @@
46
    *d = 0;
47
 }
48
 
49
-static int check_device_busy(struct impl *this, struct device *device, snd_ctl_t *ctl_hndl)
50
+static int check_device_available(struct impl *this, struct device *device, int *num_pcm)
51
 {
52
-   int dev;
53
+   char path[PATH_MAX];
54
+   DIR *card = NULL, *pcm = NULL;
55
+   FILE *f;
56
+   char buf[16];
57
+   size_t sz;
58
+   struct dirent *entry, *entry_pcm;
59
+   int res;
60
+
61
+   /*
62
+    * Check if some pcm devices of the card are busy.  Check it via /proc, as we
63
+    * don't want to actually open any devices using alsa-lib (generates uncontrolled
64
+    * number of inotify events), or replicate its subdevice logic.
65
+    */
66
+
67
+   *num_pcm = 0;
68
 
69
-   /* Check if some pcm devices of the card cannot be opened because they are busy */
70
+   spa_scnprintf(path, sizeof(path), "/proc/asound/card%u", (unsigned int)device->id);
71
 
72
-   for (dev = -1; snd_ctl_pcm_next_device(ctl_hndl, &dev) >= 0 && dev >= 0;) {
73
-       char devpath[64];
74
-       int i;
75
+   if ((card = opendir(path)) == NULL)
76
+       goto done;
77
 
78
-       snprintf(devpath, sizeof(devpath), "hw:%u,%u", device->id, dev);
79
+   while ((errno = 0, entry = readdir(card)) != NULL) {
80
+       if (!(entry->d_type == DT_DIR &&
81
+               spa_strstartswith(entry->d_name, "pcm")))
82
+           continue;
83
 
84
-       for (i = 0; i < 2; ++i) {
85
-           snd_pcm_t *handle;
86
-           int res;
87
+       /* Check device class */
88
+       spa_scnprintf(path, sizeof(path), "/sys/class/sound/pcmC%uD%s/pcm_class",
89
+               (unsigned int)device->id, entry->d_name+3);
90
+       f = fopen(path, "r");
91
+       if (f == NULL)
92
+           goto done;
93
+       sz = fread(buf, 1, sizeof(buf) - 1, f);
94
+       buf[sz] = '\0';
95
+       fclose(f);
96
+       if (spa_strstartswith(buf, "modem"))
97
+           continue;
98
 
99
-           res = snd_pcm_open(&handle, devpath,
100
-                   (i == 0) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE,
101
-                   SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE |
102
-                   SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT);
103
-           if (res == -EBUSY) {
104
-               spa_log_debug(this->log, "pcm device %s busy", devpath);
105
-               return -EBUSY;
106
-           } else if (res >= 0) {
107
-               snd_pcm_close(handle);
108
+       /* Check busy status */
109
+       spa_scnprintf(path, sizeof(path), "/proc/asound/card%u/%s",
110
+               (unsigned int)device->id, entry->d_name);
111
+       if ((pcm = opendir(path)) == NULL)
112
+           goto done;
113
+
114
+       while ((errno = 0, entry_pcm = readdir(pcm)) != NULL) {
115
+           if (!(entry_pcm->d_type == DT_DIR &&
116
+                   spa_strstartswith(entry_pcm->d_name, "sub")))
117
+               continue;
118
+
119
+           spa_scnprintf(path, sizeof(path), "/proc/asound/card%u/%s/%s/status",
120
+                   (unsigned int)device->id, entry->d_name, entry_pcm->d_name);
121
+
122
+           f = fopen(path, "r");
123
+           if (f == NULL)
124
+               goto done;
125
+           sz = fread(buf, 1, 6, f);
126
+           buf[sz] = '\0';
127
+           fclose(f);
128
+
129
+           if (!spa_strstartswith(buf, "closed")) {
130
+               spa_log_debug(this->log, "card %u pcm device %s busy",
131
+                       (unsigned int)device->id, entry->d_name);
132
+               errno = EBUSY;
133
+               goto done;
134
            }
135
+           spa_log_debug(this->log, "card %u pcm device %s free",
136
+                   (unsigned int)device->id, entry->d_name);
137
        }
138
-       spa_log_debug(this->log, "pcm device %s free", devpath);
139
-   }
140
+       if (errno != 0)
141
+           goto done;
142
 
143
-   return 0;
144
+       ++*num_pcm;
145
+
146
+       closedir(pcm);
147
+       pcm = NULL;
148
+   }
149
+   if (errno != 0)
150
+       goto done;
151
+
152
+done:
153
+   res = -errno;
154
+   if (card)
155
+       closedir(card);
156
+   if (pcm)
157
+       closedir(pcm);
158
+   return res;
159
 }
160
 
161
 static int emit_object_info(struct impl *this, struct device *device)
162
@@ -287,42 +341,28 @@
163
    struct spa_device_object_info info;
164
    uint32_t id = device->id;
165
    struct udev_device *dev = device->dev;
166
-   snd_ctl_t *ctl_hndl;
167
    const char *str;
168
    char path[32], *cn = NULL, *cln = NULL;
169
    struct spa_dict_item items[25];
170
    uint32_t n_items = 0;
171
    int res, pcm;
172
 
173
-   snprintf(path, sizeof(path), "hw:%u", id);
174
-   spa_log_debug(this->log, "open card %s", path);
175
+   /*
176
+    * inotify close events under /dev/snd must not be emitted, except after setting
177
+    * device->emitted to true. alsalib functions can be used after that.
178
+    */
179
 
180
-   if ((res = snd_ctl_open(&ctl_hndl, path, 0)) < 0) {
181
-       spa_log_error(this->log, "can't open control for card %s: %s",
182
-               path, snd_strerror(res));
183
+   if ((res = check_device_available(this, device, &pcm)) < 0)
184
        return res;
185
-   }
186
-
187
-   pcm = -1;
188
-   res = snd_ctl_pcm_next_device(ctl_hndl, &pcm);
189
-
190
-   if (res < 0) {
191
-       spa_log_error(this->log, "error iterating devices: %s", snd_strerror(res));
192
-       device->ignored = true;
193
-   } else if (pcm < 0) {
194
+   if (pcm == 0) {
195
        spa_log_debug(this->log, "no pcm devices for %s", path);
196
        device->ignored = true;
197
-       res = 0;
198
-   } else if (device->retry > 0) {
199
-       /* Check if we can open all PCM devices (retry later if not) */
200
-       res = check_device_busy(this, device, ctl_hndl);
201
+       return 0;
202
    }
203
 
204
-   spa_log_debug(this->log, "close card %s", path);
205
-   snd_ctl_close(ctl_hndl);
206
-
207
-   if (res < 0 || device->ignored)
208
-       return res;
209
+   snprintf(path, sizeof(path), "hw:%u", id);
210
+   spa_log_debug(this->log, "emitting card %s", path);
211
+   device->emitted = true;
212
 
213
    info = SPA_DEVICE_OBJECT_INFO_INIT();
214
 
215
@@ -429,96 +469,22 @@
216
    info.props = &SPA_DICT_INIT(items, n_items);
217
 
218
    spa_device_emit_object_info(&this->hooks, id, &info);
219
-   device->emitted = true;
220
    free(cn);
221
    free(cln);
222
 
223
    return 1;
224
 }
225
 
226
-static void start_retry(struct impl *this);
227
-
228
-static void stop_retry(struct impl *this);
229
-
230
-static void retry_timer_event(struct spa_source *source)
231
-{
232
-   struct impl *this = source->data;
233
-   bool have_retry = false;
234
-   size_t i;
235
-
236
-   stop_retry(this);
237
-
238
-   for (i = 0; i < this->n_devices; ++i) {
239
-       struct device *device = &this->devices[i];
240
-       if (device->ignored)
241
-           device->retry = 0;
242
-       if (device->retry > 0) {
243
-           --device->retry;
244
-
245
-           spa_log_debug(this->log, "retrying device %u", device->id);
246
-
247
-           if (emit_object_info(this, device) == -EBUSY) {
248
-               spa_log_debug(this->log, "device %u busy (remaining retries %u)",
249
-                       device->id, device->retry);
250
-           } else {
251
-               device->retry = 0;
252
-           }
253
-       }
254
-       if (device->retry > 0)
255
-           have_retry = true;
256
-   }
257
-
258
-   if (have_retry)
259
-       start_retry(this);
260
-}
261
-
262
-static void start_retry(struct impl *this)
263
-{
264
-   struct itimerspec ts;
265
-
266
-   spa_log_debug(this->log, "start retry");
267
-
268
-   if (this->retry_timer.data == NULL) {
269
-       this->retry_timer.data = this;
270
-       this->retry_timer.func = retry_timer_event;
271
-       this->retry_timer.mask = SPA_IO_IN;
272
-       this->retry_timer.rmask = 0;
273
-       spa_loop_add_source(this->main_loop, &this->retry_timer);
274
-   }
275
-
276
-   ts.it_value.tv_sec = ((uint64_t)RETRY_MSEC * SPA_NSEC_PER_MSEC) / SPA_NSEC_PER_SEC;
277
-   ts.it_value.tv_nsec = ((uint64_t)RETRY_MSEC * SPA_NSEC_PER_MSEC) % SPA_NSEC_PER_SEC;
278
-   ts.it_interval.tv_sec = 0;
279
-   ts.it_interval.tv_nsec = 0;
280
-   spa_system_timerfd_settime(this->main_system, this->retry_timer.fd, 0, &ts, NULL);
281
-}
282
-
283
-static void stop_retry(struct impl *this)
284
-{
285
-   struct itimerspec ts;
286
-
287
-   if (this->retry_timer.data == NULL)
288
-       return;
289
-
290
-   spa_log_debug(this->log, "stop retry");
291
-
292
-   spa_loop_remove_source(this->main_loop, &this->retry_timer);
293
-   this->retry_timer.data = NULL;
294
-
295
-   ts.it_value.tv_sec = 0;
296
-   ts.it_value.tv_nsec = 0;
297
-   ts.it_interval.tv_sec = 0;
298
-   ts.it_interval.tv_nsec = 0;
299
-   spa_system_timerfd_settime(this->main_system, this->retry_timer.fd, 0, &ts, NULL);
300
-}
301
-
302
 static bool check_access(struct impl *this, struct device *device)
303
 {
304
    char path[128];
305
+   bool accessible;
306
 
307
    snprintf(path, sizeof(path), "/dev/snd/controlC%u", device->id);
308
-   device->accessible = access(path, R_OK|W_OK) >= 0;
309
-   spa_log_debug(this->log, "%s accessible:%u", path, device->accessible);
310
+   accessible = access(path, R_OK|W_OK) >= 0;
311
+   if (accessible != device->accessible)
312
+       spa_log_debug(this->log, "%s accessible:%u", path, accessible);
313
+   device->accessible = accessible;
314
 
315
    return device->accessible;
316
 }
317
@@ -528,6 +494,7 @@
318
    uint32_t id;
319
    struct device *device;
320
    bool emitted;
321
+   int res;
322
 
323
    if ((id = get_card_id(this, dev)) == SPA_ID_INVALID)
324
        return;
325
@@ -544,13 +511,23 @@
326
            return;
327
        if (!check_access(this, device))
328
            return;
329
-       device->retry = RETRY_COUNT;
330
-       if (emit_object_info(this, device) == -EBUSY) {
331
-           spa_log_debug(this->log, "device %u busy (remaining retries %u)",
332
-                   device->id, device->retry);
333
-           start_retry(this);
334
+       res = emit_object_info(this, device);
335
+       if (res < 0) {
336
+           if (device->ignored)
337
+               spa_log_info(this->log, "ALSA card %u unavailable (%s): it is ignored",
338
+                       device->id, spa_strerror(res));
339
+           else if (!device->unavailable)
340
+               spa_log_info(this->log, "ALSA card %u unavailable (%s): wait for it",
341
+                       device->id, spa_strerror(res));
342
+           else
343
+               spa_log_debug(this->log, "ALSA card %u still unavailable (%s)",
344
+                       device->id, spa_strerror(res));
345
+           device->unavailable = true;
346
        } else {
347
-           device->retry = 0;
348
+           if (device->unavailable)
349
+               spa_log_info(this->log, "ALSA card %u now available",
350
+                       device->id);
351
+           device->unavailable = false;
352
        }
353
        break;
354
 
355
@@ -566,7 +543,6 @@
356
    case ACTION_DISABLE:
357
        if (device == NULL)
358
            return;
359
-       device->retry = 0;
360
        if (device->emitted) {
361
            device->emitted = false;
362
            spa_device_emit_object_info(&this->hooks, id, NULL);
363
@@ -615,12 +591,19 @@
364
 
365
            event = (const struct inotify_event *) p;
366
 
367
-           if ((event->mask & IN_ATTRIB)) {
368
+           /* Device becomes accessible or not busy */
369
+           if ((event->mask & (IN_ATTRIB | IN_CLOSE_WRITE))) {
370
                bool access;
371
-               if (sscanf(event->name, "controlC%u", &id) != 1)
372
+
373
+               if ((event->mask & IN_ATTRIB) &&
374
+                       spa_strstartswith(event->name, "pcm"))
375
+                   continue;
376
+               if (sscanf(event->name, "controlC%u", &id) != 1 &&
377
+                       sscanf(event->name, "pcmC%uD", &id) != 1)
378
                    continue;
379
                if ((device = find_device(this, id)) == NULL)
380
                    continue;
381
+
382
                access = check_access(this, device);
383
                if (access && !device->emitted)
384
                    process_device(this, ACTION_ADD, device->dev);
385
@@ -855,10 +838,6 @@
386
    struct impl *this = (struct impl *) handle;
387
    stop_monitor(this);
388
    impl_udev_close(this);
389
-   stop_retry(this);
390
-   if (this->retry_timer.fd >= 0)
391
-       spa_system_close(this->main_system, this->retry_timer.fd);
392
-   this->retry_timer.fd = -1;
393
    return 0;
394
 }
395
 
396
@@ -887,7 +866,6 @@
397
 
398
    this = (struct impl *) handle;
399
    this->notify.fd = -1;
400
-   this->retry_timer.fd = -1;
401
 
402
    this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
403
    alsa_log_topic_init(this->log);
404
@@ -919,9 +897,6 @@
405
            this->use_acp = spa_atob(str);
406
    }
407
 
408
-   this->retry_timer.fd = spa_system_timerfd_create(this->main_system,
409
-           CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
410
-
411
    return 0;
412
 }
413
 
414
pipewire-0.3.44.tar.gz/spa/plugins/alsa/mixer/profile-sets/texas-instruments-pcm2902.conf -> pipewire-0.3.45.tar.gz/spa/plugins/alsa/mixer/profile-sets/texas-instruments-pcm2902.conf Changed
52
 
1
@@ -16,12 +16,15 @@
2
 ; Texas Instruments PCM2902
3
 ;
4
 ; This is a generic chip used in multiple products, including at least
5
-; Behringer U-Phoria UMC22, Intopic Jazz-UB700 and some unbranded "usb mini
6
-; microphone".
7
+; Behringer U-Phoria UMC22, Behringer Xenyx 302USB, Intopic Jazz-UB700 and
8
+; some unbranded "usb mini microphone".
9
 ;
10
 ; Behringer UMC22 has stereo input (representing two physical mono inputs),
11
 ; others have mono input.
12
 ;
13
+; Some devices have a mic input path, but at least Behringer Xenyx 302USB
14
+; doesn't have any input mixer controls.
15
+;
16
 ; Since the UMC22 card has only stereo input PCM device but is commonly used
17
 ; with mono mics, we define special mono mappings using "mono,aux1" and
18
 ; "aux1,mono" channel maps. If we had only had the standard stereo input
19
@@ -40,28 +43,28 @@
20
 [Mapping analog-stereo-input]
21
 device-strings = hw:%f
22
 channel-map = left,right
23
-paths-input = analog-input-mic
24
+paths-input = analog-input-mic analog-input
25
 direction = input
26
 priority = 4
27
 
28
 [Mapping analog-mono]
29
 device-strings = hw:%f
30
 channel-map = mono
31
-paths-input = analog-input-mic
32
+paths-input = analog-input-mic analog-input
33
 direction = input
34
 priority = 3
35
 
36
 [Mapping analog-mono-left]
37
 device-strings = hw:%f
38
 channel-map = mono,aux1
39
-paths-input = analog-input-mic
40
+paths-input = analog-input-mic analog-input
41
 direction = input
42
 priority = 2
43
 
44
 [Mapping analog-mono-right]
45
 device-strings = hw:%f
46
 channel-map = aux1,mono
47
-paths-input = analog-input-mic
48
+paths-input = analog-input-mic analog-input
49
 direction = input
50
 priority = 1
51
 
52
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/channelmix-ops.h -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/channelmix-ops.h Changed
10
 
1
@@ -93,6 +93,8 @@
2
        uint32_t n_src, const void * SPA_RESTRICT src[n_src],   \
3
        uint32_t n_samples);
4
 
5
+#define CHANNELMIX_OPS_MAX_ALIGN 16
6
+
7
 DEFINE_FUNCTION(copy, c);
8
 DEFINE_FUNCTION(f32_n_m, c);
9
 DEFINE_FUNCTION(f32_1_2, c);
10
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/channelmix.c -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/channelmix.c Changed
38
 
1
@@ -50,6 +50,7 @@
2
 
3
 #define MAX_BUFFERS    32
4
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
5
+#define MAX_ALIGN  CHANNELMIX_OPS_MAX_ALIGN
6
 
7
 #define DEFAULT_CONTROL_BUFFER_SIZE    32768
8
 
9
@@ -164,6 +165,7 @@
10
    unsigned int started:1;
11
    unsigned int is_passthrough:1;
12
    uint32_t cpu_flags;
13
+   uint32_t max_align;
14
 };
15
 
16
 #define IS_CONTROL_PORT(this,d,id) (id == 1 && d == SPA_DIRECTION_INPUT)
17
@@ -1207,7 +1209,7 @@
18
                          buffers[i]);
19
                return -EINVAL;
20
            }
21
-           if (!SPA_IS_ALIGNED(d[j].data, 16)) {
22
+           if (!SPA_IS_ALIGNED(d[j].data, this->max_align)) {
23
                spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned",
24
                        this, j, i);
25
            }
26
@@ -1559,8 +1561,10 @@
27
    spa_log_topic_init(this->log, log_topic);
28
 
29
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
30
-   if (this->cpu)
31
+   if (this->cpu) {
32
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
33
+       this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
34
+   }
35
 
36
    spa_hook_list_init(&this->hooks);
37
 
38
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/fmt-ops.h Changed
10
 
1
@@ -200,6 +200,8 @@
2
 void conv_##name##_##arch(struct convert *conv, void * SPA_RESTRICT dst[], \
3
        const void * SPA_RESTRICT src[], uint32_t n_samples)        \
4
 
5
+#define FMT_OPS_MAX_ALIGN  32
6
+
7
 DEFINE_FUNCTION(copy8d, c);
8
 DEFINE_FUNCTION(copy8, c);
9
 DEFINE_FUNCTION(copy16d, c);
10
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/fmtconvert.c -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/fmtconvert.c Changed
39
 
1
@@ -53,7 +53,7 @@
2
 #define DEFAULT_CHANNELS   2
3
 
4
 #define MAX_BUFFERS    32
5
-#define MAX_ALIGN  16
6
+#define MAX_ALIGN  FMT_OPS_MAX_ALIGN
7
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
8
 
9
 #define PROP_DEFAULT_TRUNCATE  false
10
@@ -118,6 +118,7 @@
11
    struct spa_log *log;
12
    struct spa_cpu *cpu;
13
    uint32_t cpu_flags;
14
+   uint32_t max_align;
15
    uint32_t quantum_limit;
16
 
17
    struct spa_io_position *io_position;
18
@@ -812,7 +813,7 @@
19
                        this, j, i);
20
                return -EINVAL;
21
            }
22
-           if (!SPA_IS_ALIGNED(d[j].data, MAX_ALIGN)) {
23
+           if (!SPA_IS_ALIGNED(d[j].data, this->max_align)) {
24
                spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned",
25
                        this, j, i);
26
            }
27
@@ -1091,8 +1092,10 @@
28
    spa_log_topic_init(this->log, log_topic);
29
 
30
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
31
-   if (this->cpu)
32
+   if (this->cpu) {
33
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
34
+       this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
35
+   }
36
 
37
    for (i = 0; info && i < info->n_items; i++) {
38
        const char *k = info->items[i].key;
39
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/merger.c -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/merger.c Changed
39
 
1
@@ -55,7 +55,7 @@
2
 #define DEFAULT_RATE       48000
3
 #define DEFAULT_CHANNELS   2
4
 
5
-#define MAX_ALIGN  16
6
+#define MAX_ALIGN  FMT_OPS_MAX_ALIGN
7
 #define MAX_BUFFERS    32
8
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
9
 #define MAX_PORTS  SPA_AUDIO_MAX_CHANNELS
10
@@ -146,6 +146,7 @@
11
    struct spa_cpu *cpu;
12
 
13
    uint32_t cpu_flags;
14
+   uint32_t max_align;
15
    uint32_t quantum_limit;
16
 
17
    struct spa_io_position *io_position;
18
@@ -1265,7 +1266,7 @@
19
                        this, j, i, d[j].type, d[j].data);
20
                return -EINVAL;
21
            }
22
-           if (!SPA_IS_ALIGNED(d[j].data, MAX_ALIGN)) {
23
+           if (!SPA_IS_ALIGNED(d[j].data, this->max_align)) {
24
                spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned",
25
                        this, j, i);
26
            }
27
@@ -1576,8 +1577,10 @@
28
    spa_log_topic_init(this->log, log_topic);
29
 
30
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
31
-   if (this->cpu)
32
+   if (this->cpu) {
33
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
34
+       this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
35
+   }
36
 
37
    for (i = 0; info && i < info->n_items; i++) {
38
        const char *k = info->items[i].key;
39
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/resample.c -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/resample.c Changed
9
 
1
@@ -48,7 +48,6 @@
2
 #define DEFAULT_RATE       48000
3
 #define DEFAULT_CHANNELS   2
4
 
5
-#define MAX_ALIGN  16
6
 #define MAX_BUFFERS    32
7
 
8
 struct impl;
9
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/splitter.c -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/splitter.c Changed
39
 
1
@@ -53,7 +53,7 @@
2
 #define DEFAULT_CHANNELS   2
3
 #define DEFAULT_MASK       (1LL << SPA_AUDIO_CHANNEL_FL) | (1LL << SPA_AUDIO_CHANNEL_FR)
4
 
5
-#define MAX_ALIGN  16
6
+#define MAX_ALIGN  FMT_OPS_MAX_ALIGN
7
 #define MAX_BUFFERS    32
8
 #define MAX_DATAS  SPA_AUDIO_MAX_CHANNELS
9
 #define MAX_PORTS  SPA_AUDIO_MAX_CHANNELS
10
@@ -107,6 +107,7 @@
11
    struct spa_cpu *cpu;
12
 
13
    uint32_t cpu_flags;
14
+   uint32_t max_align;
15
    uint32_t quantum_limit;
16
 
17
    struct spa_io_position *io_position;
18
@@ -916,7 +917,7 @@
19
                        this, j, i, d[j].type, d[j].data);
20
                return -EINVAL;
21
            }
22
-           if (!SPA_IS_ALIGNED(d[j].data, MAX_ALIGN)) {
23
+           if (!SPA_IS_ALIGNED(d[j].data, this->max_align)) {
24
                spa_log_warn(this->log, "%p: memory %d on buffer %d not aligned",
25
                        this, j, i);
26
            }
27
@@ -1164,8 +1165,10 @@
28
    spa_log_topic_init(this->log, log_topic);
29
 
30
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
31
-   if (this->cpu)
32
+   if (this->cpu) {
33
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
34
+       this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
35
+   }
36
 
37
    for (i = 0; info && i < info->n_items; i++) {
38
        const char *k = info->items[i].key;
39
pipewire-0.3.44.tar.gz/spa/plugins/audioconvert/volume-ops.h -> pipewire-0.3.45.tar.gz/spa/plugins/audioconvert/volume-ops.h Changed
10
 
1
@@ -56,6 +56,8 @@
2
        const void * SPA_RESTRICT src,      \
3
        float volume, uint32_t n_samples);
4
 
5
+#define VOLUME_OPS_MAX_ALIGN   16
6
+
7
 DEFINE_FUNCTION(f32, c);
8
 
9
 #if defined (HAVE_SSE)
10
pipewire-0.3.44.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.45.tar.gz/spa/plugins/audiomixer/audiomixer.c Changed
38
 
1
@@ -48,6 +48,7 @@
2
 #define MAX_BUFFERS     64
3
 #define MAX_PORTS       128
4
 #define MAX_CHANNELS    64
5
+#define MAX_ALIGN  MIX_OPS_MAX_ALIGN
6
 
7
 #define PORT_DEFAULT_VOLUME    1.0
8
 #define PORT_DEFAULT_MUTE  false
9
@@ -103,6 +104,7 @@
10
    struct spa_log *log;
11
    struct spa_cpu *cpu;
12
    uint32_t cpu_flags;
13
+   uint32_t max_align;
14
    uint32_t quantum_limit;
15
 
16
    struct mix_ops ops;
17
@@ -658,7 +660,7 @@
18
                      buffers[i]);
19
            return -EINVAL;
20
        }
21
-       if (!SPA_IS_ALIGNED(d[0].data, 16)) {
22
+       if (!SPA_IS_ALIGNED(d[0].data, this->max_align)) {
23
            spa_log_warn(this->log, "%p: memory on buffer %d not aligned", this, i);
24
        }
25
        if (direction == SPA_DIRECTION_OUTPUT)
26
@@ -888,8 +890,10 @@
27
    spa_log_topic_init(this->log, log_topic);
28
 
29
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
30
-   if (this->cpu)
31
+   if (this->cpu) {
32
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
33
+       this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
34
+   }
35
 
36
    for (i = 0; info && i < info->n_items; i++) {
37
        const char *k = info->items[i].key;
38
pipewire-0.3.44.tar.gz/spa/plugins/audiomixer/mix-ops.h -> pipewire-0.3.45.tar.gz/spa/plugins/audiomixer/mix-ops.h Changed
10
 
1
@@ -125,6 +125,8 @@
2
        const void * SPA_RESTRICT src[], uint32_t n_src,        \
3
        uint32_t n_samples)                     \
4
 
5
+#define MIX_OPS_MAX_ALIGN  32
6
+
7
 DEFINE_FUNCTION(s8, c);
8
 DEFINE_FUNCTION(u8, c);
9
 DEFINE_FUNCTION(s16, c);
10
pipewire-0.3.44.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.45.tar.gz/spa/plugins/audiomixer/mixer-dsp.c Changed
39
 
1
@@ -47,7 +47,7 @@
2
 
3
 #define MAX_BUFFERS    64
4
 #define MAX_PORTS  128
5
-#define MAX_ALIGN  64
6
+#define MAX_ALIGN  MIX_OPS_MAX_ALIGN
7
 
8
 #define PORT_DEFAULT_VOLUME    1.0
9
 #define PORT_DEFAULT_MUTE  false
10
@@ -103,6 +103,7 @@
11
    struct spa_log *log;
12
    struct spa_cpu *cpu;
13
    uint32_t cpu_flags;
14
+   uint32_t max_align;
15
 
16
    uint32_t quantum_limit;
17
 
18
@@ -604,7 +605,7 @@
19
            spa_log_error(this->log, "%p: invalid memory on buffer %d", this, i);
20
            return -EINVAL;
21
        }
22
-       if (!SPA_IS_ALIGNED(d[0].data, 32)) {
23
+       if (!SPA_IS_ALIGNED(d[0].data, this->max_align)) {
24
            spa_log_warn(this->log, "%p: memory on buffer %d not aligned", this, i);
25
        }
26
        if (direction == SPA_DIRECTION_OUTPUT)
27
@@ -831,8 +832,10 @@
28
    spa_log_topic_init(this->log, log_topic);
29
 
30
    this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
31
-   if (this->cpu)
32
+   if (this->cpu) {
33
        this->cpu_flags = spa_cpu_get_flags(this->cpu);
34
+       this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
35
+   }
36
 
37
    for (i = 0; info && i < info->n_items; i++) {
38
        const char *k = info->items[i].key;
39
pipewire-0.3.44.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.45.tar.gz/spa/plugins/bluez5/backend-native.c Changed
169
 
1
@@ -201,12 +201,6 @@
2
    td = t->user_data;
3
    td->rfcomm = rfcomm;
4
 
5
-   for (int i = 0; i < SPA_BT_VOLUME_ID_TERM ; ++i) {
6
-       rfcomm->volumes[i].hw_volume = SPA_BT_VOLUME_INVALID;
7
-       t->volumes[i].active = rfcomm->volumes[i].active;
8
-       t->volumes[i].hw_volume_max = SPA_BT_VOLUME_HS_MAX;
9
-   }
10
-
11
    if (t->profile & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY) {
12
        t->volumes[SPA_BT_VOLUME_ID_RX].volume = DEFAULT_AG_VOLUME;
13
        t->volumes[SPA_BT_VOLUME_ID_TX].volume = DEFAULT_AG_VOLUME;
14
@@ -215,6 +209,14 @@
15
        t->volumes[SPA_BT_VOLUME_ID_TX].volume = DEFAULT_TX_VOLUME;
16
    }
17
 
18
+   for (int i = 0; i < SPA_BT_VOLUME_ID_TERM ; ++i) {
19
+       t->volumes[i].active = rfcomm->volumes[i].active;
20
+       t->volumes[i].hw_volume_max = SPA_BT_VOLUME_HS_MAX;
21
+       if (rfcomm->volumes[i].active && rfcomm->volumes[i].hw_volume != SPA_BT_VOLUME_INVALID)
22
+           t->volumes[i].volume =
23
+               spa_bt_volume_hw_to_linear(rfcomm->volumes[i].hw_volume, t->volumes[i].hw_volume_max);
24
+   }
25
+
26
    spa_bt_transport_add_listener(t, &rfcomm->transport_listener, &transport_events, rfcomm);
27
 
28
 finish:
29
@@ -550,11 +552,10 @@
30
 
31
 #ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
32
 
33
-static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapter, bool msbc);
34
-
35
 static bool device_supports_required_mSBC_transport_modes(
36
-       struct impl *backend, struct spa_bt_device *device) {
37
-   int sock;
38
+       struct impl *backend, struct spa_bt_device *device)
39
+{
40
+   int res;
41
    bool msbc_ok, msbc_alt1_ok;
42
    uint32_t bt_features;
43
 
44
@@ -575,43 +576,20 @@
45
    if (!msbc_ok && !msbc_alt1_ok)
46
        return false;
47
 
48
-   /*
49
-    * Check if adapter supports BT_VOICE_TRANSPARENT. Do this without
50
-    * directly probing HCI properties.
51
-    */
52
-   sock = sco_create_socket(backend, device->adapter, true);
53
-   if (sock < 0) {
54
+   res = spa_bt_adapter_has_msbc(device->adapter);
55
+   if (res < 0) {
56
+       spa_log_warn(backend->log,
57
+               "adapter %s: failed to determine msbc/esco capability (%d)",
58
+               device->adapter->path, res);
59
+   } else if (res == 0) {
60
+       spa_log_info(backend->log,
61
+               "adapter %s: no msbc/esco transport",
62
+               device->adapter->path);
63
        return false;
64
    } else {
65
-       struct sockaddr_sco addr;
66
-       socklen_t len;
67
-       int res;
68
-
69
-       /* Connect to non-existent address */
70
-       len = sizeof(addr);
71
-       memset(&addr, 0, len);
72
-       addr.sco_family = AF_BLUETOOTH;
73
-       bacpy(&addr.sco_bdaddr, BDADDR_LOCAL);
74
-
75
-       spa_log_debug(backend->log, "connect to determine adapter msbc support...");
76
-
77
-       /* Linux kernel code checks for features needed for BT_VOICE_TRANSPARENT
78
-        * among the first checks it does, and fails with EOPNOTSUPP if not
79
-        * supported. The connection generally timeouts, so set it
80
-        * nonblocking since we are just checking.
81
-        */
82
-       fcntl(sock, F_SETFL, O_NONBLOCK);
83
-       res = connect(sock, (struct sockaddr *) &addr, len);
84
-       if (res < 0)
85
-           res = errno;
86
-       else
87
-           res = 0;
88
-       close(sock);
89
-
90
-       spa_log_debug(backend->log, "determined adapter-msbc:%d res:%d",
91
-               (res != EOPNOTSUPP), res);
92
-       if (res == EOPNOTSUPP)
93
-           return false;
94
+       spa_log_debug(backend->log,
95
+               "adapter %s: has msbc/esco transport",
96
+               device->adapter->path);
97
    }
98
 
99
    /* Check if USB ALT6 is really available on the device */
100
@@ -705,7 +683,6 @@
101
    unsigned int indicator_value;
102
    int xapl_vendor;
103
    int xapl_product;
104
-   int xapl_version;
105
    int xapl_features;
106
 
107
    if (sscanf(buf, "AT+BRSF=%u", &features) == 1) {
108
@@ -889,7 +866,7 @@
109
        rfcomm_send_reply(rfcomm, "OK");
110
    } else if (sscanf(buf, "AT+BIEV=%u,%u", &indicator, &indicator_value) == 2) {
111
        process_hfp_hf_indicator(rfcomm, indicator, indicator_value);
112
-   } else if (sscanf(buf, "AT+XAPL=%04x-%04x-%04x,%u", &xapl_vendor, &xapl_product, &xapl_version, &xapl_features) == 4) {
113
+   } else if (sscanf(buf, "AT+XAPL=%04x-%04x-%*[^,],%u", &xapl_vendor, &xapl_product, &xapl_features) == 3) {
114
        if (xapl_features & SPA_BT_HFP_HF_XAPL_FEATURE_BATTERY_REPORTING) {
115
            /* claim, that we support battery status reports */
116
            rfcomm_send_reply(rfcomm, "+XAPL=iPhone,%u", SPA_BT_HFP_HF_XAPL_FEATURE_BATTERY_REPORTING);
117
@@ -1155,6 +1132,7 @@
118
 {
119
    struct impl *backend = SPA_CONTAINER_OF(t->backend, struct impl, this);
120
    struct spa_bt_device *d = t->device;
121
+   struct transport_data *td = t->user_data;
122
    struct sockaddr_sco addr;
123
    socklen_t len;
124
    int err;
125
@@ -1189,6 +1167,21 @@
126
        goto again;
127
    } else if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
128
        spa_log_error(backend->log, "connect(): %s", strerror(errno));
129
+#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
130
+       if (errno == EOPNOTSUPP && t->codec == HFP_AUDIO_CODEC_MSBC &&
131
+               td->rfcomm->msbc_supported_by_hfp) {
132
+           /* Adapter doesn't support msbc. Renegotiate. */
133
+           d->adapter->msbc_probed = true;
134
+           d->adapter->has_msbc = false;
135
+           td->rfcomm->msbc_supported_by_hfp = false;
136
+           if (t->profile == SPA_BT_PROFILE_HFP_HF) {
137
+               td->rfcomm->hfp_ag_switching_codec = true;
138
+               rfcomm_send_reply(td->rfcomm, "+BCS: 1");
139
+           } else if (t->profile == SPA_BT_PROFILE_HFP_AG) {
140
+               rfcomm_send_cmd(td->rfcomm, "AT+BAC=1");
141
+           }
142
+       }
143
+#endif
144
        goto fail_close;
145
    }
146
 
147
@@ -1209,10 +1202,6 @@
148
 
149
    spa_log_debug(backend->log, "transport %p: enter sco_acquire_cb", t);
150
 
151
-#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
152
-   rfcomm_hfp_ag_set_cind(td->rfcomm, true);
153
-#endif
154
-
155
    if (optional || t->fd > 0)
156
        sock = t->fd;
157
    else
158
@@ -1221,6 +1210,10 @@
159
    if (sock < 0)
160
        goto fail;
161
 
162
+#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
163
+   rfcomm_hfp_ag_set_cind(td->rfcomm, true);
164
+#endif
165
+
166
    t->fd = sock;
167
 
168
    /* Fallback value */
169
pipewire-0.3.44.tar.gz/spa/plugins/bluez5/bluez-hardware.conf -> pipewire-0.3.45.tar.gz/spa/plugins/bluez5/bluez-hardware.conf Changed
10
 
1
@@ -34,7 +34,7 @@
2
     { name = "BAA 100", no-features = [ hw-volume ] },  # Buxton BAA 100, doesn't remember volume, #pipewire-1449
3
     { name = "D50s", address = "~^00:13:ef:", no-features = [ hw-volume ] },  # volume has no effect, #pipewire-1562
4
     { name = "FiiO BTR3", address = "~^40:ed:98:", no-features = [ faststream ] },  # #pipewire-1658
5
-    { name = "JBL Endurance RUN BT", no-features = [ msbc-alt1, msbc-alt1-rtl, sbc-xq ] },
6
+    { name = "JBL Endurance RUN BT", no-features = [ msbc-alt1, msbc-alt1-rtl ] },
7
     { name = "JBL LIVE650BTNC" },
8
     { name = "Motorola DC800", no-features = [ sbc-xq ] },  # #pipewire-1590
9
     { name = "Motorola S305", no-features = [ sbc-xq ] },  # #pipewire-1590
10
pipewire-0.3.44.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.45.tar.gz/spa/plugins/bluez5/bluez5-dbus.c Changed
114
 
1
@@ -1823,6 +1823,8 @@
2
 
3
    spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_IDLE);
4
 
5
+   spa_bt_transport_keepalive(transport, false);
6
+
7
    spa_bt_transport_emit_destroy(transport);
8
 
9
    spa_bt_transport_stop_volume_timer(transport);
10
@@ -1857,6 +1859,23 @@
11
    free(transport);
12
 }
13
 
14
+int spa_bt_transport_keepalive(struct spa_bt_transport *t, bool keepalive)
15
+{
16
+   if (keepalive) {
17
+       t->keepalive = true;
18
+       return 0;
19
+   }
20
+
21
+   t->keepalive = false;
22
+
23
+   if (t->acquire_refcount == 0 && t->acquired) {
24
+       t->acquire_refcount = 1;
25
+       return spa_bt_transport_release(t);
26
+   }
27
+
28
+   return 0;
29
+}
30
+
31
 int spa_bt_transport_acquire(struct spa_bt_transport *transport, bool optional)
32
 {
33
    struct spa_bt_monitor *monitor = transport->monitor;
34
@@ -1869,10 +1888,15 @@
35
    }
36
    spa_assert(transport->acquire_refcount == 0);
37
 
38
-   res = spa_bt_transport_impl(transport, acquire, 0, optional);
39
+   if (!transport->acquired)
40
+       res = spa_bt_transport_impl(transport, acquire, 0, optional);
41
+   else
42
+       res = 0;
43
 
44
-   if (res >= 0)
45
+   if (res >= 0) {
46
        transport->acquire_refcount = 1;
47
+       transport->acquired = true;
48
+   }
49
 
50
    return res;
51
 }
52
@@ -1892,14 +1916,22 @@
53
        return 0;
54
    }
55
    spa_assert(transport->acquire_refcount == 1);
56
+   spa_assert(transport->acquired);
57
 
58
    if (SPA_BT_TRANSPORT_IS_SCO(transport)) {
59
        /* Postpone SCO transport releases, since we might need it again soon */
60
        res = spa_bt_transport_start_release_timer(transport);
61
+   } else if (transport->keepalive) {
62
+       res = 0;
63
+       transport->acquire_refcount = 0;
64
+       spa_log_debug(monitor->log, "transport %p: keepalive %s on release",
65
+               transport, transport->path);
66
    } else {
67
        res = spa_bt_transport_impl(transport, release, 0);
68
-       if (res >= 0)
69
+       if (res >= 0) {
70
            transport->acquire_refcount = 0;
71
+           transport->acquired = false;
72
+       }
73
    }
74
 
75
    return res;
76
@@ -1909,13 +1941,15 @@
77
 {
78
    int res;
79
 
80
-   if (transport->acquire_refcount == 0)
81
+   if (!transport->acquired)
82
        return 0;
83
 
84
    spa_bt_transport_stop_release_timer(transport);
85
    res = spa_bt_transport_impl(transport, release, 0);
86
-   if (res >= 0)
87
+   if (res >= 0) {
88
        transport->acquire_refcount = 0;
89
+       transport->acquired = false;
90
+   }
91
 
92
    return res;
93
 }
94
@@ -1974,11 +2008,18 @@
95
    struct spa_bt_monitor *monitor = transport->monitor;
96
 
97
    spa_assert(transport->acquire_refcount >= 1);
98
+   spa_assert(transport->acquired);
99
 
100
    spa_bt_transport_stop_release_timer(transport);
101
 
102
    if (transport->acquire_refcount == 1) {
103
-       spa_bt_transport_impl(transport, release, 0);
104
+       if (!transport->keepalive) {
105
+           spa_bt_transport_impl(transport, release, 0);
106
+           transport->acquired = false;
107
+       } else {
108
+           spa_log_debug(monitor->log, "transport %p: keepalive %s on release",
109
+                   transport, transport->path);
110
+       }
111
    } else {
112
        spa_log_debug(monitor->log, "transport %p: delayed decref %s", transport, transport->path);
113
    }
114
pipewire-0.3.44.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.45.tar.gz/spa/plugins/bluez5/bluez5-device.c Changed
15
 
1
@@ -519,11 +519,13 @@
2
    if (state >= SPA_BT_TRANSPORT_STATE_PENDING && old < SPA_BT_TRANSPORT_STATE_PENDING) {
3
        if (!SPA_FLAG_IS_SET(this->id, DYNAMIC_NODE_ID_FLAG)) {
4
            SPA_FLAG_SET(this->id, DYNAMIC_NODE_ID_FLAG);
5
+           spa_bt_transport_keepalive(t, true);
6
            emit_node(impl, t, this->id, this->factory_name, this->a2dp_duplex);
7
        }
8
    } else if (state < SPA_BT_TRANSPORT_STATE_PENDING && old >= SPA_BT_TRANSPORT_STATE_PENDING) {
9
        if (SPA_FLAG_IS_SET(this->id, DYNAMIC_NODE_ID_FLAG)) {
10
            SPA_FLAG_CLEAR(this->id, DYNAMIC_NODE_ID_FLAG);
11
+           spa_bt_transport_keepalive(t, false);
12
            spa_device_emit_object_info(&impl->hooks, this->id, NULL);
13
        }
14
    }
15
pipewire-0.3.44.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.45.tar.gz/spa/plugins/bluez5/defs.h Changed
43
 
1
@@ -332,11 +332,13 @@
2
    uint32_t bluetooth_class;
3
    uint32_t profiles;
4
    int powered;
5
+   unsigned int has_msbc:1;
6
+   unsigned int msbc_probed:1;
7
    unsigned int endpoints_registered:1;
8
    unsigned int application_registered:1;
9
    unsigned int player_registered:1;
10
-   unsigned int has_battery_provider;
11
-   unsigned int battery_provider_unavailable;
12
+   unsigned int has_battery_provider:1;
13
+   unsigned int battery_provider_unavailable:1;
14
 };
15
 
16
 enum spa_bt_form_factor {
17
@@ -581,6 +583,8 @@
18
    struct spa_bt_transport_volume volumes[SPA_BT_VOLUME_ID_TERM];
19
 
20
    int acquire_refcount;
21
+   bool acquired;
22
+   bool keepalive;
23
    int fd;
24
    uint16_t read_mtu;
25
    uint16_t write_mtu;
26
@@ -610,6 +614,7 @@
27
 
28
 int spa_bt_transport_acquire(struct spa_bt_transport *t, bool optional);
29
 int spa_bt_transport_release(struct spa_bt_transport *t);
30
+int spa_bt_transport_keepalive(struct spa_bt_transport *t, bool keepalive);
31
 int spa_bt_transport_ensure_sco_io(struct spa_bt_transport *t, struct spa_loop *data_loop);
32
 
33
 #define spa_bt_transport_emit(t,m,v,...)       spa_hook_list_call(&(t)->listener_list, \
34
@@ -696,6 +701,8 @@
35
        uint32_t *features);
36
 void spa_bt_quirks_destroy(struct spa_bt_quirks *quirks);
37
 
38
+int spa_bt_adapter_has_msbc(struct spa_bt_adapter *adapter);
39
+
40
 struct spa_bt_backend_implementation {
41
 #define SPA_VERSION_BT_BACKEND_IMPLEMENTATION  0
42
    uint32_t version;
43
pipewire-0.3.45.tar.gz/spa/plugins/bluez5/hci.c Added
95
 
1
@@ -0,0 +1,93 @@
2
+/* Spa HSP/HFP native backend HCI support
3
+ *
4
+ * Copyright © 2022 Pauli Virtanen
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice (including the next
14
+ * paragraph) shall be included in all copies or substantial portions of the
15
+ * Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ * DEALINGS IN THE SOFTWARE.
24
+ */
25
+
26
+#include <errno.h>
27
+#include <unistd.h>
28
+#include <stdarg.h>
29
+#include <sys/types.h>
30
+#include <sys/stat.h>
31
+#include <fcntl.h>
32
+#include <poll.h>
33
+#include <sys/uio.h>
34
+#include <sys/socket.h>
35
+
36
+#include "defs.h"
37
+
38
+#ifndef HAVE_BLUEZ_5_HCI
39
+
40
+int spa_bt_adapter_has_msbc(struct spa_bt_adapter *adapter)
41
+{
42
+   if (adapter->msbc_probed)
43
+       return adapter->has_msbc;
44
+   return -EOPNOTSUPP;
45
+}
46
+
47
+#else
48
+
49
+#include <bluetooth/bluetooth.h>
50
+#include <bluetooth/hci.h>
51
+#include <bluetooth/hci_lib.h>
52
+
53
+int spa_bt_adapter_has_msbc(struct spa_bt_adapter *adapter)
54
+{
55
+   int hci_id, res;
56
+   int sock = -1;
57
+   uint8_t features[8], max_page = 0;
58
+   struct sockaddr_hci a;
59
+   const char *str;
60
+
61
+   if (adapter->msbc_probed)
62
+       return adapter->has_msbc;
63
+
64
+   str = strrchr(adapter->path, '/');  /* hciXX */
65
+   if (str == NULL || sscanf(str, "/hci%d", &hci_id) != 1 || hci_id < 0)
66
+       return -ENOENT;
67
+
68
+   sock = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
69
+   if (sock < 0)
70
+       goto error;
71
+
72
+   memset(&a, 0, sizeof(a));
73
+   a.hci_family = AF_BLUETOOTH;
74
+   a.hci_dev = hci_id;
75
+   if (bind(sock, (struct sockaddr *) &a, sizeof(a)) < 0)
76
+       goto error;
77
+
78
+   if (hci_read_local_ext_features(sock, 0, &max_page, features, 1000) < 0)
79
+       goto error;
80
+
81
+   close(sock);
82
+
83
+   adapter->msbc_probed = true;
84
+   adapter->has_msbc = ((features[2] & LMP_TRSP_SCO) && (features[3] & LMP_ESCO)) ? 1 : 0;
85
+   return adapter->has_msbc;
86
+
87
+error:
88
+   res = -errno;
89
+   if (sock >= 0)
90
+       close(sock);
91
+   return res;
92
+}
93
+
94
+#endif
95
pipewire-0.3.44.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.45.tar.gz/spa/plugins/bluez5/meson.build Changed
22
 
1
@@ -20,6 +20,10 @@
2
   cdata.set('HAVE_BLUEZ_5_BACKEND_HSPHFPD', 1)
3
 endif
4
 
5
+if dependency('bluez', version: '< 6', required: false).found()
6
+  cdata.set('HAVE_BLUEZ_5_HCI', 1)
7
+endif
8
+
9
 bluez5_sources = [
10
   'plugin.c',
11
   'codec-loader.c',
12
@@ -32,7 +36,8 @@
13
   'quirks.c',
14
   'player.c',
15
   'bluez5-device.c',
16
-  'bluez5-dbus.c'
17
+  'bluez5-dbus.c',
18
+  'hci.c'
19
 ]
20
 
21
 bluez5_data = ['bluez-hardware.conf']
22
pipewire-0.3.44.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.45.tar.gz/spa/plugins/bluez5/sco-sink.c Changed
78
 
1
@@ -269,7 +269,7 @@
2
 static uint64_t get_next_timeout(struct impl *this, uint64_t now_time, uint64_t processed_samples)
3
 {
4
    struct port *port = &this->port;
5
-   uint64_t playback_time = 0, elapsed_time = 0, next_time = 1;
6
+   uint64_t playback_time = 0, elapsed_time = 0, next_time = 0;
7
 
8
    this->total_samples += processed_samples;
9
 
10
@@ -380,7 +380,6 @@
11
 {
12
    struct port *port = &this->port;
13
    struct spa_data *datas;
14
-   uint64_t next_timeout = 1;
15
    const uint32_t min_in_size =
16
        (this->transport->codec == HFP_AUDIO_CODEC_MSBC) ?
17
        MSBC_DECODED_SIZE : this->transport->write_mtu;
18
@@ -391,7 +390,8 @@
19
    if (this->transport == NULL || this->transport->sco_io == NULL)
20
        return;
21
 
22
-   if (!spa_list_is_empty(&port->ready)) {
23
+again:
24
+   while (!spa_list_is_empty(&port->ready) && port->write_buffer_size < min_in_size) {
25
        /* get buffer */
26
        if (!port->current_buffer) {
27
            spa_return_if_fail(!spa_list_is_empty(&port->ready));
28
@@ -434,6 +434,7 @@
29
        int processed = 0;
30
        ssize_t out_encoded;
31
        int written;
32
+       uint64_t next_timeout;
33
 
34
        spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &this->now);
35
        now_time = SPA_TIMESPEC_TO_NSEC(&this->now);
36
@@ -468,7 +469,6 @@
37
                        written, spa_strerror(written));
38
                goto stop;
39
            }
40
-           spa_log_trace(this->log, "wrote socket data %d", written);
41
 
42
            this->buffer_head += written;
43
 
44
@@ -507,17 +507,29 @@
45
 
46
        next_timeout = get_next_timeout(this, now_time, processed / port->frame_size);
47
 
48
-       if (this->clock) {
49
+       if (!this->following && this->clock) {
50
            this->clock->nsec = now_time;
51
            this->clock->position = this->total_samples;
52
            this->clock->delay = processed / port->frame_size;
53
            this->clock->rate_diff = 1.0f;
54
-           this->clock->next_nsec = next_timeout;
55
+           this->clock->next_nsec = now_time + next_timeout;
56
        }
57
+
58
+       if (next_timeout == 0)
59
+           goto again;
60
+
61
+       spa_log_trace(this->log, "timeout %"PRIu64" ns", next_timeout);
62
+       set_timeout(this, next_timeout);
63
+   } else {
64
+       /* As follower, driver will wake us up when there is data */
65
+       if (this->following)
66
+           return;
67
+
68
+       /* As driver, run timeout now to schedule data */
69
+       spa_log_trace(this->log, "timeout 1 ns (driver: schedule now)");
70
+       set_timeout(this, 1);
71
    }
72
 
73
-   /* schedule next timeout */
74
-   set_timeout(this, next_timeout);
75
    return;
76
 
77
 stop:
78
pipewire-0.3.44.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.45.tar.gz/spa/plugins/v4l2/v4l2-udev.c Changed
10
 
1
@@ -169,7 +169,7 @@
2
 {
3
    const char *s;
4
    char *d;
5
-   int h1, h2;
6
+   int h1 = 0, h2 = 0;
7
    enum { TEXT, BACKSLASH, EX, FIRST } state = TEXT;
8
 
9
    for (s = src, d = dst; *s; s++) {
10
pipewire-0.3.45.tar.gz/src/daemon/filter-chain/duplicate-FL.conf Added
50
 
1
@@ -0,0 +1,48 @@
2
+# An example filter chain for duplicating the FL channel
3
+# to FL and FR.
4
+#
5
+# Copy this file into a conf.d/ directory
6
+#
7
+context.modules = [
8
+    { name = libpipewire-module-filter-chain
9
+        args = {
10
+            node.name        = "remap-FL-to-FL-FR"
11
+            node.description = "Remap example"
12
+            media.name       = "Remap example"
13
+            filter.graph = {
14
+                nodes = [
15
+                    {
16
+                        name   = copyIL
17
+                        type   = builtin
18
+                        label  = copy
19
+                    }
20
+                    {
21
+                        name   = copyOL
22
+                        type   = builtin
23
+                        label  = copy
24
+                    }
25
+                    {
26
+                        name   = copyOR
27
+                        type   = builtin
28
+                        label  = copy
29
+                    }
30
+                ]
31
+                links = [
32
+           # we can only tee from nodes, not inputs so we need
33
+           # to copy the inputs and then tee.
34
+                    { output = "copyIL:Out" input = "copyOL:In" }
35
+                    { output = "copyIL:Out" input = "copyOR:In" }
36
+                ]
37
+                inputs  = [ "copyIL:In" ]
38
+                outputs = [ "copyOL:Out" "copyOR:Out" ]
39
+            }
40
+            capture.props = {
41
+                audio.position  = [ FL ]
42
+                stream.dont-remix = true
43
+            }
44
+            playback.props = {
45
+                audio.position  = [ FL FR ]
46
+            }
47
+        }
48
+    }
49
+]
50
pipewire-0.3.44.tar.gz/src/daemon/filter-chain/meson.build -> pipewire-0.3.45.tar.gz/src/daemon/filter-chain/meson.build Changed
8
 
1
@@ -1,5 +1,6 @@
2
 conf_files = [
3
   [ 'demonic.conf', 'demonic.conf' ],
4
+  [ 'duplicate-FL.conf', 'duplicate-FL.conf' ],
5
   [ 'sink-virtual-surround-5.1-kemar.conf', 'sink-virtual-surround-5.1-kemar.conf' ],
6
   [ 'sink-virtual-surround-7.1-hesuvi.conf', 'sink-virtual-surround-7.1-hesuvi.conf' ],
7
   [ 'sink-dolby-surround.conf', 'sink-dolby-surround.conf' ],
8
pipewire-0.3.44.tar.gz/src/examples/audio-dsp-filter.c -> pipewire-0.3.45.tar.gz/src/examples/audio-dsp-filter.c Changed
11
 
1
@@ -79,6 +79,9 @@
2
    in = pw_filter_get_dsp_buffer(data->in_port, n_samples);
3
    out = pw_filter_get_dsp_buffer(data->out_port, n_samples);
4
 
5
+   if (in == NULL || out == NULL)
6
+       return;
7
+
8
    memcpy(out, in, n_samples * sizeof(float));
9
 }
10
 
11
pipewire-0.3.44.tar.gz/src/examples/audio-dsp-src.c -> pipewire-0.3.45.tar.gz/src/examples/audio-dsp-src.c Changed
10
 
1
@@ -77,6 +77,8 @@
2
    pw_log_trace("do process %d", n_samples);
3
 
4
    out = pw_filter_get_dsp_buffer(out_port, n_samples);
5
+   if (out == NULL)
6
+       return;
7
 
8
    for (i = 0; i < n_samples; i++) {
9
        out_port->accumulator += M_PI_M2 * DEFAULT_FREQ / DEFAULT_RATE;
10
pipewire-0.3.44.tar.gz/src/modules/module-adapter.c -> pipewire-0.3.45.tar.gz/src/modules/module-adapter.c Changed
26
 
1
@@ -243,21 +243,16 @@
2
 
3
 error_properties:
4
    res = -EINVAL;
5
-   pw_log_error("factory %p: usage: " FACTORY_USAGE, d->this);
6
-   if (resource)
7
-       pw_resource_errorf_id(resource, new_id, res, "usage: " FACTORY_USAGE);
8
+   pw_resource_errorf_id(resource, new_id, res, "usage: " FACTORY_USAGE);
9
    goto error_cleanup;
10
 error_errno:
11
    res = -errno;
12
-   pw_log_error("can't create node: %m");
13
-   if (resource)
14
-       pw_resource_errorf_id(resource, new_id, res, "can't create node: %s", spa_strerror(res));
15
+   pw_resource_errorf_id(resource, new_id, res, "can't create node: %s", spa_strerror(res));
16
    goto error_cleanup;
17
 error_usage:
18
    res = -EINVAL;
19
    pw_log_error("usage: "ADAPTER_USAGE);
20
-   if (resource)
21
-       pw_resource_errorf_id(resource, new_id, res, "usage: "ADAPTER_USAGE);
22
+   pw_resource_errorf_id(resource, new_id, res, "usage: "ADAPTER_USAGE);
23
    goto error_cleanup;
24
 error_cleanup:
25
    pw_properties_free(properties);
26
pipewire-0.3.44.tar.gz/src/modules/module-client-device/protocol-native.c -> pipewire-0.3.45.tar.gz/src/modules/module-client-device/protocol-native.c Changed
134
 
1
@@ -32,6 +32,9 @@
2
 
3
 #include <pipewire/extensions/protocol-native.h>
4
 
5
+#define MAX_DICT   256
6
+#define MAX_PARAM_INFO 128
7
+
8
 static inline void push_item(struct spa_pod_builder *b, const struct spa_dict_item *item)
9
 {
10
    const char *str;
11
@@ -55,16 +58,41 @@
12
    return 0;
13
 }
14
 
15
-static inline int parse_dict(struct spa_pod_parser *prs, struct spa_dict *dict)
16
-{
17
-   uint32_t i;
18
-   int res;
19
-   for (i = 0; i < dict->n_items; i++) {
20
-       if ((res = parse_item(prs, (struct spa_dict_item *) &dict->items[i])) < 0)
21
-           return res;
22
-   }
23
-   return 0;
24
-}
25
+#define parse_dict(prs,d)                                  \
26
+do {                                               \
27
+   uint32_t i;                                     \
28
+   if (spa_pod_parser_get(prs,                             \
29
+            SPA_POD_Int(&(d)->n_items), NULL) < 0)                 \
30
+       return -EINVAL;                                 \
31
+   if ((d)->n_items > 0) {                                 \
32
+       if ((d)->n_items > MAX_DICT)                            \
33
+           return -ENOSPC;                             \
34
+       (d)->items = alloca((d)->n_items * sizeof(struct spa_dict_item));       \
35
+       for (i = 0; i < (d)->n_items; i++) {                        \
36
+           if (parse_item(prs, (struct spa_dict_item *) &(d)->items[i]) < 0)   \
37
+               return -EINVAL;                         \
38
+       }                                       \
39
+   }                                           \
40
+} while(0)
41
+
42
+#define parse_param_info(prs,n_params,params)                          \
43
+do {                                               \
44
+   uint32_t i;                                     \
45
+   if (spa_pod_parser_get(prs,                             \
46
+           SPA_POD_Int(&(n_params)), NULL) < 0)                    \
47
+       return -EINVAL;                                 \
48
+   if (n_params > 0) {                                 \
49
+       if (n_params > MAX_PARAM_INFO)                          \
50
+           return -ENOSPC;                             \
51
+       params = alloca(n_params * sizeof(struct spa_param_info));          \
52
+       for (i = 0; i < n_params; i++) {                        \
53
+           if (spa_pod_parser_get(prs,                     \
54
+                   SPA_POD_Id(&(params[i]).id),                \
55
+                   SPA_POD_Int(&(params[i]).flags), NULL) < 0)     \
56
+               return -EINVAL;                         \
57
+       }                                       \
58
+   }                                           \
59
+} while(0)
60
 
61
 static int device_marshal_add_listener(void *object,
62
            struct spa_hook *listener,
63
@@ -242,7 +270,6 @@
64
    struct spa_pod *ipod;
65
    struct spa_device_info info = SPA_DEVICE_INFO_INIT(), *infop;
66
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
67
-   uint32_t i;
68
 
69
    spa_pod_parser_init(&prs, msg->data, msg->size);
70
 
71
@@ -259,34 +286,18 @@
72
        if (spa_pod_parser_push_struct(&p2, &f2) < 0 ||
73
            spa_pod_parser_get(&p2,
74
                SPA_POD_Long(&info.change_mask),
75
-               SPA_POD_Long(&info.flags),
76
-               SPA_POD_Int(&props.n_items), NULL) < 0)
77
+               SPA_POD_Long(&info.flags), NULL) < 0)
78
            return -EINVAL;
79
 
80
        info.change_mask &= SPA_DEVICE_CHANGE_MASK_FLAGS |
81
                SPA_DEVICE_CHANGE_MASK_PROPS |
82
                SPA_DEVICE_CHANGE_MASK_PARAMS;
83
 
84
-       if (props.n_items > 0) {
85
+       parse_dict(&p2, &props);
86
+       if (props.n_items > 0)
87
            info.props = &props;
88
 
89
-           props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
90
-           if (parse_dict(&p2, &props) < 0)
91
-               return -EINVAL;
92
-       }
93
-       if (spa_pod_parser_get(&p2,
94
-               SPA_POD_Int(&info.n_params), NULL) < 0)
95
-           return -EINVAL;
96
-
97
-       if (info.n_params > 0) {
98
-           info.params = alloca(info.n_params * sizeof(struct spa_param_info));
99
-           for (i = 0; i < info.n_params; i++) {
100
-               if (spa_pod_parser_get(&p2,
101
-                       SPA_POD_Id(&info.params[i].id),
102
-                       SPA_POD_Int(&info.params[i].flags), NULL) < 0)
103
-                   return -EINVAL;
104
-           }
105
-       }
106
+       parse_param_info(&p2, info.n_params, info.params);
107
    }
108
    else {
109
        infop = NULL;
110
@@ -467,20 +478,15 @@
111
            spa_pod_parser_get(&p2,
112
                SPA_POD_String(&info.type),
113
                SPA_POD_Long(&info.change_mask),
114
-               SPA_POD_Long(&info.flags),
115
-               SPA_POD_Int(&props.n_items), NULL) < 0)
116
+               SPA_POD_Long(&info.flags), NULL) < 0)
117
            return -EINVAL;
118
 
119
        info.change_mask &= SPA_DEVICE_OBJECT_CHANGE_MASK_FLAGS |
120
                SPA_DEVICE_CHANGE_MASK_PROPS;
121
 
122
-       if (props.n_items > 0) {
123
+       parse_dict(&p2, &props);
124
+       if (props.n_items > 0)
125
            info.props = &props;
126
-
127
-           props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
128
-           if (parse_dict(&p2, &props) < 0)
129
-               return -EINVAL;
130
-       }
131
    } else {
132
        infop = NULL;
133
    }
134
pipewire-0.3.44.tar.gz/src/modules/module-client-node/client-node.c -> pipewire-0.3.45.tar.gz/src/modules/module-client-node/client-node.c Changed
11
 
1
@@ -755,6 +755,9 @@
2
    if (!CHECK_PORT(this, direction, port_id))
3
        return n_buffers == 0 ? 0 : -EINVAL;
4
 
5
+   if (n_buffers > MAX_BUFFERS)
6
+       return -ENOSPC;
7
+
8
    p = GET_PORT(this, direction, port_id);
9
 
10
    spa_log_debug(this->log, "%p: %s port %d.%d use buffers %p %u flags:%08x", this,
11
pipewire-0.3.44.tar.gz/src/modules/module-client-node/protocol-native.c -> pipewire-0.3.45.tar.gz/src/modules/module-client-node/protocol-native.c Changed
314
 
1
@@ -33,6 +33,13 @@
2
 #include <pipewire/extensions/protocol-native.h>
3
 #include <pipewire/extensions/client-node.h>
4
 
5
+#define MAX_DICT   256
6
+#define MAX_PARAMS 128
7
+#define MAX_PARAM_INFO 128
8
+#define MAX_BUFFERS    64
9
+#define MAX_METAS  16u
10
+#define MAX_DATAS  64u
11
+
12
 PW_LOG_TOPIC_EXTERN(mod_topic);
13
 #define PW_LOG_TOPIC_DEFAULT mod_topic
14
 
15
@@ -73,16 +80,70 @@
16
    return 0;
17
 }
18
 
19
-static inline int parse_dict(struct spa_pod_parser *prs, struct spa_dict *dict)
20
-{
21
-   uint32_t i;
22
-   int res;
23
-   for (i = 0; i < dict->n_items; i++) {
24
-       if ((res = parse_item(prs, (struct spa_dict_item *) &dict->items[i])) < 0)
25
-           return res;
26
-   }
27
-   return 0;
28
-}
29
+#define parse_dict(prs,d)                              \
30
+do {                                           \
31
+   uint32_t i;                                 \
32
+   if (spa_pod_parser_get(prs,                         \
33
+            SPA_POD_Int(&(d)->n_items), NULL) < 0)             \
34
+       return -EINVAL;                             \
35
+   (d)->items = NULL;                              \
36
+   if ((d)->n_items > 0) {                             \
37
+       if ((d)->n_items > MAX_DICT)                        \
38
+           return -ENOSPC;                         \
39
+       (d)->items = alloca((d)->n_items * sizeof(struct spa_dict_item));   \
40
+       for (i = 0; i < (d)->n_items; i++) {                    \
41
+           if (parse_item(prs, (struct spa_dict_item *) &(d)->items[i]) < 0)   \
42
+               return -EINVAL;                     \
43
+       }                                   \
44
+   }                                       \
45
+} while(0)
46
+
47
+#define parse_dict_struct(prs,f,dict)                      \
48
+do {                                       \
49
+   if (spa_pod_parser_push_struct(prs, f) < 0)             \
50
+       return -EINVAL;                         \
51
+   parse_dict(prs, dict);                          \
52
+   spa_pod_parser_pop(prs, f);                     \
53
+} while(0)
54
+
55
+#define parse_params(prs,n_params,params)                      \
56
+do {                                           \
57
+   uint32_t i;                                 \
58
+   if (spa_pod_parser_get(prs,                         \
59
+            SPA_POD_Int(&n_params), NULL) < 0)             \
60
+       return -EINVAL;                             \
61
+   params = NULL;                                  \
62
+   if (n_params > 0) {                             \
63
+       if (n_params > MAX_PARAMS)                      \
64
+           return -ENOSPC;                         \
65
+       params = alloca(n_params * sizeof(struct spa_pod *));           \
66
+       for (i = 0; i < n_params; i++) {                    \
67
+           if (spa_pod_parser_get(prs,                 \
68
+                   SPA_POD_PodObject(&params[i]), NULL) < 0)   \
69
+               return -EINVAL;                     \
70
+       }                                   \
71
+   }                                       \
72
+} while(0)
73
+
74
+#define parse_param_info(prs,n_params,params)                      \
75
+do {                                           \
76
+   uint32_t i;                                 \
77
+   if (spa_pod_parser_get(prs,                         \
78
+           SPA_POD_Int(&(n_params)), NULL) < 0)                \
79
+       return -EINVAL;                             \
80
+   params = NULL;                                  \
81
+   if (n_params > 0) {                             \
82
+       if (n_params > MAX_PARAM_INFO)                      \
83
+           return -ENOSPC;                         \
84
+       params = alloca(n_params * sizeof(struct spa_param_info));      \
85
+       for (i = 0; i < n_params; i++) {                    \
86
+           if (spa_pod_parser_get(prs,                 \
87
+                   SPA_POD_Id(&(params[i]).id),            \
88
+                   SPA_POD_Int(&(params[i]).flags), NULL) < 0) \
89
+               return -EINVAL;                     \
90
+       }                                   \
91
+   }                                       \
92
+} while(0)
93
 
94
 static int client_node_marshal_add_listener(void *object,
95
            struct spa_hook *listener,
96
@@ -407,15 +468,7 @@
97
            SPA_POD_Int(&port_id), NULL) < 0)
98
        return -EINVAL;
99
 
100
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0)
101
-       return -EINVAL;
102
-   if (spa_pod_parser_get(&prs,
103
-            SPA_POD_Int(&props.n_items), NULL) < 0)
104
-       return -EINVAL;
105
-
106
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
107
-   if (parse_dict(&prs, &props) < 0)
108
-       return -EINVAL;
109
+   parse_dict_struct(&prs, &f[1], &props);
110
 
111
    pw_proxy_notify(proxy, struct pw_client_node_events, add_port, 0, direction, port_id,
112
            props.n_items ? &props : NULL);
113
@@ -478,6 +531,9 @@
114
            SPA_POD_Int(&n_buffers), NULL) < 0)
115
        return -EINVAL;
116
 
117
+   if (n_buffers > MAX_BUFFERS)
118
+       return -ENOSPC;
119
+
120
    buffers = alloca(sizeof(struct pw_client_node_buffer) * n_buffers);
121
    for (i = 0; i < n_buffers; i++) {
122
        struct spa_buffer *buf = buffers[i].buffer = alloca(sizeof(struct spa_buffer));
123
@@ -489,6 +545,9 @@
124
                      SPA_POD_Int(&buf->n_metas), NULL) < 0)
125
            return -EINVAL;
126
 
127
+       if (buf->n_metas > MAX_METAS)
128
+           return -ENOSPC;
129
+
130
        buf->metas = alloca(sizeof(struct spa_meta) * buf->n_metas);
131
        for (j = 0; j < buf->n_metas; j++) {
132
            struct spa_meta *m = &buf->metas[j];
133
@@ -502,6 +561,9 @@
134
                    SPA_POD_Int(&buf->n_datas), NULL) < 0)
135
            return -EINVAL;
136
 
137
+       if (buf->n_datas > MAX_DATAS)
138
+           return -ENOSPC;
139
+
140
        buf->datas = alloca(sizeof(struct spa_data) * buf->n_datas);
141
        for (j = 0; j < buf->n_datas; j++) {
142
            struct spa_data *d = &buf->datas[j];
143
@@ -594,15 +656,7 @@
144
            SPA_POD_Int(&peer_id), NULL) < 0)
145
        return -EINVAL;
146
 
147
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0)
148
-       return -EINVAL;
149
-   if (spa_pod_parser_get(&prs,
150
-            SPA_POD_Int(&props.n_items), NULL) < 0)
151
-       return -EINVAL;
152
-
153
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
154
-   if (parse_dict(&prs, &props) < 0)
155
-       return -EINVAL;
156
+   parse_dict_struct(&prs, &f[1], &props);
157
 
158
    pw_proxy_notify(proxy, struct pw_client_node_events, port_set_mix_info, 1,
159
                            direction, port_id, mix_id,
160
@@ -926,24 +980,18 @@
161
    struct spa_pod_parser prs;
162
    struct spa_pod_frame f[2];
163
    uint32_t change_mask, n_params;
164
-   const struct spa_pod **params;
165
+   const struct spa_pod **params = NULL;
166
    struct spa_node_info info = SPA_NODE_INFO_INIT(), *infop = NULL;
167
    struct spa_pod *ipod;
168
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
169
-   uint32_t i;
170
 
171
    spa_pod_parser_init(&prs, msg->data, msg->size);
172
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
173
        spa_pod_parser_get(&prs,
174
-           SPA_POD_Int(&change_mask),
175
-           SPA_POD_Int(&n_params), NULL) < 0)
176
+           SPA_POD_Int(&change_mask), NULL) < 0)
177
        return -EINVAL;
178
 
179
-   params = alloca(n_params * sizeof(struct spa_pod *));
180
-   for (i = 0; i < n_params; i++)
181
-       if (spa_pod_parser_get(&prs,
182
-                   SPA_POD_PodObject(&params[i]), NULL) < 0)
183
-           return -EINVAL;
184
+   parse_params(&prs, n_params, params);
185
 
186
    if (spa_pod_parser_get(&prs,
187
                SPA_POD_PodStruct(&ipod), NULL) < 0)
188
@@ -960,34 +1008,18 @@
189
                SPA_POD_Int(&info.max_input_ports),
190
                SPA_POD_Int(&info.max_output_ports),
191
                SPA_POD_Long(&info.change_mask),
192
-               SPA_POD_Long(&info.flags),
193
-               SPA_POD_Int(&props.n_items), NULL) < 0)
194
+               SPA_POD_Long(&info.flags), NULL) < 0)
195
            return -EINVAL;
196
 
197
        info.change_mask &= SPA_NODE_CHANGE_MASK_FLAGS |
198
                SPA_NODE_CHANGE_MASK_PROPS |
199
                SPA_NODE_CHANGE_MASK_PARAMS;
200
 
201
-       if (props.n_items > 0) {
202
+       parse_dict(&p2, &props);
203
+       if (props.n_items > 0)
204
            info.props = &props;
205
 
206
-           props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
207
-           if (parse_dict(&p2, &props) < 0)
208
-               return -EINVAL;
209
-       }
210
-       if (spa_pod_parser_get(&p2,
211
-               SPA_POD_Int(&info.n_params), NULL) < 0)
212
-           return -EINVAL;
213
-
214
-       if (info.n_params > 0) {
215
-           info.params = alloca(info.n_params * sizeof(struct spa_param_info));
216
-           for (i = 0; i < info.n_params; i++) {
217
-               if (spa_pod_parser_get(&p2,
218
-                       SPA_POD_Id(&info.params[i].id),
219
-                       SPA_POD_Int(&info.params[i].flags), NULL) < 0)
220
-                   return -EINVAL;
221
-           }
222
-       }
223
+       parse_param_info(&p2, info.n_params, info.params);
224
    }
225
 
226
    pw_resource_notify(resource, struct pw_client_node_methods, update, 0, change_mask,
227
@@ -1001,7 +1033,7 @@
228
    struct pw_resource *resource = object;
229
    struct spa_pod_parser prs;
230
    struct spa_pod_frame f;
231
-   uint32_t i, direction, port_id, change_mask, n_params;
232
+   uint32_t direction, port_id, change_mask, n_params;
233
    const struct spa_pod **params = NULL;
234
    struct spa_port_info info = SPA_PORT_INFO_INIT(), *infop = NULL;
235
    struct spa_pod *ipod;
236
@@ -1012,15 +1044,10 @@
237
        spa_pod_parser_get(&prs,
238
            SPA_POD_Int(&direction),
239
            SPA_POD_Int(&port_id),
240
-           SPA_POD_Int(&change_mask),
241
-           SPA_POD_Int(&n_params), NULL) < 0)
242
+           SPA_POD_Int(&change_mask), NULL) < 0)
243
        return -EINVAL;
244
 
245
-   params = alloca(n_params * sizeof(struct spa_pod *));
246
-   for (i = 0; i < n_params; i++)
247
-       if (spa_pod_parser_get(&prs,
248
-                   SPA_POD_PodObject(&params[i]), NULL) < 0)
249
-           return -EINVAL;
250
+   parse_params(&prs, n_params, params);
251
 
252
    if (spa_pod_parser_get(&prs,
253
                SPA_POD_PodStruct(&ipod), NULL) < 0)
254
@@ -1037,8 +1064,7 @@
255
                SPA_POD_Long(&info.change_mask),
256
                SPA_POD_Long(&info.flags),
257
                SPA_POD_Int(&info.rate.num),
258
-               SPA_POD_Int(&info.rate.denom),
259
-               SPA_POD_Int(&props.n_items), NULL) < 0)
260
+               SPA_POD_Int(&info.rate.denom), NULL) < 0)
261
            return -EINVAL;
262
 
263
        info.change_mask &= SPA_PORT_CHANGE_MASK_FLAGS |
264
@@ -1046,26 +1072,11 @@
265
                SPA_PORT_CHANGE_MASK_PROPS |
266
                SPA_PORT_CHANGE_MASK_PARAMS;
267
 
268
-       if (props.n_items > 0) {
269
+       parse_dict(&p2, &props);
270
+       if (props.n_items > 0)
271
            info.props = &props;
272
 
273
-           props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
274
-           if (parse_dict(&p2, &props) < 0)
275
-               return -EINVAL;
276
-       }
277
-       if (spa_pod_parser_get(&p2,
278
-               SPA_POD_Int(&info.n_params), NULL) < 0)
279
-           return -EINVAL;
280
-
281
-       if (info.n_params > 0) {
282
-           info.params = alloca(info.n_params * sizeof(struct spa_param_info));
283
-           for (i = 0; i < info.n_params; i++) {
284
-               if (spa_pod_parser_get(&p2,
285
-                       SPA_POD_Id(&info.params[i].id),
286
-                       SPA_POD_Int(&info.params[i].flags), NULL) < 0)
287
-                   return -EINVAL;
288
-           }
289
-       }
290
+       parse_param_info(&p2, info.n_params, info.params);
291
    }
292
 
293
    pw_resource_notify(resource, struct pw_client_node_methods, port_update, 0, direction,
294
@@ -1124,6 +1135,9 @@
295
            SPA_POD_Int(&n_buffers), NULL) < 0)
296
        return -EINVAL;
297
 
298
+   if (n_buffers > MAX_BUFFERS)
299
+       return -ENOSPC;
300
+
301
    buffers = alloca(sizeof(struct spa_buffer*) * n_buffers);
302
    for (i = 0; i < n_buffers; i++) {
303
        struct spa_buffer *buf = buffers[i] = alloca(sizeof(struct spa_buffer));
304
@@ -1133,6 +1147,9 @@
305
                    SPA_POD_Int(&buf->n_datas), NULL) < 0)
306
            return -EINVAL;
307
 
308
+       if (buf->n_datas > MAX_DATAS)
309
+           return -ENOSPC;
310
+
311
        buf->datas = alloca(sizeof(struct spa_data) * buf->n_datas);
312
        for (j = 0; j < buf->n_datas; j++) {
313
            struct spa_data *d = &buf->datas[j];
314
pipewire-0.3.44.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.45.tar.gz/src/modules/module-client-node/remote-node.c Changed
21
 
1
@@ -41,7 +41,8 @@
2
 #include "pipewire/extensions/protocol-native.h"
3
 #include "pipewire/extensions/client-node.h"
4
 
5
-#define MAX_MIX    4096
6
+#define MAX_BUFFERS    64
7
+#define MAX_MIX        4096
8
 
9
 PW_LOG_TOPIC_EXTERN(mod_topic);
10
 #define PW_LOG_TOPIC_DEFAULT mod_topic
11
@@ -629,6 +630,9 @@
12
        goto error_exit;
13
    }
14
 
15
+   if (n_buffers > MAX_BUFFERS)
16
+       return -ENOSPC;
17
+
18
    prot = PW_MEMMAP_FLAG_READWRITE;
19
 
20
    /* clear previous buffers */
21
pipewire-0.3.44.tar.gz/src/modules/module-link-factory.c -> pipewire-0.3.45.tar.gz/src/modules/module-link-factory.c Changed
62
 
1
@@ -57,6 +57,7 @@
2
 
3
 struct factory_data {
4
    struct pw_impl_module *module;
5
+   struct pw_context *context;
6
    struct pw_impl_factory *this;
7
 
8
    struct spa_list link_list;
9
@@ -125,9 +126,13 @@
10
 static void link_initialized(void *data)
11
 {
12
    struct link_data *ld = data;
13
-   struct pw_impl_client *client = pw_resource_get_client(ld->factory_resource);
14
+   struct pw_impl_client *client;
15
    int res;
16
 
17
+   if (ld->factory_resource == NULL)
18
+       return;
19
+
20
+   client = pw_resource_get_client(ld->factory_resource);
21
    ld->global = pw_impl_link_get_global(ld->link);
22
    pw_global_add_listener(ld->global, &ld->global_listener, &global_events, ld);
23
 
24
@@ -364,7 +369,7 @@
25
    struct pw_impl_client *client = NULL;
26
    struct pw_impl_node *output_node, *input_node;
27
    struct pw_impl_port *outport = NULL, *inport = NULL;
28
-   struct pw_context *context;
29
+   struct pw_context *context = d->context;
30
    struct pw_impl_link *link;
31
    const char *output_node_str, *input_node_str;
32
    const char *output_port_str, *input_port_str;
33
@@ -372,9 +377,6 @@
34
    int res;
35
    bool linger;
36
 
37
-   client = pw_resource_get_client(resource);
38
-   context = pw_impl_client_get_context(client);
39
-
40
    if (properties == NULL)
41
        goto error_properties;
42
 
43
@@ -406,7 +408,9 @@
44
 
45
    pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d",
46
            pw_impl_factory_get_info(d->this)->id);
47
-   if (!linger)
48
+
49
+   client = resource ? pw_resource_get_client(resource) : NULL;
50
+   if (client && !linger)
51
        pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d",
52
                pw_impl_client_get_info(client)->id);
53
 
54
@@ -524,6 +528,7 @@
55
    data = pw_impl_factory_get_user_data(factory);
56
    data->this = factory;
57
    data->module = module;
58
+   data->context = context;
59
    data->work = pw_context_get_work_queue(context);
60
    if (data->work == NULL) {
61
        res = -errno;
62
pipewire-0.3.44.tar.gz/src/modules/module-metadata.c -> pipewire-0.3.45.tar.gz/src/modules/module-metadata.c Changed
19
 
1
@@ -121,15 +121,11 @@
2
    return result;
3
 
4
 error_resource:
5
-   pw_log_error("can't create resource: %s", spa_strerror(res));
6
-   if (resource)
7
-       pw_resource_errorf_id(resource, new_id, res,
8
+   pw_resource_errorf_id(resource, new_id, res,
9
                "can't create resource: %s", spa_strerror(res));
10
    goto error_exit;
11
 error_node:
12
-   pw_log_error("can't create metadata: %s", spa_strerror(res));
13
-   if (resource)
14
-       pw_resource_errorf_id(resource, new_id, res,
15
+   pw_resource_errorf_id(resource, new_id, res,
16
                "can't create metadata: %s", spa_strerror(res));
17
    goto error_exit_free;
18
 
19
pipewire-0.3.44.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-native.c Changed
11
 
1
@@ -264,8 +264,7 @@
2
    return res;
3
 
4
 error:
5
-   if (client->core_resource)
6
-       pw_resource_errorf(client->core_resource, res, "client error %d (%s)",
7
+   pw_resource_errorf(client->core_resource, res, "client error %d (%s)",
8
                res, spa_strerror(res));
9
    goto done;
10
 }
11
pipewire-0.3.44.tar.gz/src/modules/module-protocol-native/protocol-native.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-native/protocol-native.c Changed
478
 
1
@@ -34,6 +34,10 @@
2
 
3
 #include "connection.h"
4
 
5
+#define MAX_DICT   256
6
+#define MAX_PARAM_INFO 128
7
+#define MAX_PERMISSIONS    1024
8
+
9
 PW_LOG_TOPIC_EXTERN(mod_topic);
10
 #define PW_LOG_TOPIC_DEFAULT mod_topic
11
 
12
@@ -167,16 +171,31 @@
13
    return 0;
14
 }
15
 
16
-static inline int parse_dict(struct spa_pod_parser *prs, struct spa_dict *dict)
17
-{
18
-   uint32_t i;
19
-   int res;
20
-   for (i = 0; i < dict->n_items; i++) {
21
-       if ((res = parse_item(prs, (struct spa_dict_item *) &dict->items[i])) < 0)
22
-           return res;
23
-   }
24
-   return 0;
25
-}
26
+#define parse_dict(prs,d)                                  \
27
+do {                                               \
28
+   if (spa_pod_parser_get(prs,                             \
29
+            SPA_POD_Int(&(d)->n_items), NULL) < 0)                 \
30
+       return -EINVAL;                                 \
31
+   (d)->items = NULL;                                  \
32
+   if ((d)->n_items > 0) {                                 \
33
+       uint32_t i;                                 \
34
+       if ((d)->n_items > MAX_DICT)                            \
35
+           return -ENOSPC;                             \
36
+       (d)->items = alloca((d)->n_items * sizeof(struct spa_dict_item));       \
37
+       for (i = 0; i < (d)->n_items; i++) {                        \
38
+           if (parse_item(prs, (struct spa_dict_item *) &(d)->items[i]) < 0)   \
39
+               return -EINVAL;                         \
40
+       }                                       \
41
+   }                                           \
42
+} while(0)
43
+
44
+#define parse_dict_struct(prs,f,dict)                      \
45
+do {                                       \
46
+   if (spa_pod_parser_push_struct(prs, f) < 0)             \
47
+       return -EINVAL;                         \
48
+   parse_dict(prs, dict);                          \
49
+   spa_pod_parser_pop(prs, f);                     \
50
+} while(0)
51
 
52
 static void push_params(struct spa_pod_builder *b, uint32_t n_params,
53
        const struct spa_param_info *params)
54
@@ -193,6 +212,52 @@
55
    spa_pod_builder_pop(b, &f);
56
 }
57
 
58
+
59
+#define parse_params_struct(prs,f,params,n_params)                 \
60
+do {                                           \
61
+   if (spa_pod_parser_push_struct(prs, f) < 0 ||                   \
62
+       spa_pod_parser_get(prs,                         \
63
+                  SPA_POD_Int(&(n_params)), NULL) < 0)         \
64
+       return -EINVAL;                             \
65
+   params = NULL;                                  \
66
+   if (n_params > 0) {                             \
67
+       uint32_t i;                             \
68
+       if (n_params > MAX_PARAM_INFO)                      \
69
+           return -ENOSPC;                         \
70
+       params = alloca(n_params * sizeof(struct spa_param_info));      \
71
+       for (i = 0; i < n_params; i++) {                    \
72
+           if (spa_pod_parser_get(prs,                 \
73
+                      SPA_POD_Id(&(params)[i].id),         \
74
+                      SPA_POD_Int(&(params)[i].flags), NULL) < 0)  \
75
+               return -EINVAL;                     \
76
+       }                                   \
77
+   }                                       \
78
+   spa_pod_parser_pop(prs, f);                         \
79
+} while(0)
80
+
81
+
82
+#define parse_permissions_struct(prs,f,n_permissions,permissions)              \
83
+do {                                               \
84
+   if (spa_pod_parser_push_struct(prs, f) < 0 ||                       \
85
+       spa_pod_parser_get(prs,                             \
86
+           SPA_POD_Int(&n_permissions), NULL) < 0)                 \
87
+       return -EINVAL;                                 \
88
+   permissions = NULL;                                 \
89
+   if (n_permissions > 0) {                                \
90
+       uint32_t i;                                 \
91
+       if (n_permissions > MAX_PERMISSIONS)                        \
92
+           return -ENOSPC;                             \
93
+       permissions = alloca(n_permissions * sizeof(struct pw_permission));     \
94
+       for (i = 0; i < n_permissions; i++) {                       \
95
+           if (spa_pod_parser_get(prs,                     \
96
+                   SPA_POD_Int(&permissions[i].id),            \
97
+                   SPA_POD_Int(&permissions[i].permissions), NULL) < 0)    \
98
+               return -EINVAL;                         \
99
+       }                                       \
100
+   }                                           \
101
+   spa_pod_parser_pop(prs, f);                             \
102
+} while(0)
103
+
104
 static void *
105
 core_method_marshal_create_object(void *object,
106
               const char *factory_name,
107
@@ -247,8 +312,8 @@
108
 {
109
    struct pw_proxy *proxy = object;
110
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
111
+   struct pw_core_info info = { .props = &props };
112
    struct spa_pod_frame f[2];
113
-   struct pw_core_info info;
114
    struct spa_pod_parser prs;
115
 
116
    spa_pod_parser_init(&prs, msg->data, msg->size);
117
@@ -264,16 +329,8 @@
118
             SPA_POD_Long(&info.change_mask), NULL) < 0)
119
        return -EINVAL;
120
 
121
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0)
122
-       return -EINVAL;
123
-   if (spa_pod_parser_get(&prs,
124
-            SPA_POD_Int(&props.n_items), NULL) < 0)
125
-       return -EINVAL;
126
 
127
-   info.props = &props;
128
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
129
-   if (parse_dict(&prs, &props) < 0)
130
-       return -EINVAL;
131
+   parse_dict_struct(&prs, &f[1], &props);
132
 
133
    return pw_proxy_notify(proxy, struct pw_core_events, info, 0, &info);
134
 }
135
@@ -611,15 +668,7 @@
136
            NULL) < 0)
137
        return -EINVAL;
138
 
139
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
140
-       spa_pod_parser_get(&prs,
141
-           SPA_POD_Int(&props.n_items), NULL) < 0)
142
-       return -EINVAL;
143
-
144
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
145
-   if (parse_dict(&prs, &props) < 0)
146
-       return -EINVAL;
147
-   spa_pod_parser_pop(&prs, &f[1]);
148
+   parse_dict_struct(&prs, &f[1], &props);
149
 
150
    if (spa_pod_parser_get(&prs,
151
            SPA_POD_Int(&new_id), NULL) < 0)
152
@@ -770,7 +819,7 @@
153
    struct spa_pod_parser prs;
154
    struct spa_pod_frame f[2];
155
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
156
-   struct pw_module_info info;
157
+   struct pw_module_info info = { .props = &props };
158
 
159
    spa_pod_parser_init(&prs, msg->data, msg->size);
160
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
161
@@ -782,15 +831,7 @@
162
            SPA_POD_Long(&info.change_mask), NULL) < 0)
163
        return -EINVAL;
164
 
165
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
166
-       spa_pod_parser_get(&prs,
167
-           SPA_POD_Int(&props.n_items), NULL) < 0)
168
-       return -EINVAL;
169
-
170
-   info.props = &props;
171
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
172
-   if (parse_dict(&prs, &props) < 0)
173
-       return -EINVAL;
174
+   parse_dict_struct(&prs, &f[1], &props);
175
 
176
    return pw_proxy_notify(proxy, struct pw_module_events, info, 0, &info);
177
 }
178
@@ -831,8 +872,7 @@
179
    struct spa_pod_parser prs;
180
    struct spa_pod_frame f[2];
181
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
182
-   struct pw_device_info info;
183
-   uint32_t i;
184
+   struct pw_device_info info = { .props = &props };
185
 
186
    spa_pod_parser_init(&prs, msg->data, msg->size);
187
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
188
@@ -841,30 +881,8 @@
189
            SPA_POD_Long(&info.change_mask), NULL) < 0)
190
        return -EINVAL;
191
 
192
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
193
-       spa_pod_parser_get(&prs,
194
-           SPA_POD_Int(&props.n_items), NULL) < 0)
195
-       return -EINVAL;
196
-
197
-   info.props = &props;
198
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
199
-   if (parse_dict(&prs, &props) < 0)
200
-       return -EINVAL;
201
-   spa_pod_parser_pop(&prs, &f[1]);
202
-
203
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
204
-       spa_pod_parser_get(&prs,
205
-                  SPA_POD_Int(&info.n_params),
206
-                  NULL) < 0)
207
-       return -EINVAL;
208
-
209
-   info.params = alloca(info.n_params * sizeof(struct spa_param_info));
210
-   for (i = 0; i < info.n_params; i++) {
211
-       if (spa_pod_parser_get(&prs,
212
-                      SPA_POD_Id(&info.params[i].id),
213
-                      SPA_POD_Int(&info.params[i].flags), NULL) < 0)
214
-           return -EINVAL;
215
-   }
216
+   parse_dict_struct(&prs, &f[1], &props);
217
+   parse_params_struct(&prs, &f[1], info.params, info.n_params);
218
 
219
    return pw_proxy_notify(proxy, struct pw_device_events, info, 0, &info);
220
 }
221
@@ -1050,7 +1068,7 @@
222
    struct spa_pod_parser prs;
223
    struct spa_pod_frame f[2];
224
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
225
-   struct pw_factory_info info;
226
+   struct pw_factory_info info = { .props = &props };
227
 
228
    spa_pod_parser_init(&prs, msg->data, msg->size);
229
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
230
@@ -1062,15 +1080,7 @@
231
            SPA_POD_Long(&info.change_mask), NULL) < 0)
232
        return -EINVAL;
233
 
234
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
235
-       spa_pod_parser_get(&prs,
236
-           SPA_POD_Int(&props.n_items), NULL) < 0)
237
-       return -EINVAL;
238
-
239
-   info.props = &props;
240
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
241
-   if (parse_dict(&prs, &props) < 0)
242
-       return -EINVAL;
243
+   parse_dict_struct(&prs, &f[1], &props);
244
 
245
    return pw_proxy_notify(proxy, struct pw_factory_events, info, 0, &info);
246
 }
247
@@ -1117,8 +1127,7 @@
248
    struct spa_pod_parser prs;
249
    struct spa_pod_frame f[2];
250
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
251
-   struct pw_node_info info;
252
-   uint32_t i;
253
+   struct pw_node_info info = { .props = &props };
254
 
255
    spa_pod_parser_init(&prs, msg->data, msg->size);
256
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
257
@@ -1133,30 +1142,8 @@
258
            SPA_POD_String(&info.error), NULL) < 0)
259
        return -EINVAL;
260
 
261
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
262
-       spa_pod_parser_get(&prs,
263
-           SPA_POD_Int(&props.n_items), NULL) < 0)
264
-       return -EINVAL;
265
-
266
-   info.props = &props;
267
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
268
-   if (parse_dict(&prs, &props) < 0)
269
-       return -EINVAL;
270
-   spa_pod_parser_pop(&prs, &f[1]);
271
-
272
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
273
-       spa_pod_parser_get(&prs,
274
-                  SPA_POD_Int(&info.n_params),
275
-                  NULL) < 0)
276
-       return -EINVAL;
277
-
278
-   info.params = alloca(info.n_params * sizeof(struct spa_param_info));
279
-   for (i = 0; i < info.n_params; i++) {
280
-       if (spa_pod_parser_get(&prs,
281
-                      SPA_POD_Id(&info.params[i].id),
282
-                      SPA_POD_Int(&info.params[i].flags), NULL) < 0)
283
-           return -EINVAL;
284
-   }
285
+   parse_dict_struct(&prs, &f[1], &props);
286
+   parse_params_struct(&prs, &f[1], info.params, info.n_params);
287
 
288
    return pw_proxy_notify(proxy, struct pw_node_events, info, 0, &info);
289
 }
290
@@ -1366,8 +1353,7 @@
291
    struct spa_pod_parser prs;
292
    struct spa_pod_frame f[2];
293
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
294
-   struct pw_port_info info;
295
-   uint32_t i;
296
+   struct pw_port_info info = { .props = &props };
297
 
298
    spa_pod_parser_init(&prs, msg->data, msg->size);
299
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
300
@@ -1377,30 +1363,9 @@
301
            SPA_POD_Long(&info.change_mask), NULL) < 0)
302
        return -EINVAL;
303
 
304
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
305
-       spa_pod_parser_get(&prs,
306
-           SPA_POD_Int(&props.n_items), NULL) < 0)
307
-       return -EINVAL;
308
-
309
-   info.props = &props;
310
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
311
-   if (parse_dict(&prs, &props) < 0)
312
-       return -EINVAL;
313
-   spa_pod_parser_pop(&prs, &f[1]);
314
-
315
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
316
-       spa_pod_parser_get(&prs,
317
-                  SPA_POD_Int(&info.n_params),
318
-                  NULL) < 0)
319
-       return -EINVAL;
320
+   parse_dict_struct(&prs, &f[1], &props);
321
+   parse_params_struct(&prs, &f[1], info.params, info.n_params);
322
 
323
-   info.params = alloca(info.n_params * sizeof(struct spa_param_info));
324
-   for (i = 0; i < info.n_params; i++) {
325
-       if (spa_pod_parser_get(&prs,
326
-                      SPA_POD_Id(&info.params[i].id),
327
-                      SPA_POD_Int(&info.params[i].flags), NULL) < 0)
328
-           return -EINVAL;
329
-   }
330
    return pw_proxy_notify(proxy, struct pw_port_events, info, 0, &info);
331
 }
332
 
333
@@ -1550,7 +1515,7 @@
334
    struct spa_pod_parser prs;
335
    struct spa_pod_frame f[2];
336
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
337
-   struct pw_client_info info;
338
+   struct pw_client_info info = { .props = &props };
339
 
340
    spa_pod_parser_init(&prs, msg->data, msg->size);
341
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
342
@@ -1559,15 +1524,7 @@
343
            SPA_POD_Long(&info.change_mask), NULL) < 0)
344
        return -EINVAL;
345
 
346
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
347
-       spa_pod_parser_get(&prs,
348
-           SPA_POD_Int(&props.n_items), NULL) < 0)
349
-       return -EINVAL;
350
-
351
-   info.props = &props;
352
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
353
-   if (parse_dict(&prs, &props) < 0)
354
-       return -EINVAL;
355
+   parse_dict_struct(&prs, &f[1], &props);
356
 
357
    return pw_proxy_notify(proxy, struct pw_client_events, info, 0, &info);
358
 }
359
@@ -1610,7 +1567,7 @@
360
    struct pw_permission *permissions;
361
    struct spa_pod_parser prs;
362
    struct spa_pod_frame f[2];
363
-   uint32_t i, index, n_permissions;
364
+   uint32_t index, n_permissions;
365
 
366
    spa_pod_parser_init(&prs, msg->data, msg->size);
367
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
368
@@ -1618,18 +1575,8 @@
369
            SPA_POD_Int(&index), NULL) < 0)
370
        return -EINVAL;
371
 
372
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
373
-       spa_pod_parser_get(&prs,
374
-           SPA_POD_Int(&n_permissions), NULL) < 0)
375
-       return -EINVAL;
376
+   parse_permissions_struct(&prs, &f[1], n_permissions, permissions);
377
 
378
-   permissions = alloca(n_permissions * sizeof(struct pw_permission));
379
-   for (i = 0; i < n_permissions; i++) {
380
-       if (spa_pod_parser_get(&prs,
381
-               SPA_POD_Int(&permissions[i].id),
382
-               SPA_POD_Int(&permissions[i].permissions), NULL) < 0)
383
-           return -EINVAL;
384
-   }
385
    return pw_proxy_notify(proxy, struct pw_client_events, permissions, 0, index, n_permissions, permissions);
386
 }
387
 
388
@@ -1700,15 +1647,10 @@
389
    struct spa_pod_frame f[2];
390
 
391
    spa_pod_parser_init(&prs, msg->data, msg->size);
392
-   if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
393
-       spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
394
-       spa_pod_parser_get(&prs,
395
-           SPA_POD_Int(&props.n_items), NULL) < 0)
396
+   if (spa_pod_parser_push_struct(&prs, &f[0]) < 0)
397
        return -EINVAL;
398
 
399
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
400
-   if (parse_dict(&prs, &props) < 0)
401
-       return -EINVAL;
402
+   parse_dict_struct(&prs, &f[1], &props);
403
 
404
    return pw_resource_notify(resource, struct pw_client_methods, update_properties, 0,
405
            &props);
406
@@ -1756,21 +1698,12 @@
407
    struct pw_permission *permissions;
408
    struct spa_pod_parser prs;
409
    struct spa_pod_frame f[1];
410
-   uint32_t i, n_permissions;
411
+   uint32_t n_permissions;
412
 
413
    spa_pod_parser_init(&prs, msg->data, msg->size);
414
-   if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
415
-       spa_pod_parser_get(&prs,
416
-               SPA_POD_Int(&n_permissions), NULL) < 0)
417
-       return -EINVAL;
418
 
419
-   permissions = alloca(n_permissions * sizeof(struct pw_permission));
420
-   for (i = 0; i < n_permissions; i++) {
421
-       if (spa_pod_parser_get(&prs,
422
-               SPA_POD_Int(&permissions[i].id),
423
-               SPA_POD_Int(&permissions[i].permissions), NULL) < 0)
424
-           return -EINVAL;
425
-   }
426
+   parse_permissions_struct(&prs, &f[0], n_permissions, permissions);
427
+
428
    return pw_resource_notify(resource, struct pw_client_methods, update_permissions, 0,
429
            n_permissions, permissions);
430
 }
431
@@ -1817,7 +1750,7 @@
432
    struct spa_pod_parser prs;
433
    struct spa_pod_frame f[2];
434
    struct spa_dict props = SPA_DICT_INIT(NULL, 0);
435
-   struct pw_link_info info = { 0, };
436
+   struct pw_link_info info = { .props = &props };
437
 
438
    spa_pod_parser_init(&prs, msg->data, msg->size);
439
    if (spa_pod_parser_push_struct(&prs, &f[0]) < 0 ||
440
@@ -1833,15 +1766,7 @@
441
            SPA_POD_Pod(&info.format), NULL) < 0)
442
        return -EINVAL;
443
 
444
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
445
-       spa_pod_parser_get(&prs,
446
-           SPA_POD_Int(&props.n_items), NULL) < 0)
447
-       return -EINVAL;
448
-
449
-   info.props = &props;
450
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
451
-   if (parse_dict(&prs, &props) < 0)
452
-       return -EINVAL;
453
+   parse_dict_struct(&prs, &f[1], &props);
454
 
455
    return pw_proxy_notify(proxy, struct pw_link_events, info, 0, &info);
456
 }
457
@@ -1864,18 +1789,10 @@
458
            SPA_POD_Int(&version), NULL) < 0)
459
        return -EINVAL;
460
 
461
-   if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
462
-       spa_pod_parser_get(&prs,
463
-           SPA_POD_Int(&props.n_items), NULL) < 0)
464
-       return -EINVAL;
465
-
466
-   props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
467
-   if (parse_dict(&prs, &props) < 0)
468
-       return -EINVAL;
469
+   parse_dict_struct(&prs, &f[1], &props);
470
 
471
    return pw_proxy_notify(proxy, struct pw_registry_events,
472
-           global, 0, id, permissions, type, version,
473
-           props.n_items > 0 ? &props : NULL);
474
+           global, 0, id, permissions, type, version, &props);
475
 }
476
 
477
 static int registry_demarshal_global_remove(void *object, const struct pw_protocol_native_message *msg)
478
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/client.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/client.c Changed
48
 
1
@@ -99,6 +99,7 @@
2
 
3
    /* remove from the `server->clients` list */
4
    spa_list_remove(&client->link);
5
+   spa_list_append(&impl->cleanup_clients, &client->link);
6
 
7
    server->n_clients--;
8
    if (server->wait_clients > 0 && --server->wait_clients == 0) {
9
@@ -125,15 +126,18 @@
10
    spa_assert(client->server == NULL);
11
 
12
    client->disconnect = true;
13
-   spa_list_append(&impl->cleanup_clients, &client->link);
14
 
15
    pw_map_for_each(&client->streams, client_free_stream, client);
16
 
17
-   if (client->source)
18
+   if (client->source) {
19
        pw_loop_destroy_source(impl->loop, client->source);
20
+       client->source = NULL;
21
+   }
22
 
23
-   if (client->manager)
24
+   if (client->manager) {
25
        pw_manager_destroy(client->manager);
26
+       client->manager = NULL;
27
+   }
28
 }
29
 
30
 void client_free(struct client *client)
31
@@ -163,13 +167,13 @@
32
    spa_list_consume(o, &client->operations, link)
33
        operation_free(o);
34
 
35
-   if (client->core) {
36
-       client->disconnecting = true;
37
+   if (client->core)
38
        pw_core_disconnect(client->core);
39
-   }
40
 
41
    pw_map_clear(&client->streams);
42
 
43
+   pw_work_queue_cancel(impl->work_queue, client, SPA_ID_INVALID);
44
+
45
    free(client->default_sink);
46
    free(client->default_source);
47
 
48
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/client.h -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/client.h Changed
9
 
1
@@ -95,7 +95,6 @@
2
    struct spa_list pending_streams;
3
 
4
    unsigned int disconnect:1;
5
-   unsigned int disconnecting:1;
6
    unsigned int new_msg_since_last_flush:1;
7
    unsigned int authenticated:1;
8
 
9
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/defs.h -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/defs.h Changed
10
 
1
@@ -52,7 +52,7 @@
2
 #define MIN_BUFFERS     1u
3
 #define MAX_BUFFERS     4u
4
 
5
-#define MAXLENGTH      (4*1024*1024) /* 4MB */
6
+#define MAXLENGTH      (4u*1024*1024) /* 4MB */
7
 
8
 #define SCACHE_ENTRY_SIZE_MAX  (1024*1024*16)
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/format.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/format.c Changed
27
 
1
@@ -475,10 +475,7 @@
2
            return -ENOTSUP;
3
 
4
        info.info.raw.format = SPA_AUDIO_FORMAT_S16;
5
-       info.info.raw.channels = 2;
6
        info.info.raw.rate = iec.rate;
7
-       info.info.raw.position[0] = SPA_AUDIO_CHANNEL_FL;
8
-       info.info.raw.position[1] = SPA_AUDIO_CHANNEL_FR;
9
        break;
10
    }
11
    default:
12
@@ -493,9 +490,11 @@
13
                ss->channels = info.info.raw.channels;
14
    }
15
    if (map) {
16
-       map->channels = info.info.raw.channels;
17
-       for (i = 0; i < map->channels; i++)
18
-           map->map[i] = info.info.raw.position[i];
19
+       if (info.info.raw.channels) {
20
+           map->channels = info.info.raw.channels;
21
+           for (i = 0; i < map->channels; i++)
22
+               map->map[i] = info.info.raw.position[i];
23
+       }
24
    }
25
    return 0;
26
 }
27
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/module.c Changed
37
 
1
@@ -45,7 +45,7 @@
2
 static void on_module_unload(void *obj, void *data, int res, uint32_t index)
3
 {
4
    struct module *module = obj;
5
-   module_unload(NULL, module);
6
+   module_unload(module);
7
 }
8
 
9
 void module_schedule_unload(struct module *module)
10
@@ -110,7 +110,7 @@
11
    free(module);
12
 }
13
 
14
-int module_unload(struct client *client, struct module *module)
15
+int module_unload(struct module *module)
16
 {
17
    struct impl *impl = module->impl;
18
    int res = 0;
19
@@ -121,7 +121,7 @@
20
    pw_log_info("unload module index:%u name:%s", module->index, module->name);
21
 
22
    if (module->methods->unload)
23
-       res = module->methods->unload(client, module);
24
+       res = module->methods->unload(module);
25
 
26
    if (module->loaded)
27
        broadcast_subscribe_event(impl,
28
@@ -302,7 +302,7 @@
29
 
30
    module->index = pw_map_insert_new(&impl->modules, module);
31
    if (module->index == SPA_ID_INVALID) {
32
-       module_unload(client, module);
33
+       module_unload(module);
34
        return NULL;
35
    }
36
    module->name = strdup(name);
37
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/module.h Changed
19
 
1
@@ -53,7 +53,7 @@
2
    uint32_t version;
3
 
4
    int (*load) (struct client *client, struct module *module);
5
-   int (*unload) (struct client *client, struct module *module);
6
+   int (*unload) (struct module *module);
7
 };
8
 
9
 struct module {
10
@@ -76,7 +76,7 @@
11
 void module_free(struct module *module);
12
 struct module *module_new(struct impl *impl, const struct module_methods *methods, size_t user_data);
13
 int module_load(struct client *client, struct module *module);
14
-int module_unload(struct client *client, struct module *module);
15
+int module_unload(struct module *module);
16
 void module_schedule_unload(struct module *module);
17
 
18
 void module_add_listener(struct module *module,
19
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c Changed
10
 
1
@@ -390,7 +390,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_combine_sink_unload(struct client *client, struct module *module)
6
+static int module_combine_sink_unload(struct module *module)
7
 {
8
    struct module_combine_sink_data *d = module->user_data;
9
    int i;
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c Changed
10
 
1
@@ -108,7 +108,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_echo_cancel_unload(struct client *client, struct module *module)
6
+static int module_echo_cancel_unload(struct module *module)
7
 {
8
    struct module_echo_cancel_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c Changed
19
 
1
@@ -124,7 +124,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_ladspa_sink_unload(struct client *client, struct module *module)
6
+static int module_ladspa_sink_unload(struct module *module)
7
 {
8
    struct module_ladspa_sink_data *d = module->user_data;
9
 
10
@@ -212,6 +212,8 @@
11
    }
12
    if (pw_properties_get(capture_props, PW_KEY_MEDIA_CLASS) == NULL)
13
        pw_properties_set(capture_props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
14
+   if (pw_properties_get(capture_props, PW_KEY_DEVICE_CLASS) == NULL)
15
+       pw_properties_set(capture_props, PW_KEY_DEVICE_CLASS, "filter");
16
 
17
    if ((str = pw_properties_get(props, "master")) != NULL ||
18
        (str = pw_properties_get(props, "sink_master")) != NULL) {
19
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c Changed
19
 
1
@@ -124,7 +124,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_ladspa_source_unload(struct client *client, struct module *module)
6
+static int module_ladspa_source_unload(struct module *module)
7
 {
8
    struct module_ladspa_source_data *d = module->user_data;
9
 
10
@@ -212,6 +212,8 @@
11
    }
12
    if (pw_properties_get(playback_props, PW_KEY_MEDIA_CLASS) == NULL)
13
        pw_properties_set(playback_props, PW_KEY_MEDIA_CLASS, "Audio/Source");
14
+   if (pw_properties_get(playback_props, PW_KEY_DEVICE_CLASS) == NULL)
15
+       pw_properties_set(playback_props, PW_KEY_DEVICE_CLASS, "filter");
16
 
17
    if ((str = pw_properties_get(props, "master")) != NULL ||
18
        (str = pw_properties_get(props, "source_master")) != NULL) {
19
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c Changed
10
 
1
@@ -107,7 +107,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_loopback_unload(struct client *client, struct module *module)
6
+static int module_loopback_unload(struct module *module)
7
 {
8
    struct module_loopback_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c Changed
10
 
1
@@ -58,7 +58,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_native_protocol_tcp_unload(struct client *client, struct module *module)
6
+static int module_native_protocol_tcp_unload(struct module *module)
7
 {
8
    struct module_native_protocol_tcp_data *d = module->user_data;
9
    struct server **s;
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c Changed
10
 
1
@@ -126,7 +126,7 @@
2
    return SPA_RESULT_RETURN_ASYNC(0);
3
 }
4
 
5
-static int module_null_sink_unload(struct client *client, struct module *module)
6
+static int module_null_sink_unload(struct module *module)
7
 {
8
    struct module_null_sink_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c Changed
10
 
1
@@ -185,7 +185,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_pipesink_unload(struct client *client, struct module *module)
6
+static int module_pipesink_unload(struct module *module)
7
 {
8
    struct module_pipesink_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c Changed
10
 
1
@@ -206,7 +206,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_pipesource_unload(struct client *client, struct module *module)
6
+static int module_pipesource_unload(struct module *module)
7
 {
8
    struct module_pipesrc_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-raop-discover.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-raop-discover.c Changed
10
 
1
@@ -73,7 +73,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_raop_discover_unload(struct client *client, struct module *module)
6
+static int module_raop_discover_unload(struct module *module)
7
 {
8
    struct module_raop_discover_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c Changed
62
 
1
@@ -95,7 +95,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_remap_sink_unload(struct client *client, struct module *module)
6
+static int module_remap_sink_unload(struct module *module)
7
 {
8
    struct module_remap_sink_data *d = module->user_data;
9
 
10
@@ -151,7 +151,7 @@
11
    struct module *module;
12
    struct module_remap_sink_data *d;
13
    struct pw_properties *props = NULL, *playback_props = NULL, *capture_props = NULL;
14
-   const char *str;
15
+   const char *str, *master;
16
    struct spa_audio_info_raw capture_info = { 0 };
17
    struct spa_audio_info_raw playback_info = { 0 };
18
    int res;
19
@@ -168,16 +168,40 @@
20
    if (argument)
21
        module_args_add_props(props, argument);
22
 
23
+   master = pw_properties_get(props, "master");
24
+   if (pw_properties_get(props, "sink_name") == NULL) {
25
+       pw_properties_setf(props, "sink_name", "%s.remapped",
26
+               master ? master : "default");
27
+   }
28
    if ((str = pw_properties_get(props, "sink_name")) != NULL) {
29
        pw_properties_set(capture_props, PW_KEY_NODE_NAME, str);
30
+       pw_properties_setf(playback_props, PW_KEY_NODE_NAME, "output.%s", str);
31
        pw_properties_set(props, "sink_name", NULL);
32
    }
33
    if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
34
        module_args_add_props(capture_props, str);
35
        pw_properties_set(props, "sink_properties", NULL);
36
    }
37
-   pw_properties_set(capture_props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
38
-
39
+   if (pw_properties_get(capture_props, PW_KEY_MEDIA_CLASS) == NULL)
40
+       pw_properties_set(capture_props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
41
+   if (pw_properties_get(capture_props, PW_KEY_DEVICE_CLASS) == NULL)
42
+       pw_properties_set(capture_props, PW_KEY_DEVICE_CLASS, "filter");
43
+
44
+   if ((str = pw_properties_get(capture_props, PW_KEY_MEDIA_NAME)) != NULL)
45
+       pw_properties_set(props, PW_KEY_MEDIA_NAME, str);
46
+   if ((str = pw_properties_get(capture_props, PW_KEY_NODE_DESCRIPTION)) != NULL) {
47
+       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str);
48
+   } else {
49
+       str = pw_properties_get(capture_props, PW_KEY_NODE_NAME);
50
+       if (master != NULL || str == NULL) {
51
+           pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
52
+                   "Remapped %s sink",
53
+                   master ? master : "default");
54
+       } else {
55
+           pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
56
+                   "%s sink", str);
57
+       }
58
+   }
59
    if ((str = pw_properties_get(props, "master")) != NULL) {
60
        pw_properties_set(playback_props, PW_KEY_NODE_TARGET, str);
61
        pw_properties_set(props, "master", NULL);
62
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c Changed
62
 
1
@@ -95,7 +95,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_remap_source_unload(struct client *client, struct module *module)
6
+static int module_remap_source_unload(struct module *module)
7
 {
8
    struct module_remap_source_data *d = module->user_data;
9
 
10
@@ -151,7 +151,7 @@
11
    struct module *module;
12
    struct module_remap_source_data *d;
13
    struct pw_properties *props = NULL, *playback_props = NULL, *capture_props = NULL;
14
-   const char *str;
15
+   const char *str, *master;
16
    struct spa_audio_info_raw capture_info = { 0 };
17
    struct spa_audio_info_raw playback_info = { 0 };
18
    int res;
19
@@ -168,16 +168,40 @@
20
    if (argument)
21
        module_args_add_props(props, argument);
22
 
23
+   master = pw_properties_get(props, "master");
24
+   if (pw_properties_get(props, "source_name") == NULL) {
25
+       pw_properties_setf(props, "source_name", "%s.remapped",
26
+               master ? master : "default");
27
+   }
28
    if ((str = pw_properties_get(props, "source_name")) != NULL) {
29
        pw_properties_set(playback_props, PW_KEY_NODE_NAME, str);
30
+       pw_properties_setf(capture_props, PW_KEY_NODE_NAME, "input.%s", str);
31
        pw_properties_set(props, "source_name", NULL);
32
    }
33
    if ((str = pw_properties_get(props, "source_properties")) != NULL) {
34
        module_args_add_props(playback_props, str);
35
        pw_properties_set(props, "source_properties", NULL);
36
    }
37
-   pw_properties_set(playback_props, PW_KEY_MEDIA_CLASS, "Audio/Source");
38
-
39
+   if (pw_properties_get(playback_props, PW_KEY_MEDIA_CLASS) == NULL)
40
+       pw_properties_set(playback_props, PW_KEY_MEDIA_CLASS, "Audio/Source");
41
+   if (pw_properties_get(playback_props, PW_KEY_DEVICE_CLASS) == NULL)
42
+       pw_properties_set(playback_props, PW_KEY_DEVICE_CLASS, "filter");
43
+
44
+   if ((str = pw_properties_get(playback_props, PW_KEY_MEDIA_NAME)) != NULL)
45
+       pw_properties_set(props, PW_KEY_MEDIA_NAME, str);
46
+   if ((str = pw_properties_get(playback_props, PW_KEY_NODE_DESCRIPTION)) != NULL) {
47
+       pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, str);
48
+   } else {
49
+       str = pw_properties_get(playback_props, PW_KEY_NODE_NAME);
50
+       if (master != NULL || str == NULL) {
51
+           pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
52
+                   "Remapped %s source",
53
+                   master ? master : "default");
54
+       } else {
55
+           pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
56
+                   "%s source", str);
57
+       }
58
+   }
59
    if ((str = pw_properties_get(props, "master")) != NULL) {
60
        pw_properties_set(capture_props, PW_KEY_NODE_TARGET, str);
61
        pw_properties_set(props, "master", NULL);
62
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c Changed
10
 
1
@@ -104,7 +104,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_roc_sink_unload(struct client *client, struct module *module)
6
+static int module_roc_sink_unload(struct module *module)
7
 {
8
    struct module_roc_sink_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c Changed
10
 
1
@@ -106,7 +106,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_roc_source_unload(struct client *client, struct module *module)
6
+static int module_roc_source_unload(struct module *module)
7
 {
8
    struct module_roc_source_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c Changed
117
 
1
@@ -36,9 +36,12 @@
2
 
3
 struct module_simple_protocol_tcp_data {
4
    struct module *module;
5
-   struct pw_properties *module_props;
6
    struct pw_impl_module *mod;
7
    struct spa_hook mod_listener;
8
+
9
+   struct pw_properties *module_props;
10
+
11
+   struct spa_audio_info_raw info;
12
 };
13
 
14
 static void module_destroy(void *data)
15
@@ -61,29 +64,26 @@
16
    struct module_simple_protocol_tcp_data *data = module->user_data;
17
    struct impl *impl = client->impl;
18
    char *args;
19
-   const char *str;
20
    size_t size;
21
+   uint32_t i;
22
    FILE *f;
23
 
24
    f = open_memstream(&args, &size);
25
-   if ((str = pw_properties_get(data->module_props, "audio.format")) != NULL)
26
-       fprintf(f, "audio.format=%s ", str);
27
-   if ((str = pw_properties_get(data->module_props, "audio.rate")) != NULL)
28
-       fprintf(f, "audio.rate=%s ", str);
29
-   if ((str = pw_properties_get(data->module_props, "audio.channels")) != NULL)
30
-       fprintf(f, "audio.channels=%s ", str);
31
-   if ((str = pw_properties_get(data->module_props, "server.address")) != NULL)
32
-       fprintf(f, "server.address=%s ", str);
33
-   if ((str = pw_properties_get(data->module_props, "capture")) != NULL)
34
-       fprintf(f, "capture=%s ", str);
35
-   if ((str = pw_properties_get(data->module_props, "playback")) != NULL)
36
-       fprintf(f, "playback=%s ", str);
37
-   if ((str = pw_properties_get(data->module_props, "capture.node")) != NULL)
38
-       fprintf(f, "capture.node=\"%s\" ", str);
39
-   if ((str = pw_properties_get(data->module_props, "playback.node")) != NULL)
40
-       fprintf(f, "playback.node=\"%s\" ", str);
41
-   if ((str = pw_properties_get(data->module_props, PW_KEY_STREAM_CAPTURE_SINK)) != NULL)
42
-       fprintf(f, PW_KEY_STREAM_CAPTURE_SINK"=\"%s\" ", str);
43
+   fprintf(f, "{");
44
+   if (data->info.rate != 0)
45
+       fprintf(f, " \"audio.rate\": %u,", data->info.rate);
46
+   if (data->info.channels != 0) {
47
+       fprintf(f, " \"audio.channels\": %u,", data->info.channels);
48
+       if (!(data->info.flags & SPA_AUDIO_FLAG_UNPOSITIONED)) {
49
+           fprintf(f, " \"audio.position\": [ ");
50
+           for (i = 0; i < data->info.channels; i++)
51
+               fprintf(f, "%s\"%s\"", i == 0 ? "" : ",",
52
+                   channel_id2name(data->info.position[i]));
53
+           fprintf(f, " ],");
54
+       }
55
+   }
56
+   pw_properties_serialize_dict(f, &data->module_props->dict, 0);
57
+   fprintf(f, "}");
58
    fclose(f);
59
 
60
    data->mod = pw_context_load_module(impl->context,
61
@@ -99,7 +99,7 @@
62
    return 0;
63
 }
64
 
65
-static int module_simple_protocol_tcp_unload(struct client *client, struct module *module)
66
+static int module_simple_protocol_tcp_unload(struct module *module)
67
 {
68
    struct module_simple_protocol_tcp_data *d = module->user_data;
69
 
70
@@ -125,6 +125,7 @@
71
    { PW_KEY_MODULE_USAGE, "rate=<sample rate> "
72
                "format=<sample format> "
73
                "channels=<number of channels> "
74
+               "channel_map=<number of channels> "
75
                "sink=<sink to connect to> "
76
                "source=<source to connect to> "
77
                "playback=<enable playback?> "
78
@@ -140,6 +141,7 @@
79
    struct module_simple_protocol_tcp_data *d;
80
    struct pw_properties *props = NULL, *module_props = NULL;
81
    const char *str, *port, *listen;
82
+   struct spa_audio_info_raw info = { 0 };
83
    int res;
84
 
85
    PW_LOG_TOPIC_INIT(mod_topic);
86
@@ -158,17 +160,14 @@
87
        goto out;
88
    }
89
 
90
-   if ((str = pw_properties_get(props, "rate")) != NULL) {
91
-       pw_properties_set(module_props, "audio.rate", str);
92
-       pw_properties_set(props, "rate", NULL);
93
-   }
94
    if ((str = pw_properties_get(props, "format")) != NULL) {
95
-       pw_properties_set(module_props, "audio.format", format_id2name(format_paname2id(str, strlen(str))));
96
+       pw_properties_set(module_props, "audio.format",
97
+               format_id2name(format_paname2id(str, strlen(str))));
98
        pw_properties_set(props, "format", NULL);
99
    }
100
-   if ((str = pw_properties_get(props, "channels")) != NULL) {
101
-       pw_properties_set(module_props, "audio.channels", str);
102
-       pw_properties_set(props, "channels", NULL);
103
+   if (module_args_to_audioinfo(impl, props, &info) < 0) {
104
+       res = -EINVAL;
105
+       goto out;
106
    }
107
    if ((str = pw_properties_get(props, "playback")) != NULL) {
108
        pw_properties_set(module_props, "playback", str);
109
@@ -213,6 +212,7 @@
110
    d = module->user_data;
111
    d->module = module;
112
    d->module_props = module_props;
113
+   d->info = info;
114
 
115
    return module;
116
 out:
117
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c Changed
10
 
1
@@ -209,7 +209,7 @@
2
    return res;
3
 }
4
 
5
-static int module_switch_on_connect_unload(struct client *client, struct module *module)
6
+static int module_switch_on_connect_unload(struct module *module)
7
 {
8
    struct module_switch_on_connect_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c Changed
10
 
1
@@ -100,7 +100,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_tunnel_sink_unload(struct client *client, struct module *module)
6
+static int module_tunnel_sink_unload(struct module *module)
7
 {
8
    struct module_tunnel_sink_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c Changed
10
 
1
@@ -100,7 +100,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_tunnel_source_unload(struct client *client, struct module *module)
6
+static int module_tunnel_source_unload(struct module *module)
7
 {
8
    struct module_tunnel_source_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c Changed
10
 
1
@@ -86,7 +86,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_x11_bell_unload(struct client *client, struct module *module)
6
+static int module_x11_bell_unload(struct module *module)
7
 {
8
    struct module_x11_bell_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c Changed
10
 
1
@@ -73,7 +73,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_zeroconf_discover_unload(struct client *client, struct module *module)
6
+static int module_zeroconf_discover_unload(struct module *module)
7
 {
8
    struct module_zeroconf_discover_data *d = module->user_data;
9
 
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c Changed
10
 
1
@@ -602,7 +602,7 @@
2
    return 0;
3
 }
4
 
5
-static int module_zeroconf_publish_unload(struct client *client, struct module *module)
6
+static int module_zeroconf_publish_unload(struct module *module)
7
 {
8
    struct module_zeroconf_publish_data *d = module->user_data;
9
    struct service *s;
10
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/pending-sample.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/pending-sample.c Changed
9
 
1
@@ -41,7 +41,5 @@
2
    spa_hook_remove(&ps->listener);
3
    pw_work_queue_cancel(impl->work_queue, ps, SPA_ID_INVALID);
4
 
5
-   client->ref--;
6
-
7
    sample_play_destroy(ps->play);
8
 }
9
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/pending-sample.h -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/pending-sample.h Changed
9
 
1
@@ -39,7 +39,6 @@
2
    struct sample_play *play;
3
    struct spa_hook listener;
4
    uint32_t tag;
5
-   unsigned int done:1;
6
 };
7
 
8
 void pending_sample_free(struct pending_sample *ps);
9
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/pulse-server.c Changed
479
 
1
@@ -22,8 +22,6 @@
2
  * DEALINGS IN THE SOFTWARE.
3
  */
4
 
5
-#include "pipewire/core.h"
6
-
7
 #include "config.h"
8
 
9
 #include <errno.h>
10
@@ -444,55 +442,66 @@
11
    return latency / frame_size;
12
 }
13
 
14
-static int reply_create_playback_stream(struct stream *stream, struct pw_manager_object *peer)
15
+static uint64_t set_playback_buffer_attr(struct stream *s, struct buffer_attr *attr)
16
 {
17
-   struct client *client = stream->client;
18
-   struct pw_manager *manager = client->manager;
19
-   struct message *reply;
20
-   uint32_t missing, peer_index;
21
+   struct spa_fraction lat;
22
+   uint64_t lat_usec;
23
    struct spa_dict_item items[5];
24
    char latency[32];
25
    char attr_maxlength[32];
26
    char attr_tlength[32];
27
    char attr_prebuf[32];
28
    char attr_minreq[32];
29
-   const char *peer_name;
30
-   struct spa_fraction lat;
31
-   uint64_t lat_usec;
32
 
33
-   lat.denom = stream->ss.rate;
34
-   lat.num = fix_playback_buffer_attr(stream, &stream->attr);
35
+   lat.denom = s->ss.rate;
36
+   lat.num = fix_playback_buffer_attr(s, attr);
37
 
38
-   stream->buffer = calloc(1, stream->attr.maxlength);
39
-   if (stream->buffer == NULL)
40
-       return -errno;
41
+   s->attr = *attr;
42
 
43
-   if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num)
44
-       lat.num = (stream->min_quantum.num * lat.denom +
45
-               (stream->min_quantum.denom -1)) / stream->min_quantum.denom;
46
+   if (lat.num * s->min_quantum.denom / lat.denom < s->min_quantum.num)
47
+       lat.num = (s->min_quantum.num * lat.denom +
48
+               (s->min_quantum.denom -1)) / s->min_quantum.denom;
49
    lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom;
50
 
51
    snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom);
52
-   snprintf(attr_maxlength, sizeof(attr_maxlength), "%u", stream->attr.maxlength);
53
-   snprintf(attr_tlength, sizeof(attr_tlength), "%u", stream->attr.tlength);
54
-   snprintf(attr_prebuf, sizeof(attr_prebuf), "%u", stream->attr.prebuf);
55
-   snprintf(attr_minreq, sizeof(attr_minreq), "%u", stream->attr.minreq);
56
+   snprintf(attr_maxlength, sizeof(attr_maxlength), "%u", s->attr.maxlength);
57
+   snprintf(attr_tlength, sizeof(attr_tlength), "%u", s->attr.tlength);
58
+   snprintf(attr_prebuf, sizeof(attr_prebuf), "%u", s->attr.prebuf);
59
+   snprintf(attr_minreq, sizeof(attr_minreq), "%u", s->attr.minreq);
60
 
61
    items[0] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_LATENCY, latency);
62
    items[1] = SPA_DICT_ITEM_INIT("pulse.attr.maxlength", attr_maxlength);
63
    items[2] = SPA_DICT_ITEM_INIT("pulse.attr.tlength", attr_tlength);
64
    items[3] = SPA_DICT_ITEM_INIT("pulse.attr.prebuf", attr_prebuf);
65
    items[4] = SPA_DICT_ITEM_INIT("pulse.attr.minreq", attr_minreq);
66
-   pw_stream_update_properties(stream->stream, &SPA_DICT_INIT(items, 5));
67
+   pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, 5));
68
 
69
-   if (stream->attr.prebuf > 0)
70
-       stream->in_prebuf = true;
71
+   if (s->attr.prebuf > 0)
72
+       s->in_prebuf = true;
73
+
74
+   return lat_usec;
75
+}
76
+
77
+static int reply_create_playback_stream(struct stream *stream, struct pw_manager_object *peer)
78
+{
79
+   struct client *client = stream->client;
80
+   struct pw_manager *manager = client->manager;
81
+   struct message *reply;
82
+   uint32_t missing, peer_index;
83
+   const char *peer_name;
84
+   uint64_t lat_usec;
85
+
86
+   stream->buffer = calloc(1, MAXLENGTH);
87
+   if (stream->buffer == NULL)
88
+       return -errno;
89
+
90
+   lat_usec = set_playback_buffer_attr(stream, &stream->attr);
91
 
92
    missing = stream_pop_missing(stream);
93
    stream->index = id_to_index(manager, stream->id);
94
 
95
-   pw_log_info("[%s] reply CREATE_PLAYBACK_STREAM tag:%u index:%u missing:%u latency:%s",
96
-           client->name, stream->create_tag, stream->index, missing, latency);
97
+   pw_log_info("[%s] reply CREATE_PLAYBACK_STREAM tag:%u index:%u missing:%u lat:%"PRIu64,
98
+           client->name, stream->create_tag, stream->index, missing, lat_usec);
99
 
100
    reply = reply_new(client, stream->create_tag);
101
    message_put(reply,
102
@@ -584,47 +593,56 @@
103
    return latency / frame_size;
104
 }
105
 
106
-static int reply_create_record_stream(struct stream *stream, struct pw_manager_object *peer)
107
+static uint64_t set_record_buffer_attr(struct stream *s, struct buffer_attr *attr)
108
 {
109
-   struct client *client = stream->client;
110
-   struct pw_manager *manager = client->manager;
111
-   struct message *reply;
112
    struct spa_dict_item items[3];
113
-   char latency[32], *tmp;
114
+   char latency[32];
115
    char attr_maxlength[32];
116
    char attr_fragsize[32];
117
-   const char *peer_name, *name;
118
-   uint32_t peer_index;
119
    struct spa_fraction lat;
120
    uint64_t lat_usec;
121
 
122
-   lat.denom = stream->ss.rate;
123
-   lat.num = fix_record_buffer_attr(stream, &stream->attr);
124
-
125
-   stream->buffer = calloc(1, stream->attr.maxlength);
126
-   if (stream->buffer == NULL)
127
-       return -errno;
128
+   lat.denom = s->ss.rate;
129
+   lat.num = fix_record_buffer_attr(s, &s->attr);
130
 
131
-   if (lat.num * stream->min_quantum.denom / lat.denom < stream->min_quantum.num)
132
-       lat.num = (stream->min_quantum.num * lat.denom +
133
-               (stream->min_quantum.denom -1)) / stream->min_quantum.denom;
134
+   if (lat.num * s->min_quantum.denom / lat.denom < s->min_quantum.num)
135
+       lat.num = (s->min_quantum.num * lat.denom +
136
+               (s->min_quantum.denom -1)) / s->min_quantum.denom;
137
    lat_usec = lat.num * SPA_USEC_PER_SEC / lat.denom;
138
 
139
    snprintf(latency, sizeof(latency), "%u/%u", lat.num, lat.denom);
140
 
141
-   snprintf(attr_maxlength, sizeof(attr_maxlength), "%u", stream->attr.maxlength);
142
-   snprintf(attr_fragsize, sizeof(attr_fragsize), "%u", stream->attr.fragsize);
143
+   snprintf(attr_maxlength, sizeof(attr_maxlength), "%u", s->attr.maxlength);
144
+   snprintf(attr_fragsize, sizeof(attr_fragsize), "%u", s->attr.fragsize);
145
 
146
    items[0] = SPA_DICT_ITEM_INIT(PW_KEY_NODE_LATENCY, latency);
147
    items[1] = SPA_DICT_ITEM_INIT("pulse.attr.maxlength", attr_maxlength);
148
    items[2] = SPA_DICT_ITEM_INIT("pulse.attr.fragsize", attr_fragsize);
149
-   pw_stream_update_properties(stream->stream,
150
-           &SPA_DICT_INIT(items, 3));
151
+   pw_stream_update_properties(s->stream, &SPA_DICT_INIT(items, 3));
152
+
153
+   return lat_usec;
154
+}
155
+
156
+static int reply_create_record_stream(struct stream *stream, struct pw_manager_object *peer)
157
+{
158
+   struct client *client = stream->client;
159
+   struct pw_manager *manager = client->manager;
160
+   char *tmp;
161
+   struct message *reply;
162
+   const char *peer_name, *name;
163
+   uint32_t peer_index;
164
+   uint64_t lat_usec;
165
+
166
+   stream->buffer = calloc(1, MAXLENGTH);
167
+   if (stream->buffer == NULL)
168
+       return -errno;
169
+
170
+   lat_usec = set_record_buffer_attr(stream, &stream->attr);
171
 
172
    stream->index = id_to_index(manager, stream->id);
173
 
174
-   pw_log_info("[%s] reply CREATE_RECORD_STREAM tag:%u index:%u latency:%s",
175
-           client->name, stream->create_tag, stream->index, latency);
176
+   pw_log_info("[%s] reply CREATE_RECORD_STREAM tag:%u index:%u latency:%"PRIu64,
177
+           client->name, stream->create_tag, stream->index, lat_usec);
178
 
179
    reply = reply_new(client, stream->create_tag);
180
    message_put(reply,
181
@@ -837,7 +855,7 @@
182
 
183
 static void do_free_client(void *obj, void *data, int res, uint32_t id)
184
 {
185
-   struct client *client = data;
186
+   struct client *client = obj;
187
    client_free(client);
188
 }
189
 
190
@@ -845,8 +863,8 @@
191
 {
192
    struct client *client = data;
193
    pw_log_debug("manager_disconnect()");
194
-   pw_work_queue_add(client->impl->work_queue, NULL, 0,
195
-               do_free_client, client);
196
+   pw_work_queue_add(client->impl->work_queue, client, 0,
197
+               do_free_client, NULL);
198
 }
199
 
200
 static const struct pw_manager_events manager_events = {
201
@@ -952,13 +970,11 @@
202
    }
203
 }
204
 
205
-static void on_stream_cleanup(void *obj, void *data, int res, uint32_t id)
206
+static void do_destroy_stream(void *obj, void *data, int res, uint32_t id)
207
 {
208
    struct stream *stream = obj;
209
-   struct client *client = stream->client;
210
+
211
    stream_free(stream);
212
-   if (client->ref <= 0)
213
-       client_free(client);
214
 }
215
 
216
 static void stream_state_changed(void *data, enum pw_stream_state old,
217
@@ -967,27 +983,29 @@
218
    struct stream *stream = data;
219
    struct client *client = stream->client;
220
    struct impl *impl = client->impl;
221
+   bool destroy_stream = false;
222
 
223
    switch (state) {
224
    case PW_STREAM_STATE_ERROR:
225
        reply_error(client, -1, stream->create_tag, -EIO);
226
-       stream->done = true;
227
+       destroy_stream = true;
228
        break;
229
    case PW_STREAM_STATE_UNCONNECTED:
230
        if (stream->create_tag != SPA_ID_INVALID)
231
            reply_error(client, -1, stream->create_tag, -ENOENT);
232
-       else if (!client->disconnecting)
233
+       else
234
            stream->killed = true;
235
-       stream->done = true;
236
+       destroy_stream = true;
237
        break;
238
    case PW_STREAM_STATE_CONNECTING:
239
    case PW_STREAM_STATE_PAUSED:
240
    case PW_STREAM_STATE_STREAMING:
241
        break;
242
    }
243
-   if (stream->done) {
244
+
245
+   if (destroy_stream) {
246
        pw_work_queue_add(impl->work_queue, stream, 0,
247
-               on_stream_cleanup, client);
248
+               do_destroy_stream, NULL);
249
    }
250
 }
251
 
252
@@ -1186,8 +1204,8 @@
253
                    return -errno;
254
 
255
                spa_ringbuffer_read_data(&stream->ring,
256
-                       stream->buffer, stream->attr.maxlength,
257
-                       index % stream->attr.maxlength,
258
+                       stream->buffer, MAXLENGTH,
259
+                       index % MAXLENGTH,
260
                        msg->data, towrite);
261
 
262
                client_queue_message(client, msg);
263
@@ -1255,8 +1273,8 @@
264
            if ((stream->attr.prebuf == 0 || do_flush) && !stream->corked) {
265
                if (avail > 0) {
266
                    spa_ringbuffer_read_data(&stream->ring,
267
-                       stream->buffer, stream->attr.maxlength,
268
-                       index % stream->attr.maxlength,
269
+                       stream->buffer, MAXLENGTH,
270
+                       index % MAXLENGTH,
271
                        p, avail);
272
                }
273
                pd.playing_for = size;
274
@@ -1282,8 +1300,8 @@
275
            size = SPA_MIN(size, minreq);
276
 
277
            spa_ringbuffer_read_data(&stream->ring,
278
-                   stream->buffer, stream->attr.maxlength,
279
-                   index % stream->attr.maxlength,
280
+                   stream->buffer, MAXLENGTH,
281
+                   index % MAXLENGTH,
282
                    p, size);
283
 
284
            index += size;
285
@@ -1315,10 +1333,10 @@
286
        }
287
 
288
        spa_ringbuffer_write_data(&stream->ring,
289
-               stream->buffer, stream->attr.maxlength,
290
-               index % stream->attr.maxlength,
291
+               stream->buffer, MAXLENGTH,
292
+               index % MAXLENGTH,
293
                SPA_PTROFF(p, buf->datas[0].chunk->offset, void),
294
-               SPA_MIN(size, stream->attr.maxlength));
295
+               SPA_MIN(size, MAXLENGTH));
296
 
297
        index += size;
298
        pd.write_inc = size;
299
@@ -2080,7 +2098,7 @@
300
 
301
    stream->props = props;
302
 
303
-   stream->buffer = calloc(1, stream->attr.maxlength);
304
+   stream->buffer = calloc(1, MAXLENGTH);
305
    if (stream->buffer == NULL)
306
        goto error_errno;
307
 
308
@@ -2139,7 +2157,7 @@
309
            channel, name);
310
 
311
    struct sample *old = find_sample(impl, SPA_ID_INVALID, name);
312
-   if (old == NULL || (old != NULL && old->ref > 1)) {
313
+   if (old == NULL || old->ref > 1) {
314
        sample = calloc(1, sizeof(*sample));
315
        if (sample == NULL)
316
            goto error_errno;
317
@@ -2326,9 +2344,9 @@
318
 {
319
    struct pending_sample *ps = obj;
320
    struct client *client = ps->client;
321
+
322
    pending_sample_free(ps);
323
-   if (client->ref <= 0)
324
-       client_free(client);
325
+   client_unref(client);
326
 }
327
 
328
 static void sample_play_done(void *data, int res)
329
@@ -2342,7 +2360,6 @@
330
    else
331
        pw_log_info("[%s] PLAY_SAMPLE done tag:%u", client->name, ps->tag);
332
 
333
-   ps->done = true;
334
    pw_work_queue_add(impl->work_queue, ps, 0,
335
                on_sample_done, client);
336
 }
337
@@ -4299,6 +4316,7 @@
338
    struct message *reply;
339
    struct buffer_attr attr;
340
    bool adjust_latency = false, early_requests = false;
341
+   uint64_t lat_usec;
342
 
343
    if (message_get(m,
344
            TAG_U32, &channel,
345
@@ -4348,7 +4366,12 @@
346
 
347
    reply = reply_new(client, tag);
348
 
349
+   stream->adjust_latency = adjust_latency;
350
+   stream->early_requests = early_requests;
351
+
352
    if (command == COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
353
+       lat_usec = set_playback_buffer_attr(stream, &attr);
354
+
355
        message_put(reply,
356
            TAG_U32, stream->attr.maxlength,
357
            TAG_U32, stream->attr.tlength,
358
@@ -4357,17 +4380,19 @@
359
            TAG_INVALID);
360
        if (client->version >= 13) {
361
            message_put(reply,
362
-               TAG_USEC, 0LL,      /* configured_sink_latency */
363
+               TAG_USEC, lat_usec,     /* configured_sink_latency */
364
                TAG_INVALID);
365
        }
366
    } else {
367
+       lat_usec = set_record_buffer_attr(stream, &attr);
368
+
369
        message_put(reply,
370
            TAG_U32, stream->attr.maxlength,
371
            TAG_U32, stream->attr.fragsize,
372
            TAG_INVALID);
373
        if (client->version >= 13) {
374
            message_put(reply,
375
-               TAG_USEC, 0LL,      /* configured_source_latency */
376
+               TAG_USEC, lat_usec,     /* configured_source_latency */
377
                TAG_INVALID);
378
        }
379
    }
380
@@ -4803,7 +4828,7 @@
381
    if (module == NULL)
382
        return -ENOENT;
383
 
384
-   module_unload(client, module);
385
+   module_unload(module);
386
 
387
    return reply_simple_ack(client, tag);
388
 }
389
@@ -5045,55 +5070,66 @@
390
 static int impl_free_sample(void *item, void *data)
391
 {
392
    struct sample *s = item;
393
-   sample_free(s);
394
+
395
+   spa_assert(s->ref == 1);
396
+   sample_unref(s);
397
+
398
    return 0;
399
 }
400
 
401
-static int impl_free_module(void *item, void *data)
402
+static int impl_unload_module(void *item, void *data)
403
 {
404
    struct module *m = item;
405
-   module_free(m);
406
+   module_unload(m);
407
    return 0;
408
 }
409
 
410
-static void impl_free(struct impl *impl)
411
+static void impl_clear(struct impl *impl)
412
 {
413
+   struct message *msg;
414
    struct server *s;
415
    struct client *c;
416
-   struct message *msg;
417
-
418
-#if HAVE_DBUS
419
-   if (impl->dbus_name)
420
-       dbus_release_name(impl->dbus_name);
421
-#endif
422
 
423
-   spa_list_consume(msg, &impl->free_messages, link)
424
-       message_free(impl, msg, true, true);
425
+   spa_list_consume(s, &impl->servers, link)
426
+       server_free(s);
427
 
428
-   if (impl->context != NULL)
429
-       spa_hook_remove(&impl->context_listener);
430
    spa_list_consume(c, &impl->cleanup_clients, link)
431
        client_free(c);
432
-   spa_list_consume(s, &impl->servers, link)
433
-       server_free(s);
434
+
435
+   spa_list_consume(msg, &impl->free_messages, link)
436
+       message_free(impl, msg, true, true);
437
 
438
    pw_map_for_each(&impl->samples, impl_free_sample, impl);
439
    pw_map_clear(&impl->samples);
440
-   pw_map_for_each(&impl->modules, impl_free_module, impl);
441
+
442
+   pw_map_for_each(&impl->modules, impl_unload_module, impl);
443
    pw_map_clear(&impl->modules);
444
 
445
+#if HAVE_DBUS
446
+   if (impl->dbus_name) {
447
+       dbus_release_name(impl->dbus_name);
448
+       impl->dbus_name = NULL;
449
+   }
450
+#endif
451
+
452
+   if (impl->context) {
453
+       spa_hook_remove(&impl->context_listener);
454
+       impl->context = NULL;
455
+   }
456
+
457
    pw_properties_free(impl->props);
458
+   impl->props = NULL;
459
+}
460
+
461
+static void impl_free(struct impl *impl)
462
+{
463
+   impl_clear(impl);
464
    free(impl);
465
 }
466
 
467
 static void context_destroy(void *data)
468
 {
469
-   struct impl *impl = data;
470
-   struct server *s;
471
-   spa_list_consume(s, &impl->servers, link)
472
-       server_free(s);
473
-   spa_hook_remove(&impl->context_listener);
474
-   impl->context = NULL;
475
+   impl_clear(data);
476
 }
477
 
478
 static const struct pw_context_events context_events = {
479
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/quirks.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/quirks.c Changed
28
 
1
@@ -170,15 +170,19 @@
2
    return 0;
3
 }
4
 
5
+static int apply_pulse_rules(void *data, const char *location, const char *section,
6
+       const char *str, size_t len)
7
+{
8
+   struct client *client = data;
9
+   pw_conf_match_rules(str, len, &client->props->dict,
10
+           client_rule_matched, client);
11
+   return 0;
12
+}
13
+
14
 int client_update_quirks(struct client *client)
15
 {
16
    struct impl *impl = client->impl;
17
    struct pw_context *context = impl->context;
18
-   const char *rules;
19
-
20
-   if ((rules = pw_context_get_conf_section(context, "pulse.rules")) == NULL)
21
-       return 0;
22
-
23
-   return pw_conf_match_rules(rules, strlen(rules), &client->props->dict,
24
-           client_rule_matched, client);
25
+   return pw_context_conf_section_for_each(context, "pulse.rules",
26
+           apply_pulse_rules, client);
27
 }
28
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/server.c Changed
15
 
1
@@ -178,10 +178,10 @@
2
    /* always write data to ringbuffer, we expect the other side
3
     * to recover */
4
    spa_ringbuffer_write_data(&stream->ring,
5
-           stream->buffer, stream->attr.maxlength,
6
-           index % stream->attr.maxlength,
7
+           stream->buffer, MAXLENGTH,
8
+           index % MAXLENGTH,
9
            msg->data,
10
-           SPA_MIN(msg->length, stream->attr.maxlength));
11
+           SPA_MIN(msg->length, MAXLENGTH));
12
    index += msg->length;
13
    stream->write_index += msg->length;
14
    spa_ringbuffer_write_update(&stream->ring, index);
15
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/stream.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/stream.c Changed
22
 
1
@@ -38,6 +38,7 @@
2
 
3
 #include "client.h"
4
 #include "commands.h"
5
+#include "defs.h"
6
 #include "internal.h"
7
 #include "log.h"
8
 #include "message.h"
9
@@ -331,7 +332,12 @@
10
    if (new_tlength <= old_tlength)
11
        return 0;
12
 
13
+   if (new_tlength > MAXLENGTH)
14
+       new_tlength = MAXLENGTH;
15
+
16
    stream->attr.tlength = new_tlength;
17
+   if (stream->attr.tlength > stream->attr.maxlength)
18
+       stream->attr.maxlength = stream->attr.tlength;
19
 
20
    if (client->version >= 15) {
21
        struct message *msg;
22
pipewire-0.3.44.tar.gz/src/modules/module-protocol-pulse/stream.h -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-pulse/stream.h Changed
9
 
1
@@ -111,7 +111,6 @@
2
    unsigned int adjust_latency:1;
3
    unsigned int is_underrun:1;
4
    unsigned int in_prebuf:1;
5
-   unsigned int done:1;
6
    unsigned int killed:1;
7
    unsigned int pending:1;
8
 };
9
pipewire-0.3.44.tar.gz/src/modules/module-protocol-simple.c -> pipewire-0.3.45.tar.gz/src/modules/module-protocol-simple.c Changed
48
 
1
@@ -64,13 +64,15 @@
2
 #define DEFAULT_RATE "44100"
3
 #define DEFAULT_CHANNELS 2
4
 #define DEFAULT_POSITION "[ FL FR ]"
5
-#define DEFAULT_LATENCY "1024/48000"
6
+#define DEFAULT_LATENCY "1024/44100"
7
 
8
 #define MAX_CLIENTS    10
9
 
10
 #define MODULE_USAGE   "[ capture=<bool> ] "                       \
11
            "[ playback=<bool> ] "                      \
12
-           "[ capture.node=<source-target> ] "             \
13
+           "[ node.latency=<num/denom, default:"DEFAULT_LATENCY"> ] "  \
14
+           "[ node.rate=<1/rate, default:1/"DEFAULT_RATE"> ] " \
15
+           "[ capture.node=<source-target> [ stream.capture.sink=true ]] " \
16
            "[ playback.node=<sink-target> ] "              \
17
            "[ audio.rate=<sample-rate, default:"DEFAULT_RATE"> ] "     \
18
            "[ audio.format=<format, default:"DEFAULT_FORMAT"> ] "      \
19
@@ -384,12 +386,17 @@
20
    uint8_t buffer[1024];
21
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
22
    struct pw_properties *props;
23
+   const char *latency;
24
    int res;
25
 
26
+   if ((latency = pw_properties_get(impl->props, PW_KEY_NODE_LATENCY)) == NULL)
27
+       latency = DEFAULT_LATENCY;
28
+
29
    if (impl->capture) {
30
        props = pw_properties_new(
31
            PW_KEY_NODE_GROUP, "pipewire.dummy",
32
-           PW_KEY_NODE_LATENCY, DEFAULT_LATENCY,
33
+           PW_KEY_NODE_LATENCY, latency,
34
+           PW_KEY_NODE_RATE, pw_properties_get(impl->props, PW_KEY_NODE_RATE),
35
            PW_KEY_NODE_TARGET, pw_properties_get(impl->props, "capture.node"),
36
            PW_KEY_STREAM_CAPTURE_SINK, pw_properties_get(impl->props,
37
                PW_KEY_STREAM_CAPTURE_SINK),
38
@@ -412,7 +419,8 @@
39
    if (impl->playback) {
40
        props = pw_properties_new(
41
            PW_KEY_NODE_GROUP, "pipewire.dummy",
42
-           PW_KEY_NODE_LATENCY, DEFAULT_LATENCY,
43
+           PW_KEY_NODE_LATENCY, latency,
44
+           PW_KEY_NODE_RATE, pw_properties_get(impl->props, PW_KEY_NODE_RATE),
45
            PW_KEY_NODE_TARGET, pw_properties_get(impl->props, "playback.node"),
46
            PW_KEY_NODE_NETWORK, "true",
47
            NULL);
48
pipewire-0.3.44.tar.gz/src/modules/module-session-manager/protocol-native.c -> pipewire-0.3.45.tar.gz/src/modules/module-session-manager/protocol-native.c Changed
66
 
1
@@ -32,6 +32,10 @@
2
 #include <pipewire/extensions/session-manager.h>
3
 #include <pipewire/extensions/protocol-native.h>
4
 
5
+#define MAX_DICT   256
6
+#define MAX_PARAMS 128
7
+#define MAX_PARAM_INFO 128
8
+
9
 static void push_dict(struct spa_pod_builder *b, const struct spa_dict *dict)
10
 {
11
    struct spa_pod_frame f;
12
@@ -61,6 +65,8 @@
13
        return -EINVAL; \
14
    \
15
    if ((dict)->n_items > 0) { \
16
+       if ((dict)->n_items > MAX_DICT) \
17
+           return -ENOSPC; \
18
        (dict)->items = alloca((dict)->n_items * sizeof(struct spa_dict_item)); \
19
        for (i = 0; i < (dict)->n_items; i++) { \
20
            if (spa_pod_parser_get(p, \
21
@@ -100,6 +106,8 @@
22
        return -EINVAL; \
23
    \
24
    if (*(n_params_p) > 0) { \
25
+       if (*(n_params_p) > MAX_PARAM_INFO) \
26
+           return -ENOSPC; \
27
        *(params_p) = alloca(*(n_params_p) * sizeof(struct spa_param_info)); \
28
        for (i = 0; i < *(n_params_p); i++) { \
29
            if (spa_pod_parser_get(p, \
30
@@ -553,6 +561,8 @@
31
            SPA_POD_Int(&n_params), NULL) < 0)
32
        return -EINVAL;
33
 
34
+   if (n_params > MAX_PARAMS)
35
+       return -ENOSPC;
36
    if (n_params > 0)
37
        params = alloca(n_params * sizeof(struct spa_pod *));
38
    for (i = 0; i < n_params; i++)
39
@@ -593,6 +603,8 @@
40
            SPA_POD_Int(&n_params), NULL) < 0)
41
        return -EINVAL;
42
 
43
+   if (n_params > MAX_PARAMS)
44
+       return -ENOSPC;
45
    if (n_params > 0)
46
        params = alloca(n_params * sizeof(struct spa_pod *));
47
    for (i = 0; i < n_params; i++)
48
@@ -867,6 +879,8 @@
49
            SPA_POD_Int(&n_params), NULL) < 0)
50
        return -EINVAL;
51
 
52
+   if (n_params > MAX_PARAMS)
53
+       return -ENOSPC;
54
    if (n_params > 0)
55
        params = alloca(n_params * sizeof(struct spa_pod *));
56
    for (i = 0; i < n_params; i++)
57
@@ -907,6 +921,8 @@
58
            SPA_POD_Int(&n_params), NULL) < 0)
59
        return -EINVAL;
60
 
61
+   if (n_params > MAX_PARAMS)
62
+       return -ENOSPC;
63
    if (n_params > 0)
64
        params = alloca(n_params * sizeof(struct spa_pod *));
65
    for (i = 0; i < n_params; i++)
66
pipewire-0.3.44.tar.gz/src/modules/spa/module-device-factory.c -> pipewire-0.3.45.tar.gz/src/modules/spa/module-device-factory.c Changed
19
 
1
@@ -165,15 +165,10 @@
2
 
3
 error_properties:
4
    res = -EINVAL;
5
-   pw_log_error("factory %p: usage: " FACTORY_USAGE, data->this);
6
-   if (resource)
7
-       pw_resource_errorf_id(resource, new_id, res,
8
-               "usage: "FACTORY_USAGE);
9
+   pw_resource_errorf_id(resource, new_id, res, "usage: "FACTORY_USAGE);
10
    goto error_exit_cleanup;
11
 error_device:
12
-   pw_log_debug("can't create device %s: %s", factory_name, spa_strerror(res));
13
-   if (resource)
14
-       pw_resource_errorf_id(resource, new_id, res,
15
+   pw_resource_errorf_id(resource, new_id, res,
16
                "can't create device %s: %s", factory_name,
17
                spa_strerror(res));
18
    goto error_exit;
19
pipewire-0.3.44.tar.gz/src/modules/spa/module-node-factory.c -> pipewire-0.3.45.tar.gz/src/modules/spa/module-node-factory.c Changed
20
 
1
@@ -163,16 +163,11 @@
2
 
3
 error_properties:
4
    res = -EINVAL;
5
-   pw_log_error("factory %p: usage: " FACTORY_USAGE, data->this);
6
-   if (resource)
7
-       pw_resource_errorf_id(resource, new_id, res,
8
-               "usage: "FACTORY_USAGE);
9
+   pw_resource_errorf_id(resource, new_id, res, "usage: "FACTORY_USAGE);
10
    goto error_exit_cleanup;
11
 error_create_node:
12
    res = -errno;
13
-   pw_log_error("can't create node: %m");
14
-   if (resource)
15
-       pw_resource_errorf_id(resource, new_id, res,
16
+   pw_resource_errorf_id(resource, new_id, res,
17
                "can't create node: %s", spa_strerror(res));
18
    goto error_exit;
19
 error_bind:
20
pipewire-0.3.44.tar.gz/src/pipewire/conf.c -> pipewire-0.3.45.tar.gz/src/pipewire/conf.c Changed
599
 
1
@@ -33,6 +33,7 @@
2
 #include <fcntl.h>
3
 #include <unistd.h>
4
 #include <sys/wait.h>
5
+#include <dirent.h>
6
 #if HAVE_PWD_H
7
 #include <pwd.h>
8
 #endif
9
@@ -45,6 +46,7 @@
10
 #include <spa/utils/json.h>
11
 
12
 #include <pipewire/impl.h>
13
+#include <pipewire/private.h>
14
 
15
 PW_LOG_TOPIC_EXTERN(log_conf);
16
 #define PW_LOG_TOPIC_DEFAULT log_conf
17
@@ -65,34 +67,21 @@
18
    return 0;
19
 }
20
 
21
-static int get_config_path(char *path, size_t size, const char *prefix, const char *name)
22
+static int get_abs_path(char *path, size_t size, const char *prefix, const char *name)
23
 {
24
-   const char *dir;
25
-   char buffer[4096];
26
-
27
-   if (name[0] == '/') {
28
-       const char *paths[] = { name, NULL };
29
-       if (make_path(path, size, paths) == 0 &&
30
-           access(path, R_OK) == 0)
31
-           return 1;
32
-       return -ENOENT;
33
-   }
34
-
35
-   if (prefix && prefix[0] == '/') {
36
+   if (prefix[0] == '/') {
37
        const char *paths[] = { prefix, name, NULL };
38
        if (make_path(path, size, paths) == 0 &&
39
            access(path, R_OK) == 0)
40
            return 1;
41
        return -ENOENT;
42
    }
43
+   return 0;
44
+}
45
 
46
-   if (prefix == NULL) {
47
-       prefix = name;
48
-       name = NULL;
49
-   }
50
-
51
-   if (pw_check_option("no-config", "true"))
52
-       goto no_config;
53
+static int get_envconf_path(char *path, size_t size, const char *prefix, const char *name)
54
+{
55
+   const char *dir;
56
 
57
    dir = getenv("PIPEWIRE_CONFIG_DIR");
58
    if (dir != NULL) {
59
@@ -100,7 +89,15 @@
60
        if (make_path(path, size, paths) == 0 &&
61
            access(path, R_OK) == 0)
62
            return 1;
63
+       return -ENOENT;
64
    }
65
+   return 0;
66
+}
67
+
68
+static int get_homeconf_path(char *path, size_t size, const char *prefix, const char *name)
69
+{
70
+   char buffer[4096];
71
+   const char *dir;
72
 
73
    dir = getenv("XDG_CONFIG_HOME");
74
    if (dir != NULL) {
75
@@ -121,7 +118,12 @@
76
            access(path, R_OK) == 0)
77
            return 1;
78
    }
79
+   return 0;
80
+}
81
 
82
+static int get_configdir_path(char *path, size_t size, const char *prefix, const char *name)
83
+{
84
+   const char *dir;
85
    dir = PIPEWIRE_CONFIG_DIR;
86
    if (dir != NULL) {
87
        const char *paths[] = { dir, prefix, name, NULL };
88
@@ -129,7 +131,12 @@
89
            access(path, R_OK) == 0)
90
            return 1;
91
    }
92
-no_config:
93
+   return 0;
94
+}
95
+
96
+static int get_confdata_path(char *path, size_t size, const char *prefix, const char *name)
97
+{
98
+   const char *dir;
99
    dir = PIPEWIRE_CONFDATADIR;
100
    if (dir != NULL) {
101
        const char *paths[] = { dir, prefix, name, NULL };
102
@@ -140,39 +147,93 @@
103
    return 0;
104
 }
105
 
106
-static int get_state_path(char *path, size_t size, const char *prefix, const char *name)
107
+static int get_config_path(char *path, size_t size, const char *prefix, const char *name)
108
 {
109
-   const char *dir;
110
-   char buffer[4096];
111
+   int res;
112
 
113
-   if (name[0] == '/') {
114
-       const char *paths[] = { name, NULL };
115
-       if (make_path(path, size, paths) == 0 &&
116
-           access(path, R_OK) == 0)
117
-           return 1;
118
-       return -ENOENT;
119
+   if (prefix == NULL) {
120
+       prefix = name;
121
+       name = NULL;
122
    }
123
+   if ((res = get_abs_path(path, size, prefix, name)) != 0)
124
+       return res;
125
 
126
-   if (prefix && prefix[0] == '/') {
127
-       const char *paths[] = { prefix, name, NULL };
128
-       if (make_path(path, size, paths) == 0 &&
129
-           access(path, R_OK) == 0)
130
-           return 1;
131
-       return -ENOENT;
132
-   }
133
+   if (pw_check_option("no-config", "true"))
134
+       goto no_config;
135
+
136
+   if ((res = get_envconf_path(path, size, prefix, name)) != 0)
137
+       return res;
138
+
139
+   if ((res = get_homeconf_path(path, size, prefix, name)) != 0)
140
+       return res;
141
+
142
+   if ((res = get_configdir_path(path, size, prefix, name)) != 0)
143
+       return res;
144
+no_config:
145
+   if ((res = get_confdata_path(path, size, prefix, name)) != 0)
146
+       return res;
147
+   return 0;
148
+}
149
+
150
+static int get_config_dir(char *path, size_t size, const char *prefix, const char *name, int *level)
151
+{
152
+   int res;
153
 
154
    if (prefix == NULL) {
155
        prefix = name;
156
        name = NULL;
157
    }
158
+   if ((res = get_abs_path(path, size, prefix, name)) != 0) {
159
+       if ((*level)++ == 0)
160
+           return res;
161
+       return -ENOENT;
162
+   }
163
+
164
+   if ((res = get_envconf_path(path, size, prefix, name)) != 0) {
165
+       if ((*level)++ == 0)
166
+           return res;
167
+       return -ENOENT;
168
+   }
169
+
170
+   if (*level == 0) {
171
+       (*level)++;
172
+       if ((res = get_confdata_path(path, size, prefix, name)) != 0)
173
+           return res;
174
+   }
175
+   if (pw_check_option("no-config", "true"))
176
+       return 0;
177
 
178
+   if (*level == 1) {
179
+       (*level)++;
180
+       if ((res = get_configdir_path(path, size, prefix, name)) != 0)
181
+           return res;
182
+   }
183
+   if (*level == 2) {
184
+       (*level)++;
185
+       if ((res = get_homeconf_path(path, size, prefix, name)) != 0)
186
+           return res;
187
+   }
188
+   return 0;
189
+}
190
+
191
+static int get_envstate_path(char *path, size_t size, const char *prefix, const char *name)
192
+{
193
+   const char *dir;
194
    dir = getenv("PIPEWIRE_STATE_DIR");
195
    if (dir != NULL) {
196
        const char *paths[] = { dir, prefix, name, NULL };
197
        if (make_path(path, size, paths) == 0 &&
198
            access(path, R_OK) == 0)
199
            return 1;
200
+       return -ENOENT;
201
    }
202
+   return 0;
203
+}
204
+
205
+static int get_homestate_path(char *path, size_t size, const char *prefix, const char *name)
206
+{
207
+   const char *dir;
208
+   char buffer[4096];
209
 
210
    dir = getenv("XDG_STATE_HOME");
211
    if (dir != NULL) {
212
@@ -200,6 +261,25 @@
213
            access(path, R_OK) == 0)
214
            return 1;
215
    }
216
+   return 0;
217
+}
218
+
219
+static int get_state_path(char *path, size_t size, const char *prefix, const char *name)
220
+{
221
+   int res;
222
+
223
+   if (prefix == NULL) {
224
+       prefix = name;
225
+       name = NULL;
226
+   }
227
+   if ((res = get_abs_path(path, size, prefix, name)) != 0)
228
+       return res;
229
+
230
+   if ((res = get_envstate_path(path, size, prefix, name)) != 0)
231
+       return res;
232
+
233
+   if ((res = get_homestate_path(path, size, prefix, name)) != 0)
234
+       return res;
235
 
236
    return 0;
237
 }
238
@@ -317,34 +397,57 @@
239
 {
240
    char *data;
241
    struct stat sbuf;
242
-   int fd;
243
+   int fd, count;
244
 
245
-   if ((fd = open(path,  O_CLOEXEC | O_RDONLY)) < 0)  {
246
-       pw_log_warn("%p: error loading config '%s': %m", conf, path);
247
-       return -errno;
248
-   }
249
+   if ((fd = open(path,  O_CLOEXEC | O_RDONLY)) < 0)
250
+       goto error;
251
 
252
-   pw_log_info("%p: loading config '%s'", conf, path);
253
    if (fstat(fd, &sbuf) < 0)
254
        goto error_close;
255
    if ((data = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
256
        goto error_close;
257
    close(fd);
258
 
259
-   pw_properties_update_string(conf, data, sbuf.st_size);
260
+   count = pw_properties_update_string(conf, data, sbuf.st_size);
261
    munmap(data, sbuf.st_size);
262
 
263
+   pw_log_info("%p: loaded config '%s' with %d items", conf, path, count);
264
+
265
    return 0;
266
 
267
 error_close:
268
    close(fd);
269
+error:
270
+   pw_log_warn("%p: error loading config '%s': %m", conf, path);
271
    return -errno;
272
 }
273
 
274
+static void add_override(struct pw_properties *conf, struct pw_properties *override,
275
+       const char *path, int level, int index)
276
+{
277
+   const struct spa_dict_item *it;
278
+   char key[1024];
279
+   snprintf(key, sizeof(key), "override.%d.%d.config.path", level, index);
280
+   pw_properties_set(conf, key, path);
281
+   spa_dict_for_each(it, &override->dict) {
282
+       snprintf(key, sizeof(key), "override.%d.%d.%s", level, index, it->key);
283
+       pw_properties_set(conf, key, it->value);
284
+   }
285
+}
286
+
287
+static int conf_filter(const struct dirent *entry)
288
+{
289
+   return spa_strendswith(entry->d_name, ".conf");
290
+}
291
+
292
 SPA_EXPORT
293
 int pw_conf_load_conf(const char *prefix, const char *name, struct pw_properties *conf)
294
 {
295
    char path[PATH_MAX];
296
+   char fname[PATH_MAX + 256];
297
+   int i, res, level = 0;
298
+   struct pw_properties *override = NULL;
299
+   const char *dname;
300
 
301
    if (name == NULL) {
302
        pw_log_debug("%p: config name must not be NULL", conf);
303
@@ -355,8 +458,45 @@
304
        pw_log_debug("%p: can't load config '%s': %m", conf, path);
305
        return -ENOENT;
306
    }
307
+   pw_properties_set(conf, "config.prefix", prefix);
308
+   pw_properties_set(conf, "config.name", name);
309
+   pw_properties_set(conf, "config.path", path);
310
 
311
-   return conf_load(path, conf);
312
+   if ((res = conf_load(path, conf)) < 0)
313
+       return res;
314
+
315
+   pw_properties_setf(conf, "config.name.d", "%s.d", name);
316
+   dname = pw_properties_get(conf, "config.name.d");
317
+
318
+   while (true) {
319
+       struct dirent **entries = NULL;
320
+       int n;
321
+
322
+       if (get_config_dir(path, sizeof(path), prefix, dname, &level) <= 0)
323
+           break;
324
+
325
+       n = scandir(path, &entries, conf_filter, alphasort);
326
+       if (n == 0)
327
+           continue;
328
+       if (n < 0) {
329
+           pw_log_warn("scandir %s failed: %m", path);
330
+           continue;
331
+       }
332
+       if (override == NULL &&
333
+           (override = pw_properties_new(NULL, NULL)) == NULL)
334
+           return -errno;
335
+
336
+       for (i = 0; i < n; i++) {
337
+           snprintf(fname, sizeof(fname), "%s/%s", path, entries[i]->d_name);
338
+           if (conf_load(fname, override) >= 0)
339
+               add_override(conf, override, fname, level, i);
340
+           pw_properties_clear(override);
341
+           free(entries[i]);
342
+       }
343
+       free(entries);
344
+   }
345
+   pw_properties_free(override);
346
+   return 0;
347
 }
348
 
349
 SPA_EXPORT
350
@@ -373,21 +513,28 @@
351
        pw_log_debug("%p: can't load config '%s': %m", conf, path);
352
        return -ENOENT;
353
    }
354
-
355
    return conf_load(path, conf);
356
 }
357
 
358
+struct data {
359
+   struct pw_context *context;
360
+   struct pw_properties *props;
361
+   int count;
362
+};
363
+
364
 /* context.spa-libs = {
365
  *  <factory-name regex> = <library-name>
366
  * }
367
  */
368
-static int parse_spa_libs(struct pw_context *context, char *str)
369
+static int parse_spa_libs(void *user_data, const char *location,
370
+       const char *section, const char *str, size_t len)
371
 {
372
+   struct data *d = user_data;
373
+   struct pw_context *context = d->context;
374
    struct spa_json it[2];
375
    char key[512], value[512];
376
-   int count = 0;
377
 
378
-   spa_json_init(&it[0], str, strlen(str));
379
+   spa_json_init(&it[0], str, len);
380
    if (spa_json_enter_object(&it[0], &it[1]) < 0) {
381
        pw_log_error("config file error: context.spa-libs is not an object");
382
        return -EINVAL;
383
@@ -396,10 +543,10 @@
384
    while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
385
        if (spa_json_get_string(&it[1], value, sizeof(value)) > 0) {
386
            pw_context_add_spa_lib(context, key, value);
387
-           count++;
388
+           d->count++;
389
        }
390
    }
391
-   return count;
392
+   return 0;
393
 }
394
 
395
 static int load_module(struct pw_context *context, const char *key, const char *args, const char *flags)
396
@@ -430,16 +577,21 @@
397
  *   }
398
  * ]
399
  */
400
-static int parse_modules(struct pw_context *context, char *str)
401
+static int parse_modules(void *user_data, const char *location,
402
+       const char *section, const char *str, size_t len)
403
 {
404
+   struct data *d = user_data;
405
+   struct pw_context *context = d->context;
406
    struct spa_json it[3];
407
-   char key[512];
408
-   int res = 0, count = 0;
409
+   char key[512], *s;
410
+   int res = 0;
411
 
412
-   spa_json_init(&it[0], str, strlen(str));
413
+   s = strndup(str, len);
414
+   spa_json_init(&it[0], s, len);
415
    if (spa_json_enter_array(&it[0], &it[1]) < 0) {
416
        pw_log_error("config file error: context.modules is not an array");
417
-       return -EINVAL;
418
+       res = -EINVAL;
419
+       goto exit;
420
    }
421
 
422
    while (spa_json_enter_object(&it[1], &it[2]) > 0) {
423
@@ -474,8 +626,10 @@
424
        if (res < 0)
425
            break;
426
 
427
-       res = ++count;
428
+       d->count++;
429
    }
430
+exit:
431
+   free(s);
432
    return res;
433
 }
434
 
435
@@ -514,16 +668,21 @@
436
  *   }
437
  * ]
438
  */
439
-static int parse_objects(struct pw_context *context, char *str)
440
+static int parse_objects(void *user_data, const char *location,
441
+       const char *section, const char *str, size_t len)
442
 {
443
+   struct data *d = user_data;
444
+   struct pw_context *context = d->context;
445
    struct spa_json it[3];
446
-   char key[512];
447
-   int res = 0, count = 0;
448
+   char key[512], *s;
449
+   int res = 0;
450
 
451
-   spa_json_init(&it[0], str, strlen(str));
452
+   s = strndup(str, len);
453
+   spa_json_init(&it[0], s, len);
454
    if (spa_json_enter_array(&it[0], &it[1]) < 0) {
455
        pw_log_error("config file error: context.objects is not an array");
456
-       return -EINVAL;
457
+       res = -EINVAL;
458
+       goto exit;
459
    }
460
 
461
    while (spa_json_enter_object(&it[1], &it[2]) > 0) {
462
@@ -558,8 +717,10 @@
463
 
464
        if (res < 0)
465
            break;
466
-       res = ++count;
467
+       d->count++;
468
    }
469
+exit:
470
+   free(s);
471
    return res;
472
 }
473
 
474
@@ -601,16 +762,21 @@
475
  *   }
476
  * ]
477
  */
478
-static int parse_exec(struct pw_context *context, char *str)
479
+static int parse_exec(void *user_data, const char *location,
480
+       const char *section, const char *str, size_t len)
481
 {
482
+   struct data *d = user_data;
483
+   struct pw_context *context = d->context;
484
    struct spa_json it[3];
485
-   char key[512];
486
-   int res = 0, count = 0;
487
+   char key[512], *s;
488
+   int res = 0;
489
 
490
-   spa_json_init(&it[0], str, strlen(str));
491
+   s = strndup(str, len);
492
+   spa_json_init(&it[0], s, len);
493
    if (spa_json_enter_array(&it[0], &it[1]) < 0) {
494
        pw_log_error("config file error: context.exec is not an array");
495
-       return -EINVAL;
496
+       res = -EINVAL;
497
+       goto exit;
498
    }
499
 
500
    while (spa_json_enter_object(&it[1], &it[2]) > 0) {
501
@@ -637,36 +803,82 @@
502
        if (res < 0)
503
            break;
504
 
505
-       res = ++count;
506
+       d->count++;
507
    }
508
+exit:
509
+   free(s);
510
    return res;
511
 }
512
 
513
 SPA_EXPORT
514
-int pw_context_parse_conf_section(struct pw_context *context,
515
-       struct pw_properties *conf, const char *section)
516
+int pw_context_conf_section_for_each(struct pw_context *context, const char *section,
517
+       int (*callback) (void *data, const char *location, const char *section,
518
+           const char *str, size_t len),
519
+       void *data)
520
 {
521
-   const char *str;
522
-   char *s;
523
+   struct pw_properties *conf = context->conf;
524
+   const char *path = NULL;
525
+   const struct spa_dict_item *it;
526
    int res;
527
 
528
-   if ((str = pw_properties_get(conf, section)) == NULL)
529
-       return 0;
530
+   spa_dict_for_each(it, &conf->dict) {
531
+       if (spa_strendswith(it->key, "config.path")) {
532
+           path = it->value;
533
+           continue;
534
+
535
+       } else if (spa_streq(it->key, section)) {
536
+           pw_log_info("handle config '%s' section '%s'", path, section);
537
+       } else if (spa_strstartswith(it->key, "override.") &&
538
+           spa_strendswith(it->key, section)) {
539
+           pw_log_info("handle override '%s' section '%s'", path, section);
540
+       } else
541
+           continue;
542
+
543
+       res = callback(data, path, section, it->value, strlen(it->value));
544
+       if (res != 0)
545
+           break;
546
+   }
547
+   return res;
548
+}
549
 
550
-   s = strdup(str);
551
+SPA_EXPORT
552
+int pw_context_parse_conf_section(struct pw_context *context,
553
+       struct pw_properties *conf, const char *section)
554
+{
555
+   struct data data = { .context = context };
556
 
557
    if (spa_streq(section, "context.spa-libs"))
558
-       res = parse_spa_libs(context, s);
559
+       pw_context_conf_section_for_each(context, section,
560
+               parse_spa_libs, &data);
561
    else if (spa_streq(section, "context.modules"))
562
-       res = parse_modules(context, s);
563
+       pw_context_conf_section_for_each(context, section,
564
+               parse_modules, &data);
565
    else if (spa_streq(section, "context.objects"))
566
-       res = parse_objects(context, s);
567
+       pw_context_conf_section_for_each(context, section,
568
+               parse_objects, &data);
569
    else if (spa_streq(section, "context.exec"))
570
-       res = parse_exec(context, s);
571
+       pw_context_conf_section_for_each(context, section,
572
+               parse_exec, &data);
573
    else
574
-       res = -EINVAL;
575
+       data.count = -EINVAL;
576
 
577
-   free(s);
578
+   return data.count;
579
+}
580
 
581
-   return res;
582
+static int update_props(void *user_data, const char *location, const char *key,
583
+           const char *val, size_t len)
584
+{
585
+   struct data *data = user_data;
586
+   data->count += pw_properties_update_string(data->props, val, len);
587
+   return 0;
588
+}
589
+
590
+SPA_EXPORT
591
+int pw_context_conf_update_props(struct pw_context *context,
592
+       const char *section, struct pw_properties *props)
593
+{
594
+   struct data data = { .context = context, .props = props };
595
+   pw_context_conf_section_for_each(context, section,
596
+               update_props, &data);
597
+   return data.count;
598
 }
599
pipewire-0.3.44.tar.gz/src/pipewire/conf.h -> pipewire-0.3.45.tar.gz/src/pipewire/conf.h Changed
10
 
1
@@ -37,8 +37,6 @@
2
 int pw_conf_load_state(const char *prefix, const char *name, struct pw_properties *conf);
3
 int pw_conf_save_state(const char *prefix, const char *name, const struct pw_properties *conf);
4
 
5
-int pw_context_parse_conf_section(struct pw_context *context,
6
-       struct pw_properties *conf, const char *section);
7
 
8
 /**
9
  * \}
10
pipewire-0.3.44.tar.gz/src/pipewire/context.c -> pipewire-0.3.45.tar.gz/src/pipewire/context.c Changed
86
 
1
@@ -273,10 +273,8 @@
2
    n_support = pw_get_support(this->support, SPA_N_ELEMENTS(this->support) - 6);
3
    cpu = spa_support_find(this->support, n_support, SPA_TYPE_INTERFACE_CPU);
4
 
5
-   if ((str = pw_properties_get(conf, "context.properties")) != NULL) {
6
-       pw_properties_update_string(properties, str, strlen(str));
7
-       pw_log_info("%p: parsed context.properties section", this);
8
-   }
9
+   res = pw_context_conf_update_props(this, "context.properties", properties);
10
+   pw_log_info("%p: parsed %d context.properties items", this, res);
11
 
12
    if ((str = getenv("PIPEWIRE_CORE"))) {
13
        pw_log_info("using core.name from environment: %s", str);
14
@@ -1066,10 +1064,11 @@
15
 int pw_context_recalc_graph(struct pw_context *context, const char *reason)
16
 {
17
    struct impl *impl = SPA_CONTAINER_OF(context, struct impl, this);
18
+   struct settings *settings = &context->settings;
19
    struct pw_impl_node *n, *s, *target, *fallback;
20
    uint32_t max_quantum, min_quantum, def_quantum, lim_quantum, rate_quantum;
21
    uint32_t *rates, n_rates, def_rate;
22
-   bool freewheel = false, force_rate;
23
+   bool freewheel = false, global_force_rate, force_rate, global_force_quantum;
24
 
25
    pw_log_info("%p: busy:%d reason:%s", context, impl->recalc, reason);
26
 
27
@@ -1082,7 +1081,10 @@
28
    impl->recalc = true;
29
 
30
    get_quantums(context, &def_quantum, &min_quantum, &max_quantum, &lim_quantum, &rate_quantum);
31
-   rates = get_rates(context, &def_rate, &n_rates, &force_rate);
32
+   rates = get_rates(context, &def_rate, &n_rates, &global_force_rate);
33
+
34
+   global_force_quantum = rate_quantum == 0;
35
+   force_rate = global_force_rate;
36
 
37
    /* start from all drivers and group all nodes that are linked
38
     * to it. Some nodes are not (yet) linked to anything and they
39
@@ -1164,6 +1166,7 @@
40
        struct spa_fraction max_latency = SPA_FRACTION(0, 0);
41
        struct spa_fraction rate = SPA_FRACTION(0, 0);
42
        uint32_t quantum, target_rate, current_rate;
43
+       uint64_t quantum_stamp = 0, rate_stamp = 0;
44
 
45
        if (!n->driving || n->exported)
46
            continue;
47
@@ -1175,6 +1178,20 @@
48
                lock_quantum |= s->lock_quantum;
49
                lock_rate |= s->lock_rate;
50
            }
51
+           if (!global_force_quantum && s->force_quantum > 0 &&
52
+               s->stamp > quantum_stamp) {
53
+               def_quantum = min_quantum = max_quantum = s->force_quantum;
54
+               rate_quantum = 0;
55
+               quantum_stamp = s->stamp;
56
+           }
57
+           if (!global_force_rate && s->force_rate > 0 &&
58
+               s->stamp > rate_stamp) {
59
+               def_rate = s->force_rate;
60
+               force_rate = true;
61
+               n_rates = 1;
62
+               rates = &s->force_rate;
63
+               rate_stamp = s->stamp;
64
+           }
65
 
66
            /* smallest latencies */
67
            if (latency.denom == 0 ||
68
@@ -1221,7 +1238,7 @@
69
                    target_rate);
70
 
71
            if (force_rate) {
72
-               if (context->settings.clock_rate_update_mode == CLOCK_RATE_UPDATE_MODE_HARD)
73
+               if (settings->clock_rate_update_mode == CLOCK_RATE_UPDATE_MODE_HARD)
74
                    suspend_driver(context, n);
75
            } else {
76
                if (n->info.state >= PW_NODE_STATE_IDLE)
77
@@ -1253,7 +1270,7 @@
78
        quantum = SPA_CLAMP(quantum, min_quantum, max_quantum);
79
        quantum = SPA_MIN(quantum, lim_quantum);
80
 
81
-       if (context->settings.clock_power_of_two_quantum)
82
+       if (settings->clock_power_of_two_quantum)
83
            quantum = flp2(quantum);
84
 
85
        if (running && quantum != n->current_quantum && !lock_quantum) {
86
pipewire-0.3.44.tar.gz/src/pipewire/context.h -> pipewire-0.3.45.tar.gz/src/pipewire/context.h Changed
24
 
1
@@ -108,8 +108,21 @@
2
 /** Update the context properties */
3
 int pw_context_update_properties(struct pw_context *context, const struct spa_dict *dict);
4
 
5
-/** Get a config section for this context. Since 0.3.22 */
6
+/** Get a config section for this context. Since 0.3.22, deprecated,
7
+ * use pw_context_conf_section_for_each(). */
8
 const char *pw_context_get_conf_section(struct pw_context *context, const char *section);
9
+/** Parse a standard config section for this context. Since 0.3.22 */
10
+int pw_context_parse_conf_section(struct pw_context *context,
11
+       struct pw_properties *conf, const char *section);
12
+
13
+/** update properties from a section into props. Since 0.3.45 */
14
+int pw_context_conf_update_props(struct pw_context *context, const char *section,
15
+       struct pw_properties *props);
16
+/** emit callback for all config sections. Since 0.3.45 */
17
+int pw_context_conf_section_for_each(struct pw_context *context, const char *section,
18
+       int (*callback) (void *data, const char *location, const char *section,
19
+           const char *str, size_t len),
20
+       void *data);
21
 
22
 /** Get the context support objects */
23
 const struct spa_support *pw_context_get_support(struct pw_context *context, uint32_t *n_support);
24
pipewire-0.3.44.tar.gz/src/pipewire/data-loop.c -> pipewire-0.3.45.tar.gz/src/pipewire/data-loop.c Changed
71
 
1
@@ -90,11 +90,13 @@
2
    return NULL;
3
 }
4
 
5
-static void do_stop(void *data, uint64_t count)
6
+static int do_stop(struct spa_loop *loop, bool async, uint32_t seq,
7
+       const void *data, size_t size, void *user_data)
8
 {
9
-   struct pw_data_loop *this = data;
10
+   struct pw_data_loop *this = user_data;
11
    pw_log_debug("%p: stopping", this);
12
    this->running = false;
13
+   return 0;
14
 }
15
 
16
 static struct pw_data_loop *loop_new(struct pw_loop *loop, const struct spa_dict *props)
17
@@ -122,23 +124,14 @@
18
    }
19
    this->loop = loop;
20
 
21
-   if (props == NULL ||
22
-       (str = spa_dict_lookup(props, "loop.cancel")) == NULL ||
23
-       pw_properties_parse_bool(str) == false) {
24
-       this->event = pw_loop_add_event(this->loop, do_stop, this);
25
-       if (this->event == NULL) {
26
-           res = -errno;
27
-           pw_log_error("%p: can't add event: %m", this);
28
-           goto error_loop_destroy;
29
-       }
30
-   }
31
+   if (props != NULL &&
32
+       (str = spa_dict_lookup(props, "loop.cancel")) != NULL)
33
+       this->cancel = pw_properties_parse_bool(str);
34
+
35
    spa_hook_list_init(&this->listener_list);
36
 
37
    return this;
38
 
39
-error_loop_destroy:
40
-   if (this->created && this->loop)
41
-       pw_loop_destroy(this->loop);
42
 error_free:
43
    free(this);
44
 error_cleanup:
45
@@ -169,8 +162,6 @@
46
 
47
    pw_data_loop_stop(loop);
48
 
49
-   if (loop->event)
50
-       pw_loop_destroy_source(loop->loop, loop->event);
51
    if (loop->created)
52
        pw_loop_destroy(loop->loop);
53
 
54
@@ -232,12 +223,12 @@
55
 {
56
    pw_log_debug("%p stopping", loop);
57
    if (loop->running) {
58
-       if (loop->event) {
59
-           pw_log_debug("%p signal", loop);
60
-           pw_loop_signal_event(loop->loop, loop->event);
61
-       } else {
62
+       if (loop->cancel) {
63
            pw_log_debug("%p cancel", loop);
64
            pthread_cancel(loop->thread);
65
+       } else {
66
+           pw_log_debug("%p signal", loop);
67
+           pw_loop_invoke(loop->loop, do_stop, 1, NULL, 0, false, loop);
68
        }
69
        pw_log_debug("%p join", loop);
70
        pw_thread_utils_join((struct spa_thread*)loop->thread, NULL);
71
pipewire-0.3.44.tar.gz/src/pipewire/filter.c -> pipewire-0.3.45.tar.gz/src/pipewire/filter.c Changed
11
 
1
@@ -1209,8 +1209,7 @@
2
        res = -errno;
3
        goto error_properties;
4
    }
5
-   if ((str = pw_context_get_conf_section(context, "filter.properties")) != NULL)
6
-       pw_properties_update_string(props, str, strlen(str));
7
+   pw_context_conf_update_props(context, "filter.properties", props);
8
 
9
    if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL && extra) {
10
        str = pw_properties_get(extra, PW_KEY_APP_NAME);
11
pipewire-0.3.44.tar.gz/src/pipewire/global.c -> pipewire-0.3.45.tar.gz/src/pipewire/global.c Changed
25
 
1
@@ -36,8 +36,6 @@
2
 PW_LOG_TOPIC_EXTERN(log_global);
3
 #define PW_LOG_TOPIC_DEFAULT log_global
4
 
5
-static uint64_t serial = 0;
6
-
7
 /** \cond */
8
 struct impl {
9
    struct pw_global this;
10
@@ -122,10 +120,11 @@
11
 SPA_EXPORT
12
 uint64_t pw_global_get_serial(struct pw_global *global)
13
 {
14
+   struct pw_context *context = global->context;
15
    if (global->serial == SPA_ID_INVALID)
16
-       global->serial = serial++;
17
-   if ((uint32_t)serial == SPA_ID_INVALID)
18
-       serial++;
19
+       global->serial = context->serial++;
20
+   if ((uint32_t)context->serial == SPA_ID_INVALID)
21
+       context->serial++;
22
    return global->serial;
23
 }
24
 
25
pipewire-0.3.44.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.45.tar.gz/src/pipewire/impl-node.c Changed
67
 
1
@@ -857,6 +857,7 @@
2
    struct pw_context *context = node->context;
3
    const char *str, *recalc_reason = NULL;
4
    struct spa_fraction frac;
5
+   uint32_t value;
6
    bool driver;
7
 
8
    if ((str = pw_properties_get(node->properties, PW_KEY_PRIORITY_DRIVER))) {
9
@@ -935,6 +936,15 @@
10
    }
11
    node->lock_quantum = pw_properties_get_bool(node->properties, PW_KEY_NODE_LOCK_QUANTUM, false);
12
 
13
+   if ((str = pw_properties_get(node->properties, PW_KEY_NODE_FORCE_QUANTUM))) {
14
+       if (spa_atou32(str, &value, 0) &&
15
+           node->force_quantum != value) {
16
+               node->force_quantum = value;
17
+           node->stamp = ++context->stamp;
18
+           recalc_reason = "force quantum changed";
19
+       }
20
+   }
21
+
22
    if ((str = pw_properties_get(node->properties, PW_KEY_NODE_RATE))) {
23
                 if (sscanf(str, "%u/%u", &frac.num, &frac.denom) == 2 && frac.denom != 0) {
24
            if (node->rate.num != frac.num || node->rate.denom != frac.denom) {
25
@@ -948,6 +958,15 @@
26
    }
27
    node->lock_rate = pw_properties_get_bool(node->properties, PW_KEY_NODE_LOCK_RATE, false);
28
 
29
+   if ((str = pw_properties_get(node->properties, PW_KEY_NODE_FORCE_RATE))) {
30
+       if (spa_atou32(str, &value, 0) &&
31
+           node->force_rate != value) {
32
+           node->force_rate = value;
33
+           node->stamp = ++context->stamp;
34
+           recalc_reason = "force rate changed";
35
+       }
36
+   }
37
+
38
    pw_log_debug("%p: driver:%d recalc:%s active:%d", node, node->driver,
39
            recalc_reason, node->active);
40
 
41
@@ -1787,6 +1806,7 @@
42
    struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this);
43
    struct pw_impl_port *port;
44
    struct pw_impl_node *follower;
45
+   struct pw_context *context = node->context;
46
    bool active, had_driver;
47
 
48
    active = node->active;
49
@@ -1836,7 +1856,7 @@
50
    }
51
 
52
    if (active || had_driver)
53
-       pw_context_recalc_graph(node->context,
54
+       pw_context_recalc_graph(context,
55
                "active node destroy");
56
 
57
    pw_log_debug("%p: free", node);
58
@@ -1858,7 +1878,7 @@
59
 
60
    clear_info(node);
61
 
62
-   spa_system_close(node->context->data_system, node->source.fd);
63
+   spa_system_close(context->data_system, node->source.fd);
64
    free(impl);
65
 }
66
 
67
pipewire-0.3.44.tar.gz/src/pipewire/keys.h -> pipewire-0.3.45.tar.gz/src/pipewire/keys.h Changed
16
 
1
@@ -161,10 +161,14 @@
2
                                  *  node as a fraction. Ex: 1024/48000 */
3
 #define PW_KEY_NODE_LOCK_QUANTUM   "node.lock-quantum" /**< don't change quantum when this node
4
                                  *  is active */
5
+#define PW_KEY_NODE_FORCE_QUANTUM  "node.force-quantum"    /**< force a quantum while the node is
6
+                                 *  active */
7
 #define PW_KEY_NODE_RATE       "node.rate"     /**< the requested rate of the graph as
8
                                  *  a fraction. Ex: 1/48000 */
9
 #define PW_KEY_NODE_LOCK_RATE      "node.lock-rate"    /**< don't change rate when this node
10
                                  *  is active */
11
+#define PW_KEY_NODE_FORCE_RATE     "node.force-rate"   /**< force a rate while the node is
12
+                                 *  active */
13
 
14
 #define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect"   /**< don't reconnect this node */
15
 #define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process"   /**< process even when unlinked */
16
pipewire-0.3.44.tar.gz/src/pipewire/log.h -> pipewire-0.3.45.tar.gz/src/pipewire/log.h Changed
13
 
1
@@ -140,6 +140,11 @@
2
 #define pw_log_level_enabled(lev) (pw_log_level >= (lev))
3
 #define pw_log_topic_enabled(lev,t) ((t) && (t)->has_custom_level ? (t)->level >= (lev) : pw_log_level_enabled((lev)))
4
 
5
+#define pw_logtv(lev,topic,fmt,ap)                     \
6
+({                                     \
7
+   if (SPA_UNLIKELY(pw_log_topic_enabled(lev,topic)))          \
8
+       pw_log_logtv(lev,topic,__FILE__,__LINE__,__func__,fmt,ap);  \
9
+})
10
 
11
 #define pw_logt(lev,topic,...)                         \
12
 ({                                     \
13
pipewire-0.3.44.tar.gz/src/pipewire/main-loop.c -> pipewire-0.3.45.tar.gz/src/pipewire/main-loop.c Changed
46
 
1
@@ -29,11 +29,13 @@
2
 PW_LOG_TOPIC_EXTERN(log_main_loop);
3
 #define PW_LOG_TOPIC_DEFAULT log_main_loop
4
 
5
-static void do_stop(void *data, uint64_t count)
6
+static int do_stop(struct spa_loop *loop, bool async, uint32_t seq,
7
+       const void *data, size_t size, void *user_data)
8
 {
9
-   struct pw_main_loop *this = data;
10
+   struct pw_main_loop *this = user_data;
11
    pw_log_debug("%p: do stop", this);
12
    this->running = false;
13
+   return 0;
14
 }
15
 
16
 static struct pw_main_loop *loop_new(struct pw_loop *loop, const struct spa_dict *props)
17
@@ -59,19 +61,10 @@
18
    }
19
    this->loop = loop;
20
 
21
-        this->event = pw_loop_add_event(this->loop, do_stop, this);
22
-   if (this->event == NULL) {
23
-       res = -errno;
24
-       goto error_free_loop;
25
-   }
26
-
27
    spa_hook_list_init(&this->listener_list);
28
 
29
    return this;
30
 
31
-error_free_loop:
32
-   if (this->created && this->loop)
33
-       pw_loop_destroy(this->loop);
34
 error_free:
35
    free(this);
36
 error_cleanup:
37
@@ -132,7 +125,7 @@
38
 int pw_main_loop_quit(struct pw_main_loop *loop)
39
 {
40
    pw_log_debug("%p: quit", loop);
41
-   return pw_loop_signal_event(loop->loop, loop->event);
42
+   return pw_loop_invoke(loop->loop, do_stop, 1, NULL, 0, false, loop);
43
 }
44
 
45
 /** Start a main loop
46
pipewire-0.3.44.tar.gz/src/pipewire/mem.c -> pipewire-0.3.45.tar.gz/src/pipewire/mem.c Changed
19
 
1
@@ -508,6 +508,7 @@
2
    }
3
    unlink(filename);
4
 #endif
5
+   pw_log_debug("%p: new fd:%d", pool, b->this.fd);
6
 
7
    if (ftruncate(b->this.fd, size) < 0) {
8
        res = -errno;
9
@@ -535,7 +536,8 @@
10
 
11
    b->this.id = pw_map_insert_new(&impl->map, b);
12
    spa_list_append(&impl->blocks, &b->link);
13
-   pw_log_debug("%p: block:%p id:%d type:%u size:%zu", pool, &b->this, b->this.id, type, size);
14
+   pw_log_debug("%p: block:%p id:%d type:%u size:%zu", pool,
15
+           &b->this, b->this.id, type, size);
16
 
17
    if (!SPA_FLAG_IS_SET(flags, PW_MEMBLOCK_FLAG_DONT_NOTIFY))
18
        pw_mempool_emit_added(impl, &b->this);
19
pipewire-0.3.44.tar.gz/src/pipewire/private.h -> pipewire-0.3.45.tar.gz/src/pipewire/private.h Changed
52
 
1
@@ -360,7 +360,11 @@
2
    buffer[1023] = '\0';
3
    pw_log_debug("resource %p: id:%d seq:%d res:%d (%s) msg:\"%s\"",
4
            resource, id, seq, res, spa_strerror(res), buffer);
5
-   pw_core_resource_error(resource, id, seq, res, buffer);
6
+   if (resource)
7
+       pw_core_resource_error(resource, id, seq, res, buffer);
8
+   else
9
+       pw_log_error("id:%d seq:%d res:%d (%s) msg:\"%s\"",
10
+               id, seq, res, spa_strerror(res), buffer);
11
 }
12
 
13
 static inline SPA_PRINTF_FUNC(5,6) void
14
@@ -424,6 +428,8 @@
15
 
16
    struct pw_mempool *pool;        /**< global memory pool */
17
 
18
+   uint64_t stamp;
19
+   uint64_t serial;
20
    struct pw_map globals;          /**< map of globals */
21
 
22
    struct spa_list core_impl_list;     /**< list of core_imp */
23
@@ -472,9 +478,9 @@
24
    struct pw_loop *loop;
25
 
26
    struct spa_hook_list listener_list;
27
-   struct spa_source *event;
28
 
29
    pthread_t thread;
30
+   unsigned int cancel:1;
31
    unsigned int created:1;
32
    unsigned int running:1;
33
 };
34
@@ -486,7 +492,6 @@
35
         struct pw_loop *loop;
36
 
37
    struct spa_hook_list listener_list;
38
-   struct spa_source *event;
39
 
40
    unsigned int created:1;
41
    unsigned int running:1;
42
@@ -713,6 +718,9 @@
43
    struct spa_fraction latency;        /**< requested latency */
44
    struct spa_fraction max_latency;    /**< maximum latency */
45
    struct spa_fraction rate;       /**< requested rate */
46
+   uint32_t force_quantum;         /**< forced quantum */
47
+   uint32_t force_rate;            /**< forced rate */
48
+   uint32_t stamp;             /**< stamp of last update */
49
    struct spa_source source;       /**< source to remotely trigger this node */
50
    struct pw_memblock *activation;
51
    struct {
52
pipewire-0.3.44.tar.gz/src/pipewire/resource.c -> pipewire-0.3.45.tar.gz/src/pipewire/resource.c Changed
76
 
1
@@ -31,8 +31,8 @@
2
 
3
 #include <spa/debug/types.h>
4
 
5
-PW_LOG_TOPIC_EXTERN(log_device);
6
-#define PW_LOG_TOPIC_DEFAULT log_device
7
+PW_LOG_TOPIC_EXTERN(log_resource);
8
+#define PW_LOG_TOPIC_DEFAULT log_resource
9
 
10
 /** \cond */
11
 struct impl {
12
@@ -228,10 +228,16 @@
13
 static void SPA_PRINTF_FUNC(4, 0)
14
 pw_resource_errorv_id(struct pw_resource *resource, uint32_t id, int res, const char *error, va_list ap)
15
 {
16
-   struct pw_impl_client *client = resource->client;
17
-   if (client->core_resource != NULL)
18
-       pw_core_resource_errorv(client->core_resource,
19
-               id, client->recv_seq, res, error, ap);
20
+   struct pw_impl_client *client;
21
+
22
+   if (resource) {
23
+       client = resource->client;
24
+       if (client->core_resource != NULL)
25
+           pw_core_resource_errorv(client->core_resource,
26
+                   id, client->recv_seq, res, error, ap);
27
+   } else {
28
+       pw_logtv(SPA_LOG_LEVEL_ERROR, PW_LOG_TOPIC_DEFAULT, error, ap);
29
+   }
30
 }
31
 
32
 SPA_EXPORT
33
@@ -239,7 +245,10 @@
34
 {
35
    va_list ap;
36
    va_start(ap, error);
37
-   pw_resource_errorv_id(resource, resource->id, res, error, ap);
38
+   if (resource)
39
+       pw_resource_errorv_id(resource, resource->id, res, error, ap);
40
+   else
41
+       pw_logtv(SPA_LOG_LEVEL_ERROR, PW_LOG_TOPIC_DEFAULT, error, ap);
42
    va_end(ap);
43
 }
44
 
45
@@ -248,17 +257,25 @@
46
 {
47
    va_list ap;
48
    va_start(ap, error);
49
-   pw_resource_errorv_id(resource, id, res, error, ap);
50
+   if (resource)
51
+       pw_resource_errorv_id(resource, id, res, error, ap);
52
+   else
53
+       pw_logtv(SPA_LOG_LEVEL_ERROR, PW_LOG_TOPIC_DEFAULT, error, ap);
54
    va_end(ap);
55
 }
56
 
57
 SPA_EXPORT
58
 void pw_resource_error(struct pw_resource *resource, int res, const char *error)
59
 {
60
-   struct pw_impl_client *client = resource->client;
61
-   if (client->core_resource != NULL)
62
-       pw_core_resource_error(client->core_resource,
63
-               resource->id, client->recv_seq, res, error);
64
+   struct pw_impl_client *client;
65
+   if (resource) {
66
+       client = resource->client;
67
+       if (client->core_resource != NULL)
68
+           pw_core_resource_error(client->core_resource,
69
+                   resource->id, client->recv_seq, res, error);
70
+   } else {
71
+       pw_log_error("%s: %s", error, spa_strerror(res));
72
+   }
73
 }
74
 
75
 SPA_EXPORT
76
pipewire-0.3.44.tar.gz/src/pipewire/stream.c -> pipewire-0.3.45.tar.gz/src/pipewire/stream.c Changed
11
 
1
@@ -1342,8 +1342,7 @@
2
        res = -errno;
3
        goto error_properties;
4
    }
5
-   if ((str = pw_context_get_conf_section(context, "stream.properties")) != NULL)
6
-       pw_properties_update_string(props, str, strlen(str));
7
+   pw_context_conf_update_props(context, "stream.properties", props);
8
 
9
    if (pw_properties_get(props, PW_KEY_STREAM_IS_LIVE) == NULL)
10
        pw_properties_set(props, PW_KEY_STREAM_IS_LIVE, "true");
11
pipewire-0.3.44.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.45.tar.gz/src/tools/pw-cli.c Changed
88
 
1
@@ -36,6 +36,10 @@
2
 #include <readline/readline.h>
3
 #include <readline/history.h>
4
 
5
+#if !defined(FNM_EXTMATCH)
6
+#define FNM_EXTMATCH 0
7
+#endif
8
+
9
 #define spa_debug(...) fprintf(stdout,__VA_ARGS__);fputc('\n', stdout)
10
 
11
 #include <spa/utils/result.h>
12
@@ -211,6 +215,7 @@
13
 static bool do_set_param(struct data *data, const char *cmd, char *args, char **error);
14
 static bool do_permissions(struct data *data, const char *cmd, char *args, char **error);
15
 static bool do_get_permissions(struct data *data, const char *cmd, char *args, char **error);
16
+static bool do_send_command(struct data *data, const char *cmd, char *args, char **error);
17
 static bool do_dump(struct data *data, const char *cmd, char *args, char **error);
18
 static bool do_quit(struct data *data, const char *cmd, char *args, char **error);
19
 
20
@@ -235,6 +240,7 @@
21
    { "set-param", "s", "Set param of an object <object-id> <param-id> <param-json>", do_set_param },
22
    { "permissions", "sp", "Set permissions for a client <client-id> <object> <permission>", do_permissions },
23
    { "get-permissions", "gp", "Get permissions of a client <client-id>", do_get_permissions },
24
+   { "send-command", "c", "Send a command <object-id>", do_send_command },
25
    { "dump", "D", "Dump objects in ways that are cleaner for humans to understand "
26
         "[short|deep|resolve|notype] [-sdrt] [all|"DUMP_NAMES"|<id>]", do_dump },
27
    { "quit", "q", "Quit", do_quit },
28
@@ -1772,6 +1778,59 @@
29
    return true;
30
 }
31
 
32
+static bool do_send_command(struct data *data, const char *cmd, char *args, char **error)
33
+{
34
+   struct remote_data *rd = data->current;
35
+   char *a[3];
36
+   int res, n;
37
+   struct global *global;
38
+   uint8_t buffer[1024];
39
+   struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
40
+   const struct spa_type_info *ti;
41
+   struct spa_pod *pod;
42
+
43
+   n = pw_split_ip(args, WHITESPACE, 3, a);
44
+   if (n < 3) {
45
+       *error = spa_aprintf("%s <object-id> <command-id> <command-json>", cmd);
46
+       return false;
47
+   }
48
+
49
+   global = find_global(rd, a[0]);
50
+   if (global == NULL) {
51
+       *error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
52
+       return false;
53
+   }
54
+   if (global->proxy == NULL) {
55
+       if (!bind_global(rd, global, error))
56
+           return false;
57
+   }
58
+
59
+   if (spa_streq(global->type, PW_TYPE_INTERFACE_Node)) {
60
+       ti = spa_debug_type_find_short(spa_type_node_command_id, a[1]);
61
+   } else {
62
+       *error = spa_aprintf("send-command not implemented on object %d type:%s",
63
+               atoi(a[0]), global->type);
64
+       return false;
65
+   }
66
+
67
+   if (ti == NULL) {
68
+       *error = spa_aprintf("%s: unknown node command type: %s", cmd, a[1]);
69
+       return false;
70
+   }
71
+   if ((res = spa_json_to_pod(&b, 0, ti, a[2], strlen(a[2]))) < 0) {
72
+       *error = spa_aprintf("%s: can't make pod: %s", cmd, spa_strerror(res));
73
+       return false;
74
+   }
75
+   if ((pod = spa_pod_builder_deref(&b, 0)) == NULL) {
76
+       *error = spa_aprintf("%s: can't make pod", cmd);
77
+       return false;
78
+   }
79
+   spa_debug_pod(0, NULL, pod);
80
+
81
+   pw_node_send_command((struct pw_node*)global->proxy, (struct spa_command*)pod);
82
+   return true;
83
+}
84
+
85
 static const char *
86
 pw_interface_short(const char *type)
87
 {
88
pipewire-0.3.44.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.45.tar.gz/src/tools/pw-dump.c Changed
12
 
1
@@ -32,6 +32,10 @@
2
 #include <math.h>
3
 #include <fnmatch.h>
4
 
5
+#if !defined(FNM_EXTMATCH)
6
+#define FNM_EXTMATCH 0
7
+#endif
8
+
9
 #include <spa/utils/result.h>
10
 #include <spa/utils/string.h>
11
 #include <spa/pod/iter.h>
12
pipewire-0.3.44.tar.gz/test/test-config.c -> pipewire-0.3.45.tar.gz/test/test-config.c Changed
17
 
1
@@ -46,6 +46,7 @@
2
    pwtest_str_eq(pw_properties_get(props, "data"), "x");
3
    pw_properties_free(props);
4
 
5
+#if 0
6
    /* Load with non-NULL abs prefix and abs path */
7
    props = pw_properties_new("ignore", "me", NULL);
8
    r = pw_conf_load_conf("/dummy", path, props);
9
@@ -59,6 +60,7 @@
10
    pwtest_neg_errno_ok(r);
11
    pwtest_str_eq(pw_properties_get(props, "data"), "x");
12
    pw_properties_free(props);
13
+#endif
14
 
15
    /* Load with non-NULL abs prefix and relative path */
16
    basename = rindex(path, '/'); /* basename(3) and dirname(3) are terrible */
17
Refresh

No build results available

Refresh

No rpmlint results available

Request History
Bjørn Lie's avatar

zaitor created request about 3 years ago

New upstream release


Bjørn Lie's avatar

zaitor accepted request about 3 years ago

Xin