Changes of Revision 3

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
201
 
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
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
201
 
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
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
201
 
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
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
201
 
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
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
201
 
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
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