Changes of Revision 19

pipewire-aptx.changes Changed
x
 
1
@@ -1,4 +1,9 @@
2
 -------------------------------------------------------------------
3
+Fri Dec 16 18:14:30 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.62
6
+
7
+-------------------------------------------------------------------
8
 Sat Dec  3 00:09:52 UTC 2022 - Bjørn Lie <zaitor@opensuse.org>
9
 
10
 - Update to version 0.3.61
11
pipewire-aptx.spec Changed
10
 
1
@@ -7,7 +7,7 @@
2
 %define soversion 0_2
3
 
4
 Name:           pipewire-aptx
5
-Version:        0.3.61
6
+Version:        0.3.62
7
 Release:        0
8
 Summary:        PipeWire Bluetooth aptX codec plugin
9
 License:        MIT
10
pipewire-0.3.61.tar.gz/NEWS -> pipewire-0.3.62.tar.gz/NEWS Changed
92
 
1
@@ -1,3 +1,80 @@
2
+# PipeWire 0.3.62 (2022-12-09)
3
+
4
+This is a bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+  - A regression in screensharing was fixed. It was caused by a race when
9
+    activating links and driver nodes.
10
+  - Video transform metadata was added so that cameras and screen sharing
11
+    can report the video orientation and transformations.
12
+  - Support for the PulseAudio module-gsettings was added to make paprefs
13
+    work.
14
+  - Support for bluetooth offloading was added. This allows for the bluetooth
15
+    reception, decoding and playback to happen completely in hardware.
16
+    This also requires some support in WirePlumber.
17
+  - Many bugfixes and improvements.
18
+
19
+
20
+## PipeWire
21
+  - More work on stopping nodes in a more controlled way.
22
+  - Fix a race in starting nodes and drivers. In some cases the driver
23
+    node would already be started while the link to the peer node was not
24
+    ready yet. This caused regressions in screen sharing. The driver is
25
+    now only started after all the followers and links completed.
26
+  - Fix a case where a slow capture stream would not recycle buffers
27
+    anymore and stall. (#2874)
28
+  - Fix a subtle bug in pw_loop_invoke that could cause callbacks to be
29
+    delayed and cause crashes in some cases.
30
+  - Fix a case where IPC was done from the data-thread and could cause
31
+    crashes.
32
+
33
+## Tools
34
+  - Silence some expected errors in the pw-top output.
35
+
36
+## modules
37
+  - The filter-chain has seen some optimizations in the copy plugin and
38
+    the convolver.
39
+  - The zeroconf plugin will now only unpublish services from the server
40
+    that was removed.
41
+  - Fix a potential crash when stopping pw-loopback.
42
+  - Some harmless errors were turned into info messages.
43
+  - Fix some cases where pw_stream methods were called from the data-thread
44
+    that could cause segfaults. (#2633)
45
+
46
+## SPA
47
+  - There is now a video transform metadata that indicates how a video
48
+    frame was transformed (rotated/flipped). libcamera and the GStreamer
49
+    elements now have support for this metadata.
50
+  - The SPA volume plugin is now disabled from the default build.
51
+  - Handle missing control info in libcamera.
52
+  - Handle errors from loop better, don't call the callbacks on errors.
53
+  - Somewhat improve performance in some audioconvert AVX2 code for format
54
+    conversion.
55
+  - Fix PortConfig and EnumPortConfig params in audioconvert and
56
+    audioadapter to reflect what is actually going on instead of using
57
+    hardcoded values.
58
+  - Pass ignore-dB property correctly in all cases.
59
+  - Probing is now done in 48KHz again. (#2857)
60
+
61
+## Pulse-server
62
+  - IPv4 addresses are now added first to the list and exposed first with
63
+    zeroconf discover.
64
+  - module-gsettings was added to make paprefs work.
65
+  - The pulse.idle.timeout option was disabled by default and only enabled
66
+    for selected apps (speech-dispatcher) because it caused some problems
67
+    for other apps. (#2880)
68
+
69
+## JACK
70
+  - Only process valid ports. Could fix some crashes. (#2863)
71
+
72
+## Bluetooth
73
+  - Support was added for offloading bluetooth handling. Some hardware can
74
+    receive, decode and play the bluetooth audio directly in hardware.
75
+
76
+
77
+Older versions:
78
+
79
 # PipeWire 0.3.61 (2022-11-24)
80
 
81
 This is a bugfix release that is API and ABI compatible with previous
82
@@ -65,9 +142,6 @@
83
   - Add option to set node.passive on jack clients. Make some quirks
84
     for qsynth to make it suspend and fade out better.
85
 
86
-
87
-Older versions:
88
-
89
 # PipeWire 0.3.60 (2022-11-10)
90
 
91
 This is a bugfix release that is API and ABI compatible with previous
92
pipewire-0.3.61.tar.gz/meson.build -> pipewire-0.3.62.tar.gz/meson.build Changed
18
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', 'c' ,
3
-  version : '0.3.61',
4
+  version : '0.3.62',
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
@@ -301,6 +301,9 @@
9
 flatpak_support = glib2_dep.found()
10
 cdata.set('HAVE_GLIB2', flatpak_support)
11
 
12
+gio_dep = dependency('gio-2.0', version : '>= 2.26.0', required : get_option('gsettings'))
13
+summary({'GIO (GSettings)': gio_dep.found()}, bool_yn: true, section: 'Misc dependencies')
14
+
15
 gst_option = get_option('gstreamer')
16
 gst_deps_def = {
17
   'glib-2.0': {'version': '>=2.32.0'},
18
pipewire-0.3.61.tar.gz/meson_options.txt -> pipewire-0.3.62.tar.gz/meson_options.txt Changed
21
 
1
@@ -177,9 +177,9 @@
2
        type: 'feature',
3
        value: 'enabled')
4
 option('volume',
5
-       description: 'Enable volume spa plugin integration',
6
+       description: 'Build the legacy volume spa plugin',
7
        type: 'feature',
8
-       value: 'enabled')
9
+       value: 'disabled')
10
 option('vulkan',
11
        description: 'Enable vulkan spa plugin integration',
12
        type: 'feature',
13
@@ -269,3 +269,7 @@
14
        description: 'Enable code that depends on libreadline',
15
        type: 'feature',
16
        value: 'auto')
17
+option('gsettings',
18
+       description: 'Enable code that depends on gsettings',
19
+       type: 'feature',
20
+       value: 'auto')
21
pipewire-0.3.61.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.62.tar.gz/pipewire-jack/src/pipewire-jack.c Changed
19
 
1
@@ -1144,6 +1144,8 @@
2
                 if (pw_map_item_is_free(item))
3
            continue;
4
        p = item->data;
5
+       if (!p->valid)
6
+           continue;
7
        spa_list_for_each(mix, &p->mix, port_link) {
8
            if (SPA_LIKELY(mix->io != NULL))
9
                mix->io->status = SPA_STATUS_NEED_DATA;
10
@@ -1153,6 +1155,8 @@
11
                 if (pw_map_item_is_free(item))
12
            continue;
13
        p = item->data;
14
+       if (!p->valid)
15
+           continue;
16
        prepare_output(p, frames);
17
        p->io.status = SPA_STATUS_NEED_DATA;
18
    }
19
pipewire-0.3.61.tar.gz/spa/include/spa/buffer/meta.h -> pipewire-0.3.62.tar.gz/spa/include/spa/buffer/meta.h Changed
54
 
1
@@ -39,16 +39,17 @@
2
 
3
 enum spa_meta_type {
4
    SPA_META_Invalid,
5
-   SPA_META_Header,    /**< struct spa_meta_header */
6
-   SPA_META_VideoCrop, /**< struct spa_meta_region with cropping data */
7
-   SPA_META_VideoDamage,   /**< array of struct spa_meta_region with damage, where an invalid entry or end-of-array marks the end. */
8
-   SPA_META_Bitmap,    /**< struct spa_meta_bitmap */
9
-   SPA_META_Cursor,    /**< struct spa_meta_cursor */
10
-   SPA_META_Control,   /**< metadata contains a spa_meta_control
11
-                 *  associated with the data */
12
-   SPA_META_Busy,      /**< don't write to buffer when count > 0 */
13
-
14
-   _SPA_META_LAST,     /**< not part of ABI/API */
15
+   SPA_META_Header,        /**< struct spa_meta_header */
16
+   SPA_META_VideoCrop,     /**< struct spa_meta_region with cropping data */
17
+   SPA_META_VideoDamage,       /**< array of struct spa_meta_region with damage, where an invalid entry or end-of-array marks the end. */
18
+   SPA_META_Bitmap,        /**< struct spa_meta_bitmap */
19
+   SPA_META_Cursor,        /**< struct spa_meta_cursor */
20
+   SPA_META_Control,       /**< metadata contains a spa_meta_control
21
+                     *  associated with the data */
22
+   SPA_META_Busy,          /**< don't write to buffer when count > 0 */
23
+   SPA_META_VideoTransform,    /**< struct spa_meta_transform */
24
+
25
+   _SPA_META_LAST,         /**< not part of ABI/API */
26
 };
27
 
28
 /**
29
@@ -161,6 +162,24 @@
30
    uint32_t count;         /**< number of users busy with the buffer */
31
 };
32
 
33
+enum spa_meta_videotransform_value {
34
+   SPA_META_TRANSFORMATION_None = 0,   /**< no transform */
35
+   SPA_META_TRANSFORMATION_90,     /**< 90 degree counter-clockwise */
36
+   SPA_META_TRANSFORMATION_180,        /**< 180 degree counter-clockwise */
37
+   SPA_META_TRANSFORMATION_270,        /**< 270 degree counter-clockwise */
38
+   SPA_META_TRANSFORMATION_Flipped,    /**< 180 degree flipped around the vertical axis. Equivalent
39
+                         * to a reflexion through the vertical line splitting the
40
+                         * bufffer in two equal sized parts */
41
+   SPA_META_TRANSFORMATION_Flipped90,  /**< flip then rotate around 90 degree counter-clockwise */
42
+   SPA_META_TRANSFORMATION_Flipped180, /**< flip then rotate around 180 degree counter-clockwise */
43
+   SPA_META_TRANSFORMATION_Flipped270, /**< flip then rotate around 270 degree counter-clockwise */
44
+};
45
+
46
+/** a transformation of the buffer */
47
+struct spa_meta_videotransform {
48
+   uint32_t transform;     /**< orientation transformation that was applied to the buffer */
49
+};
50
+
51
 /**
52
  * \}
53
  */
54
pipewire-0.3.61.tar.gz/spa/include/spa/param/props.h -> pipewire-0.3.62.tar.gz/spa/include/spa/param/props.h Changed
9
 
1
@@ -74,6 +74,7 @@
2
    SPA_PROP_rate,
3
    SPA_PROP_quality,
4
    SPA_PROP_bluetoothAudioCodec,
5
+   SPA_PROP_bluetoothOffloadActive,
6
 
7
    SPA_PROP_START_Audio    = 0x10000,  /**< audio related properties */
8
    SPA_PROP_waveType,
9
pipewire-0.3.61.tar.gz/spa/include/spa/param/type-info.h -> pipewire-0.3.62.tar.gz/spa/include/spa/param/type-info.h Changed
9
 
1
@@ -117,6 +117,7 @@
2
    { SPA_PROP_rate, SPA_TYPE_Double, SPA_TYPE_INFO_PROPS_BASE "rate", NULL },
3
    { SPA_PROP_quality, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "quality", NULL },
4
    { SPA_PROP_bluetoothAudioCodec, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "bluetoothAudioCodec", spa_type_bluetooth_audio_codec },
5
+   { SPA_PROP_bluetoothOffloadActive, SPA_TYPE_Bool, SPA_TYPE_INFO_PROPS_BASE "bluetoothOffloadActive", NULL },
6
 
7
    { SPA_PROP_waveType, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "waveType", NULL },
8
    { SPA_PROP_frequency, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "frequency", NULL },
9
pipewire-0.3.61.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.62.tar.gz/spa/plugins/aec/aec-webrtc.cpp Changed
11
 
1
@@ -100,7 +100,8 @@
2
    }
3
 
4
    apm->high_pass_filter()->Enable(high_pass_filter);
5
-   // Always disable drift compensation since it requires drift sampling
6
+   // Always disable drift compensation since PipeWire will already do
7
+   // drift compensation on all sinks and sources linked to this echo-canceler
8
    apm->echo_cancellation()->enable_drift_compensation(false);
9
    apm->echo_cancellation()->Enable(true);
10
    // TODO: wire up supression levels to args
11
pipewire-0.3.61.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.62.tar.gz/spa/plugins/alsa/acp/acp.c Changed
70
 
1
@@ -34,7 +34,7 @@
2
 
3
 struct spa_i18n *acp_i18n;
4
 
5
-#define DEFAULT_RATE   44100
6
+#define DEFAULT_RATE   48000
7
 
8
 #define VOLUME_ACCURACY (PA_VOLUME_NORM/100)  /* don't require volume adjustments to be perfectly correct. don't necessarily extend granularity in software unless the differences get greater than this level */
9
 
10
@@ -1348,7 +1348,6 @@
11
 static int device_enable(pa_card *impl, pa_alsa_mapping *mapping, pa_alsa_device *dev)
12
 {
13
    const char *mod_name;
14
-   bool ignore_dB = false;
15
    uint32_t i, port_index;
16
    int res;
17
 
18
@@ -1365,7 +1364,7 @@
19
 
20
    dev->device.flags |= ACP_DEVICE_ACTIVE;
21
 
22
-   find_mixer(impl, dev, NULL, ignore_dB);
23
+   find_mixer(impl, dev, NULL, impl->ignore_dB);
24
 
25
    /* Synchronize priority values, as it may have changed when setting the profile */
26
    for (i = 0; i < impl->card.n_ports; i++) {
27
@@ -1386,7 +1385,7 @@
28
    if (dev->active_port)
29
        dev->active_port->port.flags |= ACP_PORT_ACTIVE;
30
 
31
-   if ((res = setup_mixer(impl, dev, ignore_dB)) < 0)
32
+   if ((res = setup_mixer(impl, dev, impl->ignore_dB)) < 0)
33
        return res;
34
 
35
    if (dev->read_volume)
36
@@ -1533,7 +1532,6 @@
37
    struct acp_card *card;
38
    const char *s, *profile_set = NULL, *profile = NULL;
39
    char device_id16;
40
-   bool ignore_dB = false;
41
    uint32_t profile_index;
42
    int res;
43
 
44
@@ -1554,6 +1552,7 @@
45
    impl->use_ucm = true;
46
    impl->auto_profile = true;
47
    impl->auto_port = true;
48
+   impl->ignore_dB = false;
49
 
50
    if (props) {
51
        if ((s = acp_dict_lookup(props, "api.alsa.use-ucm")) != NULL)
52
@@ -1561,7 +1560,7 @@
53
        if ((s = acp_dict_lookup(props, "api.alsa.soft-mixer")) != NULL)
54
            impl->soft_mixer = spa_atob(s);
55
        if ((s = acp_dict_lookup(props, "api.alsa.ignore-dB")) != NULL)
56
-           ignore_dB = spa_atob(s);
57
+           impl->ignore_dB = spa_atob(s);
58
        if ((s = acp_dict_lookup(props, "device.profile-set")) != NULL)
59
            profile_set = s;
60
        if ((s = acp_dict_lookup(props, "device.profile")) != NULL)
61
@@ -1609,7 +1608,7 @@
62
        goto error;
63
    }
64
 
65
-   impl->profile_set->ignore_dB = ignore_dB;
66
+   impl->profile_set->ignore_dB = impl->ignore_dB;
67
 
68
    pa_alsa_profile_set_probe(impl->profile_set, impl->ucm.mixers,
69
            device_id,
70
pipewire-0.3.61.tar.gz/spa/plugins/alsa/acp/card.h -> pipewire-0.3.62.tar.gz/spa/plugins/alsa/acp/card.h Changed
9
 
1
@@ -46,6 +46,7 @@
2
    bool soft_mixer;
3
    bool auto_profile;
4
    bool auto_port;
5
+   bool ignore_dB;
6
 
7
    pa_alsa_ucm_config ucm;
8
    pa_alsa_profile_set *profile_set;
9
pipewire-0.3.61.tar.gz/spa/plugins/audioconvert/audioadapter.c -> pipewire-0.3.62.tar.gz/spa/plugins/audioconvert/audioadapter.c Changed
92
 
1
@@ -138,6 +138,27 @@
2
    return 0;
3
 }
4
 
5
+static int convert_enum_port_config(struct impl *this,
6
+       int seq, uint32_t id, uint32_t start, uint32_t num,
7
+       const struct spa_pod *filter, struct spa_pod_builder *builder)
8
+{
9
+   struct spa_pod *f1, *f2 = NULL;
10
+   int res;
11
+
12
+   f1 = spa_pod_builder_add_object(builder,
13
+       SPA_TYPE_OBJECT_ParamPortConfig, id,
14
+           SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(this->direction));
15
+
16
+   if (filter) {
17
+       if ((res = spa_pod_filter(builder, &f2, f1, filter)) < 0)
18
+           return res;
19
+   }
20
+   else {
21
+       f2 = f1;
22
+   }
23
+   return spa_node_enum_params(this->convert, seq, id, start, num, f2);
24
+}
25
+
26
 static int impl_node_enum_params(void *object, int seq,
27
                 uint32_t id, uint32_t start, uint32_t num,
28
                 const struct spa_pod *filter)
29
@@ -163,9 +184,25 @@
30
 
31
    switch (id) {
32
    case SPA_PARAM_EnumPortConfig:
33
+       return convert_enum_port_config(this, seq, id, start, num, filter, &b.b);
34
    case SPA_PARAM_PortConfig:
35
-       res = spa_node_enum_params(this->convert, seq, id, start, num, filter);
36
-       return res;
37
+       if (this->passthrough) {
38
+           switch (result.index) {
39
+           case 0:
40
+               result.param = spa_pod_builder_add_object(&b.b,
41
+                   SPA_TYPE_OBJECT_ParamPortConfig, id,
42
+                   SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(this->direction),
43
+                   SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(
44
+                       SPA_PARAM_PORT_CONFIG_MODE_passthrough));
45
+               result.next++;
46
+               break;
47
+           default:
48
+               return 0;
49
+           }
50
+       } else {
51
+           return convert_enum_port_config(this, seq, id, start, num, filter, &b.b);
52
+       }
53
+       break;
54
    case SPA_PARAM_PropInfo:
55
        res = follower_enum_params(this,
56
                id, IDX_PropInfo, &result, filter, &b.b);
57
@@ -813,9 +850,11 @@
58
        this->started = true;
59
        break;
60
    case SPA_NODE_COMMAND_Suspend:
61
+       this->started = false;
62
        spa_log_debug(this->log, "%p: suspending", this);
63
        break;
64
    case SPA_NODE_COMMAND_Pause:
65
+       this->started = false;
66
        spa_log_debug(this->log, "%p: pausing", this);
67
        break;
68
    case SPA_NODE_COMMAND_Flush:
69
@@ -847,10 +886,10 @@
70
        break;
71
    case SPA_NODE_COMMAND_Suspend:
72
        configure_format(this, 0, NULL);
73
-       SPA_FALLTHROUGH
74
+       spa_log_debug(this->log, "%p: suspended", this);
75
+       break;
76
    case SPA_NODE_COMMAND_Pause:
77
-       this->started = false;
78
-       spa_log_debug(this->log, "%p: stopped", this);
79
+       spa_log_debug(this->log, "%p: paused", this);
80
        break;
81
    case SPA_NODE_COMMAND_Flush:
82
        spa_log_debug(this->log, "%p: flushed", this);
83
@@ -1164,7 +1203,7 @@
84
    spa_log_trace_fp(this->log, "%p: ready %d", this, status);
85
 
86
    if (!this->started) {
87
-       spa_log_warn(this->log, "%p: ready stopped node", this);
88
+       spa_log_info(this->log, "%p: ready stopped node", this);
89
        return -EIO;
90
    }
91
 
92
pipewire-0.3.61.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.62.tar.gz/spa/plugins/audioconvert/audioconvert.c Changed
120
 
1
@@ -161,6 +161,7 @@
2
    struct port *portsMAX_PORTS;
3
    uint32_t n_ports;
4
 
5
+   enum spa_direction direction;
6
    enum spa_param_port_config_mode mode;
7
 
8
    struct spa_audio_info format;
9
@@ -378,55 +379,61 @@
10
 
11
    switch (id) {
12
    case SPA_PARAM_EnumPortConfig:
13
+   {
14
+       struct dir *dir;
15
        switch (result.index) {
16
        case 0:
17
-           param = spa_pod_builder_add_object(&b,
18
-               SPA_TYPE_OBJECT_ParamPortConfig, id,
19
-               SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_INPUT),
20
-               SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp));
21
+           dir = &this->dirSPA_DIRECTION_INPUT;;
22
            break;
23
        case 1:
24
-           param = spa_pod_builder_add_object(&b,
25
-               SPA_TYPE_OBJECT_ParamPortConfig, id,
26
-               SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_OUTPUT),
27
-               SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp));
28
-           break;
29
-       case 2:
30
-           param = spa_pod_builder_add_object(&b,
31
-               SPA_TYPE_OBJECT_ParamPortConfig, id,
32
-               SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_INPUT),
33
-               SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert));
34
-           break;
35
-       case 3:
36
-           param = spa_pod_builder_add_object(&b,
37
-               SPA_TYPE_OBJECT_ParamPortConfig, id,
38
-               SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_OUTPUT),
39
-               SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert));
40
+           dir = &this->dirSPA_DIRECTION_OUTPUT;;
41
            break;
42
        default:
43
            return 0;
44
        }
45
+       param = spa_pod_builder_add_object(&b,
46
+           SPA_TYPE_OBJECT_ParamPortConfig, id,
47
+           SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(dir->direction),
48
+           SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_CHOICE_ENUM_Id(4,
49
+               SPA_PARAM_PORT_CONFIG_MODE_none,
50
+               SPA_PARAM_PORT_CONFIG_MODE_none,
51
+               SPA_PARAM_PORT_CONFIG_MODE_dsp,
52
+               SPA_PARAM_PORT_CONFIG_MODE_convert),
53
+           SPA_PARAM_PORT_CONFIG_monitor,   SPA_POD_CHOICE_Bool(false),
54
+           SPA_PARAM_PORT_CONFIG_control,   SPA_POD_CHOICE_Bool(false));
55
        break;
56
-
57
+   }
58
    case SPA_PARAM_PortConfig:
59
+   {
60
+       struct dir *dir;
61
+       struct spa_pod_frame f1;
62
+
63
        switch (result.index) {
64
        case 0:
65
-           param = spa_pod_builder_add_object(&b,
66
-               SPA_TYPE_OBJECT_ParamPortConfig, id,
67
-               SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_INPUT),
68
-               SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(this->dirSPA_DIRECTION_INPUT.mode));
69
+           dir = &this->dirSPA_DIRECTION_INPUT;;
70
            break;
71
        case 1:
72
-           param = spa_pod_builder_add_object(&b,
73
-               SPA_TYPE_OBJECT_ParamPortConfig, id,
74
-               SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_OUTPUT),
75
-               SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(this->dirSPA_DIRECTION_OUTPUT.mode));
76
+           dir = &this->dirSPA_DIRECTION_OUTPUT;;
77
            break;
78
        default:
79
            return 0;
80
        }
81
+       spa_pod_builder_push_object(&b, &f0, SPA_TYPE_OBJECT_ParamPortConfig, id);
82
+       spa_pod_builder_add(&b,
83
+           SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(dir->direction),
84
+           SPA_PARAM_PORT_CONFIG_mode,      SPA_POD_Id(dir->mode),
85
+           SPA_PARAM_PORT_CONFIG_monitor,   SPA_POD_Bool(this->monitor),
86
+           SPA_PARAM_PORT_CONFIG_control,   SPA_POD_Bool(dir->control),
87
+           0);
88
+
89
+       if (dir->have_format) {
90
+           spa_pod_builder_prop(&b, SPA_PARAM_PORT_CONFIG_format, 0);
91
+           spa_format_audio_raw_build(&b, SPA_PARAM_PORT_CONFIG_format,
92
+                   &dir->format.info.raw);
93
+       }
94
+       param = spa_pod_builder_pop(&b, &f0);
95
        break;
96
-
97
+   }
98
    case SPA_PARAM_PropInfo:
99
    {
100
        struct props *p = &this->props;
101
@@ -1015,6 +1022,8 @@
102
        init_port(this, direction, 0, 0, false, false, false);
103
        break;
104
    }
105
+   case SPA_PARAM_PORT_CONFIG_MODE_none:
106
+       break;
107
    default:
108
        return -ENOTSUP;
109
    }
110
@@ -2906,7 +2915,9 @@
111
    this->props.soft.n_volumes = this->props.n_channels;
112
    this->props.monitor.n_volumes = this->props.n_channels;
113
 
114
+   this->dirSPA_DIRECTION_INPUT.direction = SPA_DIRECTION_INPUT;
115
    this->dirSPA_DIRECTION_INPUT.latency = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
116
+   this->dirSPA_DIRECTION_OUTPUT.direction = SPA_DIRECTION_OUTPUT;
117
    this->dirSPA_DIRECTION_OUTPUT.latency = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
118
 
119
    this->node.iface = SPA_INTERFACE_INIT(
120
pipewire-0.3.61.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c -> pipewire-0.3.62.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c Changed
201
 
1
@@ -156,11 +156,12 @@
2
 conv_s24_to_f32d_1s_avx2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
3
        uint32_t n_channels, uint32_t n_samples)
4
 {
5
-   const int24_t *s = src;
6
+   const int8_t *s = src;
7
    float *d0 = dst0;
8
    uint32_t n, unrolled;
9
    __m128i in;
10
    __m128 out, factor = _mm_set1_ps(1.0f / S24_SCALE);
11
+   __m128i mask1 = _mm_setr_epi32(0*n_channels, 3*n_channels, 6*n_channels, 9*n_channels);
12
 
13
    if (SPA_IS_ALIGNED(d0, 16) && n_samples > 0) {
14
        unrolled = n_samples & ~3;
15
@@ -171,23 +172,19 @@
16
        unrolled = 0;
17
 
18
    for(n = 0; n < unrolled; n += 4) {
19
-       in = _mm_setr_epi32(
20
-           *((uint32_t*)&s0 * n_channels),
21
-           *((uint32_t*)&s1 * n_channels),
22
-           *((uint32_t*)&s2 * n_channels),
23
-           *((uint32_t*)&s3 * n_channels));
24
+       in = _mm_i32gather_epi32((int*)s, mask1, 1);
25
        in = _mm_slli_epi32(in, 8);
26
        in = _mm_srai_epi32(in, 8);
27
        out = _mm_cvtepi32_ps(in);
28
        out = _mm_mul_ps(out, factor);
29
        _mm_store_ps(&d0n, out);
30
-       s += 4 * n_channels;
31
+       s += 12 * n_channels;
32
    }
33
    for(; n < n_samples; n++) {
34
-       out = _mm_cvtsi32_ss(factor, s24_to_s32(*s));
35
+       out = _mm_cvtsi32_ss(factor, s24_to_s32(*(int24_t*)s));
36
        out = _mm_mul_ss(out, factor);
37
        _mm_store_ss(&d0n, out);
38
-       s += n_channels;
39
+       s += 3 * n_channels;
40
    }
41
 }
42
 
43
@@ -195,11 +192,12 @@
44
 conv_s24_to_f32d_2s_avx2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
45
        uint32_t n_channels, uint32_t n_samples)
46
 {
47
-   const int24_t *s = src;
48
+   const int8_t *s = src;
49
    float *d0 = dst0, *d1 = dst1;
50
    uint32_t n, unrolled;
51
    __m128i in2;
52
    __m128 out2, factor = _mm_set1_ps(1.0f / S24_SCALE);
53
+   __m128i mask1 = _mm_setr_epi32(0*n_channels, 3*n_channels, 6*n_channels, 9*n_channels);
54
 
55
    if (SPA_IS_ALIGNED(d0, 16) &&
56
        SPA_IS_ALIGNED(d1, 16) &&
57
@@ -212,16 +210,8 @@
58
        unrolled = 0;
59
 
60
    for(n = 0; n < unrolled; n += 4) {
61
-       in0 = _mm_setr_epi32(
62
-           *((uint32_t*)&s0 + 0*n_channels),
63
-           *((uint32_t*)&s0 + 1*n_channels),
64
-           *((uint32_t*)&s0 + 2*n_channels),
65
-           *((uint32_t*)&s0 + 3*n_channels));
66
-       in1 = _mm_setr_epi32(
67
-           *((uint32_t*)&s1 + 0*n_channels),
68
-           *((uint32_t*)&s1 + 1*n_channels),
69
-           *((uint32_t*)&s1 + 2*n_channels),
70
-           *((uint32_t*)&s1 + 3*n_channels));
71
+       in0 = _mm_i32gather_epi32((int*)&s0, mask1, 1);
72
+       in1 = _mm_i32gather_epi32((int*)&s3, mask1, 1);
73
 
74
        in0 = _mm_slli_epi32(in0, 8);
75
        in1 = _mm_slli_epi32(in1, 8);
76
@@ -238,27 +228,28 @@
77
        _mm_store_ps(&d0n, out0);
78
        _mm_store_ps(&d1n, out1);
79
 
80
-       s += 4 * n_channels;
81
+       s += 12 * n_channels;
82
    }
83
    for(; n < n_samples; n++) {
84
-       out0 = _mm_cvtsi32_ss(factor, s24_to_s32(*s));
85
-       out1 = _mm_cvtsi32_ss(factor, s24_to_s32(*(s+1)));
86
+       out0 = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+0)));
87
+       out1 = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+1)));
88
        out0 = _mm_mul_ss(out0, factor);
89
        out1 = _mm_mul_ss(out1, factor);
90
        _mm_store_ss(&d0n, out0);
91
        _mm_store_ss(&d1n, out1);
92
-       s += n_channels;
93
+       s += 3 * n_channels;
94
    }
95
 }
96
 static void
97
 conv_s24_to_f32d_4s_avx2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src,
98
        uint32_t n_channels, uint32_t n_samples)
99
 {
100
-   const int24_t *s = src;
101
+   const int8_t *s = src;
102
    float *d0 = dst0, *d1 = dst1, *d2 = dst2, *d3 = dst3;
103
    uint32_t n, unrolled;
104
    __m128i in4;
105
    __m128 out4, factor = _mm_set1_ps(1.0f / S24_SCALE);
106
+   __m128i mask1 = _mm_setr_epi32(0*n_channels, 3*n_channels, 6*n_channels, 9*n_channels);
107
 
108
    if (SPA_IS_ALIGNED(d0, 16) &&
109
        SPA_IS_ALIGNED(d1, 16) &&
110
@@ -273,26 +264,10 @@
111
        unrolled = 0;
112
 
113
    for(n = 0; n < unrolled; n += 4) {
114
-       in0 = _mm_setr_epi32(
115
-           *((uint32_t*)&s0 + 0*n_channels),
116
-           *((uint32_t*)&s0 + 1*n_channels),
117
-           *((uint32_t*)&s0 + 2*n_channels),
118
-           *((uint32_t*)&s0 + 3*n_channels));
119
-       in1 = _mm_setr_epi32(
120
-           *((uint32_t*)&s1 + 0*n_channels),
121
-           *((uint32_t*)&s1 + 1*n_channels),
122
-           *((uint32_t*)&s1 + 2*n_channels),
123
-           *((uint32_t*)&s1 + 3*n_channels));
124
-       in2 = _mm_setr_epi32(
125
-           *((uint32_t*)&s2 + 0*n_channels),
126
-           *((uint32_t*)&s2 + 1*n_channels),
127
-           *((uint32_t*)&s2 + 2*n_channels),
128
-           *((uint32_t*)&s2 + 3*n_channels));
129
-       in3 = _mm_setr_epi32(
130
-           *((uint32_t*)&s3 + 0*n_channels),
131
-           *((uint32_t*)&s3 + 1*n_channels),
132
-           *((uint32_t*)&s3 + 2*n_channels),
133
-           *((uint32_t*)&s3 + 3*n_channels));
134
+       in0 = _mm_i32gather_epi32((int*)&s0, mask1, 1);
135
+       in1 = _mm_i32gather_epi32((int*)&s3, mask1, 1);
136
+       in2 = _mm_i32gather_epi32((int*)&s6, mask1, 1);
137
+       in3 = _mm_i32gather_epi32((int*)&s9, mask1, 1);
138
 
139
        in0 = _mm_slli_epi32(in0, 8);
140
        in1 = _mm_slli_epi32(in1, 8);
141
@@ -319,13 +294,13 @@
142
        _mm_store_ps(&d2n, out2);
143
        _mm_store_ps(&d3n, out3);
144
 
145
-       s += 4 * n_channels;
146
+       s += 12 * n_channels;
147
    }
148
    for(; n < n_samples; n++) {
149
-       out0 = _mm_cvtsi32_ss(factor, s24_to_s32(*s));
150
-       out1 = _mm_cvtsi32_ss(factor, s24_to_s32(*(s+1)));
151
-       out2 = _mm_cvtsi32_ss(factor, s24_to_s32(*(s+2)));
152
-       out3 = _mm_cvtsi32_ss(factor, s24_to_s32(*(s+3)));
153
+       out0 = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+0)));
154
+       out1 = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+1)));
155
+       out2 = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+2)));
156
+       out3 = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+3)));
157
        out0 = _mm_mul_ss(out0, factor);
158
        out1 = _mm_mul_ss(out1, factor);
159
        out2 = _mm_mul_ss(out2, factor);
160
@@ -334,7 +309,7 @@
161
        _mm_store_ss(&d1n, out1);
162
        _mm_store_ss(&d2n, out2);
163
        _mm_store_ss(&d3n, out3);
164
-       s += n_channels;
165
+       s += 3 * n_channels;
166
    }
167
 }
168
 
169
@@ -361,12 +336,10 @@
170
    const int32_t *s = src;
171
    float *d0 = dst0, *d1 = dst1, *d2 = dst2, *d3 = dst3;
172
    uint32_t n, unrolled;
173
-   __m256i in4, t4;
174
+   __m256i in4;
175
    __m256 out4, factor = _mm256_set1_ps(1.0f / S24_SCALE);
176
-   __m256i mask1 = _mm256_setr_epi64x(0*n_channels, 0*n_channels+2, 4*n_channels, 4*n_channels+2);
177
-   __m256i mask2 = _mm256_setr_epi64x(1*n_channels, 1*n_channels+2, 5*n_channels, 5*n_channels+2);
178
-   __m256i mask3 = _mm256_setr_epi64x(2*n_channels, 2*n_channels+2, 6*n_channels, 6*n_channels+2);
179
-   __m256i mask4 = _mm256_setr_epi64x(3*n_channels, 3*n_channels+2, 7*n_channels, 7*n_channels+2);
180
+   __m256i mask1 = _mm256_setr_epi32(0*n_channels, 1*n_channels, 2*n_channels, 3*n_channels,
181
+                     3*n_channels, 5*n_channels, 6*n_channels, 7*n_channels);
182
 
183
    if (SPA_IS_ALIGNED(d0, 32) &&
184
        SPA_IS_ALIGNED(d1, 32) &&
185
@@ -377,19 +350,10 @@
186
        unrolled = 0;
187
 
188
    for(n = 0; n < unrolled; n += 8) {
189
-       in0 = _mm256_i64gather_epi64((long long int *)&s0*n_channels, mask1, 4);
190
-       in1 = _mm256_i64gather_epi64((long long int *)&s0*n_channels, mask2, 4);
191
-       in2 = _mm256_i64gather_epi64((long long int *)&s0*n_channels, mask3, 4);
192
-       in3 = _mm256_i64gather_epi64((long long int *)&s0*n_channels, mask4, 4);
193
-
194
-       t0 = _mm256_unpacklo_epi32(in0, in1);   /* a0 a1 b0 b1 a4 a5 b4 b5 */
195
-       t1 = _mm256_unpackhi_epi32(in0, in1);   /* c0 c1 d0 d1 c4 c5 d4 d5 */
196
-       t2 = _mm256_unpacklo_epi32(in2, in3);   /* a2 a3 b2 b3 a6 a7 b6 b7 */
197
-       t3 = _mm256_unpackhi_epi32(in2, in3);   /* c2 c3 d2 d3 c6 c7 d6 d7 */
198
-       in0 = _mm256_unpacklo_epi64(t0, t2);     /* a0 a1 a2 a3 a4 a5 a6 a7 */
199
-       in1 = _mm256_unpackhi_epi64(t0, t2);     /* b0 b1 b2 b3 b4 b5 b6 b7 */
200
-       in2 = _mm256_unpacklo_epi64(t1, t3);     /* c0 c1 c2 c3 c4 c5 c6 c7 */
201
pipewire-0.3.61.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.62.tar.gz/spa/plugins/bluez5/bluez5-device.c Changed
160
 
1
@@ -79,11 +79,13 @@
2
 
3
 struct props {
4
    enum spa_bluetooth_audio_codec codec;
5
+   bool offload_active;
6
 };
7
 
8
 static void reset_props(struct props *props)
9
 {
10
    props->codec = 0;
11
+   props->offload_active = false;
12
 }
13
 
14
 struct impl;
15
@@ -97,6 +99,7 @@
16
    unsigned int mute:1;
17
    unsigned int save:1;
18
    unsigned int a2dp_duplex:1;
19
+   unsigned int offload_acquired:1;
20
    uint32_t n_channels;
21
    int64_t latency_offset;
22
    uint32_t channelsSPA_AUDIO_MAX_CHANNELS;
23
@@ -407,6 +410,24 @@
24
    .volume_changed = volume_changed,
25
 };
26
 
27
+static int node_offload_set_active(struct node *node, bool active)
28
+{
29
+   int res = 0;
30
+
31
+   if (node->transport == NULL || !node->active)
32
+       return -ENOTSUP;
33
+
34
+   if (active && !node->offload_acquired)
35
+       res = spa_bt_transport_acquire(node->transport, false);
36
+   else if (!active && node->offload_acquired)
37
+       res = spa_bt_transport_release(node->transport);
38
+
39
+   if (res >= 0)
40
+       node->offload_acquired = active;
41
+
42
+   return res;
43
+}
44
+
45
 static void get_channels(struct spa_bt_transport *t, bool a2dp_duplex, uint32_t *n_channels, uint32_t *channels)
46
 {
47
    const struct media_codec *codec;
48
@@ -480,6 +501,7 @@
49
 
50
        this->nodesid.impl = this;
51
        this->nodesid.active = true;
52
+       this->nodesid.offload_acquired = false;
53
        this->nodesid.a2dp_duplex = a2dp_duplex;
54
        get_channels(t, a2dp_duplex, &this->nodesid.n_channels, this->nodesid.channels);
55
        if (this->nodesid.transport)
56
@@ -804,6 +826,7 @@
57
 
58
    for (uint32_t i = 0; i < 2; i++) {
59
        struct node * node = &this->nodesi;
60
+       node_offload_set_active(node, false);
61
        if (node->transport) {
62
            spa_hook_remove(&node->transport_listener);
63
            node->transport = NULL;
64
@@ -813,6 +836,8 @@
65
            node->active = false;
66
        }
67
    }
68
+
69
+   this->props.offload_active = false;
70
 }
71
 
72
 static bool validate_profile(struct impl *this, uint32_t profile,
73
@@ -1674,7 +1699,7 @@
74
    return true;
75
 }
76
 
77
-static struct spa_pod *build_prop_info(struct impl *this, struct spa_pod_builder *b, uint32_t id)
78
+static struct spa_pod *build_prop_info_codec(struct impl *this, struct spa_pod_builder *b, uint32_t id)
79
 {
80
    struct spa_pod_frame f2;
81
    struct spa_pod_choice *choice;
82
@@ -1748,7 +1773,8 @@
83
 
84
    return spa_pod_builder_add_object(b,
85
            SPA_TYPE_OBJECT_Props, id,
86
-           SPA_PROP_bluetoothAudioCodec, SPA_POD_Id(p->codec));
87
+           SPA_PROP_bluetoothAudioCodec, SPA_POD_Id(p->codec),
88
+           SPA_PROP_bluetoothOffloadActive, SPA_POD_Bool(p->offload_active));
89
 }
90
 
91
 static int impl_enum_params(void *object, int seq,
92
@@ -1841,7 +1867,14 @@
93
    {
94
        switch (result.index) {
95
        case 0:
96
-           param = build_prop_info(this, &b, id);
97
+           param = build_prop_info_codec(this, &b, id);
98
+           break;
99
+       case 1:
100
+           param = spa_pod_builder_add_object(&b,
101
+                   SPA_TYPE_OBJECT_PropInfo, id,
102
+                   SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_bluetoothOffloadActive),
103
+                   SPA_PROP_INFO_description, SPA_POD_String("Bluetooth audio offload active"),
104
+                   SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(false));
105
            break;
106
        default:
107
            return 0;
108
@@ -2030,6 +2063,25 @@
109
    return changed;
110
 }
111
 
112
+static void apply_prop_offload_active(struct impl *this, bool active)
113
+{
114
+   bool old_value = this->props.offload_active;
115
+
116
+   this->props.offload_active = active;
117
+
118
+   for (int i = 0; i < 2; i++) {
119
+       node_offload_set_active(&this->nodesi, active);
120
+       if (!this->nodesi.offload_acquired)
121
+           this->props.offload_active = false;
122
+   }
123
+
124
+   if (this->props.offload_active != old_value) {
125
+       this->info.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
126
+       this->paramsIDX_Props.flags ^= SPA_PARAM_INFO_SERIAL;
127
+       emit_info(this, false);
128
+   }
129
+}
130
+
131
 static int impl_set_param(void *object,
132
              uint32_t id, uint32_t flags,
133
              const struct spa_pod *param)
134
@@ -2104,19 +2156,23 @@
135
    case SPA_PARAM_Props:
136
    {
137
        uint32_t codec_id = SPA_ID_INVALID;
138
+       bool offload_active = this->props.offload_active;
139
 
140
        if (param == NULL)
141
            return 0;
142
 
143
        if ((res = spa_pod_parse_object(param,
144
                SPA_TYPE_OBJECT_Props, NULL,
145
-               SPA_PROP_bluetoothAudioCodec, SPA_POD_OPT_Id(&codec_id))) < 0) {
146
+               SPA_PROP_bluetoothAudioCodec, SPA_POD_OPT_Id(&codec_id),
147
+               SPA_PROP_bluetoothOffloadActive, SPA_POD_OPT_Bool(&offload_active))) < 0) {
148
            spa_log_warn(this->log, "can't parse props");
149
            spa_debug_pod(0, NULL, param);
150
            return res;
151
        }
152
 
153
-       spa_log_debug(this->log, "setting props codec:%d", codec_id);
154
+       spa_log_debug(this->log, "setting props codec:%d offload:%d", (int)codec_id, (int)offload_active);
155
+
156
+       apply_prop_offload_active(this, offload_active);
157
 
158
        if (codec_id == SPA_ID_INVALID)
159
            return 0;
160
pipewire-0.3.61.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.62.tar.gz/spa/plugins/bluez5/sco-sink.c Changed
9
 
1
@@ -95,7 +95,6 @@
2
    struct buffer buffersMAX_BUFFERS;
3
    uint32_t n_buffers;
4
 
5
-   struct spa_list free;
6
    struct spa_list ready;
7
 
8
    struct buffer *current_buffer;
9
pipewire-0.3.61.tar.gz/spa/plugins/libcamera/libcamera-source.cpp -> pipewire-0.3.62.tar.gz/spa/plugins/libcamera/libcamera-source.cpp Changed
22
 
1
@@ -78,6 +78,7 @@
2
    struct spa_list link;
3
    struct spa_buffer *outbuf;
4
    struct spa_meta_header *h;
5
+   struct spa_meta_videotransform *videotransform;
6
    void *ptr;
7
 };
8
 
9
@@ -589,6 +590,12 @@
10
                SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
11
                SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));
12
            break;
13
+       case 1:
14
+           param = (struct spa_pod*)spa_pod_builder_add_object(&b,
15
+               SPA_TYPE_OBJECT_ParamMeta, id,
16
+               SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform),
17
+               SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_videotransform)));
18
+           break;
19
        default:
20
            return 0;
21
        }
22
pipewire-0.3.61.tar.gz/spa/plugins/libcamera/libcamera-utils.cpp -> pipewire-0.3.62.tar.gz/spa/plugins/libcamera/libcamera-utils.cpp Changed
123
 
1
@@ -74,7 +74,7 @@
2
        return;
3
 
4
    StreamRoles roles;
5
-   roles.push_back(VideoRecording);
6
+   roles.push_back(StreamRole::VideoRecording);
7
    impl->config = impl->camera->generateConfiguration(roles);
8
 }
9
 
10
@@ -500,28 +500,48 @@
11
            0);
12
 
13
    switch (ctrl_id->type()) {
14
-   case ControlTypeBool:
15
+   case ControlTypeBool: {
16
+       bool def;
17
+       if (ctrl_info.def().isNone())
18
+           def = ctrl_info.min().get<bool>();
19
+       else
20
+           def = ctrl_info.def().get<bool>();
21
+
22
        spa_pod_builder_add(&b,
23
-               SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(
24
-                       (bool)ctrl_info.def().get<bool>()),
25
-               0);
26
-       break;
27
-   case ControlTypeFloat:
28
+                   SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(
29
+                           def),
30
+                   0);
31
+   } break;
32
+   case ControlTypeFloat: {
33
+       float min = ctrl_info.min().get<float>();
34
+       float max = ctrl_info.max().get<float>();
35
+       float def;
36
+
37
+       if (ctrl_info.def().isNone())
38
+           def = (min + max) / 2;
39
+       else
40
+           def = ctrl_info.def().get<float>();
41
+
42
        spa_pod_builder_add(&b,
43
                SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
44
-                       (float)ctrl_info.def().get<float>(),
45
-                       (float)ctrl_info.min().get<float>(),
46
-                       (float)ctrl_info.max().get<float>()),
47
+                       def, min, max),
48
                0);
49
-       break;
50
-   case ControlTypeInteger32:
51
+   } break;
52
+   case ControlTypeInteger32: {
53
+       int32_t min = ctrl_info.min().get<int32_t>();
54
+       int32_t max = ctrl_info.max().get<int32_t>();
55
+       int32_t def;
56
+
57
+       if (ctrl_info.def().isNone())
58
+           def = (min + max) / 2;
59
+       else
60
+           def = ctrl_info.def().get<int32_t>();
61
+
62
        spa_pod_builder_add(&b,
63
                SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(
64
-                       (int32_t)ctrl_info.def().get<int32_t>(),
65
-                       (int32_t)ctrl_info.min().get<int32_t>(),
66
-                       (int32_t)ctrl_info.max().get<int32_t>()),
67
+                       def, min, max),
68
                0);
69
-       break;
70
+   } break;
71
    default:
72
        goto next;
73
    }
74
@@ -678,6 +698,31 @@
75
    return -ENOTSUP;
76
 }
77
 
78
+static const struct {
79
+   Transform libcamera_transform;
80
+   uint32_t spa_transform_value;
81
+} transform_map = {
82
+   { Transform::Identity, SPA_META_TRANSFORMATION_None },
83
+   { Transform::Rot0, SPA_META_TRANSFORMATION_None },
84
+   { Transform::HFlip, SPA_META_TRANSFORMATION_Flipped },
85
+   { Transform::VFlip, SPA_META_TRANSFORMATION_Flipped180 },
86
+   { Transform::HVFlip, SPA_META_TRANSFORMATION_180 },
87
+   { Transform::Rot180, SPA_META_TRANSFORMATION_180 },
88
+   { Transform::Transpose, SPA_META_TRANSFORMATION_Flipped90 },
89
+   { Transform::Rot90, SPA_META_TRANSFORMATION_90 },
90
+   { Transform::Rot270, SPA_META_TRANSFORMATION_270 },
91
+   { Transform::Rot180Transpose, SPA_META_TRANSFORMATION_Flipped270 },
92
+};
93
+
94
+static uint32_t libcamera_transform_to_spa_transform_value(Transform transform)
95
+{
96
+   for (const auto& t : transform_map) {
97
+       if (t.libcamera_transform == transform)
98
+           return t.spa_transform_value;
99
+   }
100
+   return SPA_META_TRANSFORMATION_None;
101
+}
102
+
103
 static int
104
 mmap_init(struct impl *impl, struct port *port,
105
        struct spa_buffer **buffers, uint32_t n_buffers)
106
@@ -722,6 +767,16 @@
107
        b->flags = BUFFER_FLAG_OUTSTANDING;
108
        b->h = (struct spa_meta_header*)spa_buffer_find_meta_data(buffersi, SPA_META_Header, sizeof(*b->h));
109
 
110
+       b->videotransform = (struct spa_meta_videotransform*)spa_buffer_find_meta_data(
111
+           buffersi, SPA_META_VideoTransform, sizeof(*b->videotransform));
112
+       if (b->videotransform) {
113
+           b->videotransform->transform =
114
+               libcamera_transform_to_spa_transform_value(impl->config->transform);
115
+           spa_log_debug(impl->log, "Setting videotransform for buffer %d to %u (from %s)",
116
+               i, b->videotransform->transform, transformToString(impl->config->transform));
117
+
118
+       }
119
+
120
        d = buffersi->datas;
121
        for(j = 0; j < buffersi->n_datas; ++j) {
122
            dj.type = port->memtype;
123
pipewire-0.3.61.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.62.tar.gz/spa/plugins/support/loop.c Changed
158
 
1
@@ -89,7 +89,7 @@
2
    uint8_t *buffer_data;
3
    uint8_t buffer_memDATAS_SIZE + MAX_ALIGN;
4
 
5
-   unsigned int flushing:1;
6
+   uint32_t flush_count;
7
    unsigned int polling:1;
8
 };
9
 
10
@@ -166,23 +166,39 @@
11
 
12
 static void flush_items(struct impl *impl)
13
 {
14
-   uint32_t index;
15
+   uint32_t index, flush_count;
16
+   int32_t avail;
17
    int res;
18
 
19
-   impl->flushing = true;
20
-   while (spa_ringbuffer_get_read_index(&impl->buffer, &index) > 0) {
21
+   flush_count = ++impl->flush_count;
22
+   avail = spa_ringbuffer_get_read_index(&impl->buffer, &index);
23
+   while (avail > 0) {
24
        struct invoke_item *item;
25
        bool block;
26
+       spa_invoke_func_t func;
27
 
28
        item = SPA_PTROFF(impl->buffer_data, index & (DATAS_SIZE - 1), struct invoke_item);
29
        block = item->block;
30
+       func = item->func;
31
 
32
        spa_log_trace_fp(impl->log, "%p: flush item %p", impl, item);
33
-       item->res = item->func ? item->func(&impl->loop,
34
-               true, item->seq, item->data, item->size,
35
-              item->user_data) : 0;
36
-
37
-       spa_ringbuffer_read_update(&impl->buffer, index + item->item_size);
38
+       /* first we remove the function from the item so that recursive
39
+        * calls don't call the callback again. We can't update the
40
+        * read index before we call the function because then the item
41
+        * might get overwritten. */
42
+       item->func = NULL;
43
+       if (func)
44
+           item->res = func(&impl->loop, true, item->seq, item->data,
45
+               item->size, item->user_data);
46
+
47
+       /* if this function did a recursive invoke, it now flushed the
48
+        * ringbuffer and we can exit */
49
+       if (flush_count != impl->flush_count)
50
+           break;
51
+
52
+       index += item->item_size;
53
+       avail -= item->item_size;
54
+       spa_ringbuffer_read_update(&impl->buffer, index);
55
 
56
        if (block) {
57
            if ((res = spa_system_eventfd_write(impl->system, impl->ack_fd, 1)) < 0)
58
@@ -190,20 +206,21 @@
59
                        impl, impl->ack_fd, spa_strerror(res));
60
        }
61
    }
62
-   impl->flushing = false;
63
 }
64
 
65
 static int
66
 loop_invoke_inthread(struct impl *impl,
67
-       spa_invoke_func_t func,
68
-       uint32_t seq,
69
-       const void *data,
70
-       size_t size,
71
-       bool block,
72
-       void *user_data)
73
+       spa_invoke_func_t func,
74
+       uint32_t seq,
75
+       const void *data,
76
+       size_t size,
77
+       bool block,
78
+       void *user_data)
79
 {
80
-   if (!impl->flushing)
81
-       flush_items(impl);
82
+   /* we should probably have a second ringbuffer for the in-thread pending
83
+    * callbacks. A recursive callback when flushing will insert itself
84
+    * before this one. */
85
+   flush_items(impl);
86
    return func ? func(&impl->loop, true, seq, data, size, user_data) : 0;
87
 }
88
 
89
@@ -222,6 +239,9 @@
90
    int32_t filled;
91
    uint32_t avail, idx, offset, l0;
92
 
93
+   /* the ringbuffer can only be written to from one thread, if we are
94
+    * in the same thread as the loop, don't write into the ringbuffer
95
+    * but try to emit the calback right away after flushing what we have */
96
    if (impl->thread == 0 || pthread_equal(impl->thread, pthread_self()))
97
        return loop_invoke_inthread(impl, func, seq, data, size, block, user_data);
98
 
99
@@ -247,6 +267,7 @@
100
    item->size = size;
101
    item->block = block;
102
    item->user_data = user_data;
103
+   item->res = 0;
104
    item->item_size = SPA_ROUND_UP_N(sizeof(struct invoke_item) + size, ITEM_ALIGN);
105
 
106
    spa_log_trace_fp(impl->log, "%p: add item %p filled:%d", impl, item, filled);
107
@@ -585,10 +606,12 @@
108
    uint64_t count = 0;
109
    int res;
110
 
111
-   if ((res = spa_system_eventfd_read(s->impl->system, source->fd, &count)) < 0)
112
-       spa_log_warn(s->impl->log, "%p: failed to read event fd:%d: %s",
113
-               source, source->fd, spa_strerror(res));
114
-
115
+   if ((res = spa_system_eventfd_read(s->impl->system, source->fd, &count)) < 0) {
116
+       if (res != -EAGAIN)
117
+           spa_log_warn(s->impl->log, "%p: failed to read event fd:%d: %s",
118
+                   source, source->fd, spa_strerror(res));
119
+       return;
120
+   }
121
    s->func.event(source->data, count);
122
 }
123
 
124
@@ -651,10 +674,12 @@
125
    int res;
126
 
127
    if (SPA_UNLIKELY((res = spa_system_timerfd_read(s->impl->system,
128
-               source->fd, &expirations)) < 0))
129
-       spa_log_warn(s->impl->log, "%p: failed to read timer fd:%d: %s",
130
-               source, source->fd, spa_strerror(res));
131
-
132
+               source->fd, &expirations)) < 0)) {
133
+       if (res != -EAGAIN)
134
+           spa_log_warn(s->impl->log, "%p: failed to read timer fd:%d: %s",
135
+                   source, source->fd, spa_strerror(res));
136
+       return;
137
+   }
138
    s->func.timer(source->data, expirations);
139
 }
140
 
141
@@ -731,10 +756,12 @@
142
    struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
143
    int res, signal_number = 0;
144
 
145
-   if ((res = spa_system_signalfd_read(s->impl->system, source->fd, &signal_number)) < 0)
146
-       spa_log_warn(s->impl->log, "%p: failed to read signal fd:%d: %s",
147
-               source, source->fd, spa_strerror(res));
148
-
149
+   if ((res = spa_system_signalfd_read(s->impl->system, source->fd, &signal_number)) < 0) {
150
+       if (res != -EAGAIN)
151
+           spa_log_warn(s->impl->log, "%p: failed to read signal fd:%d: %s",
152
+                   source, source->fd, spa_strerror(res));
153
+       return;
154
+   }
155
    s->func.signal(source->data, signal_number);
156
 }
157
 
158
pipewire-0.3.61.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.62.tar.gz/src/daemon/pipewire-pulse.conf.in Changed
27
 
1
@@ -90,7 +90,7 @@
2
     #pulse.default.frag     = 96000/48000   # 2 seconds
3
     #pulse.default.tlength  = 96000/48000   # 2 seconds
4
     #pulse.min.quantum      = 256/48000     # 5ms
5
-    #pulse.idle.timeout     = 5             # pause after 5s of underruns
6
+    #pulse.idle.timeout     = 0             # don't pause after underruns
7
     #pulse.default.format   = F32
8
     #pulse.default.position =  FL FR 
9
     # These overrides are only applied when running in a vm.
10
@@ -137,12 +137,12 @@
11
     }
12
     {
13
         # speech dispatcher asks for too small latency and then underruns.
14
-        matches =  { application.name = "~speech-dispatcher*" } 
15
+        matches =  { application.name = "~speech-dispatcher.*" } 
16
         actions = {
17
             update-props = {
18
-                pulse.min.req          = 1024/48000     # 21ms
19
-                pulse.min.quantum      = 1024/48000     # 21ms
20
-                #pulse.idle.timeout    = 0
21
+                pulse.min.req          = 512/48000      # 10.6ms
22
+                pulse.min.quantum      = 512/48000      # 10.6ms
23
+                pulse.idle.timeout     = 5              # pause after 5 seconds of underrun
24
             }
25
         }
26
     }
27
pipewire-0.3.61.tar.gz/src/examples/video-dsp-play.c -> pipewire-0.3.62.tar.gz/src/examples/video-dsp-play.c Changed
10
 
1
@@ -139,6 +139,8 @@
2
 
3
    /* copy video image in texture */
4
    sstride = buf->datas0.chunk->stride;
5
+   if (sstride == 0)
6
+       sstride = buf->datas0.chunk->size / data->position->video.size.height;
7
 
8
    src = sdata;
9
    dst = ddata;
10
pipewire-0.3.61.tar.gz/src/examples/video-play-fixate.c -> pipewire-0.3.62.tar.gz/src/examples/video-play-fixate.c Changed
10
 
1
@@ -257,6 +257,8 @@
2
 
3
    /* copy video image in texture */
4
    sstride = buf->datas0.chunk->stride;
5
+   if (sstride == 0)
6
+       sstride = buf->datas0.chunk->size / data->size.height;
7
    ostride = SPA_MIN(sstride, dstride);
8
 
9
    src = sdata;
10
pipewire-0.3.61.tar.gz/src/examples/video-play-pull.c -> pipewire-0.3.62.tar.gz/src/examples/video-play-pull.c Changed
10
 
1
@@ -206,6 +206,8 @@
2
        }
3
 
4
        sstride = buf->datas0.chunk->stride;
5
+       if (sstride == 0)
6
+           sstride = buf->datas0.chunk->size / data->size.height;
7
        ostride = SPA_MIN(sstride, dstride);
8
 
9
        src = sdata;
10
pipewire-0.3.61.tar.gz/src/examples/video-play-reneg.c -> pipewire-0.3.62.tar.gz/src/examples/video-play-reneg.c Changed
10
 
1
@@ -136,6 +136,8 @@
2
 
3
    /* copy video image in texture */
4
    sstride = buf->datas0.chunk->stride;
5
+   if (sstride == 0)
6
+       sstride = buf->datas0.chunk->size / data->size.height;
7
    ostride = SPA_MIN(sstride, dstride);
8
 
9
    src = sdata;
10
pipewire-0.3.61.tar.gz/src/examples/video-play.c -> pipewire-0.3.62.tar.gz/src/examples/video-play.c Changed
10
 
1
@@ -204,6 +204,8 @@
2
        }
3
 
4
        sstride = buf->datas0.chunk->stride;
5
+       if (sstride == 0)
6
+           sstride = buf->datas0.chunk->size / data->size.height;
7
        ostride = SPA_MIN(sstride, dstride);
8
 
9
        src = sdata;
10
pipewire-0.3.61.tar.gz/src/gst/gstpipewirepool.c -> pipewire-0.3.62.tar.gz/src/gst/gstpipewirepool.c Changed
10
 
1
@@ -115,6 +115,8 @@
2
   data->crop = spa_buffer_find_meta_data (b->buffer, SPA_META_VideoCrop, sizeof(*data->crop));
3
   if (data->crop)
4
      gst_buffer_add_video_crop_meta(buf);
5
+  data->videotransform =
6
+    spa_buffer_find_meta_data (b->buffer, SPA_META_VideoTransform, sizeof(*data->videotransform));
7
 
8
   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
9
                              pool_data_quark,
10
pipewire-0.3.61.tar.gz/src/gst/gstpipewirepool.h -> pipewire-0.3.62.tar.gz/src/gst/gstpipewirepool.h Changed
9
 
1
@@ -57,6 +57,7 @@
2
   GstBuffer *buf;
3
   gboolean queued;
4
   struct spa_meta_region *crop;
5
+  struct spa_meta_videotransform *videotransform;
6
 };
7
 
8
 struct _GstPipeWirePool {
9
pipewire-0.3.61.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.62.tar.gz/src/gst/gstpipewiresink.c Changed
9
 
1
@@ -491,6 +491,7 @@
2
     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
3
     d->chunk->offset = mem->offset;
4
     d->chunk->size = mem->size;
5
+    d->chunk->stride = 0;
6
   }
7
 
8
   if ((res = pw_stream_queue_buffer (pwsink->stream, data->b)) < 0) {
9
pipewire-0.3.61.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.62.tar.gz/src/gst/gstpipewiresrc.c Changed
87
 
1
@@ -514,6 +514,25 @@
2
   }
3
 }
4
 
5
+static const char * const transform_map = {
6
+  SPA_META_TRANSFORMATION_None = "rotate-0",
7
+  SPA_META_TRANSFORMATION_90 = "rotate-90",
8
+  SPA_META_TRANSFORMATION_180 = "rotate-180",
9
+  SPA_META_TRANSFORMATION_270 = "rotate-270",
10
+  SPA_META_TRANSFORMATION_Flipped = "flip-rotate-0",
11
+  SPA_META_TRANSFORMATION_Flipped90 = "flip-rotate-270",
12
+  SPA_META_TRANSFORMATION_Flipped180 = "flip-rotate-180",
13
+  SPA_META_TRANSFORMATION_Flipped270 = "flip-rotate-90",
14
+};
15
+
16
+static const char *spa_transform_value_to_gst_image_orientation(uint32_t transform_value)
17
+{
18
+  if (transform_value >= SPA_N_ELEMENTS(transform_map))
19
+    transform_value = SPA_META_TRANSFORMATION_None;
20
+
21
+  return transform_maptransform_value;
22
+}
23
+
24
 static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc)
25
 {
26
   struct pw_buffer *b;
27
@@ -521,6 +540,7 @@
28
   GstPipeWirePoolData *data;
29
   struct spa_meta_header *h;
30
   struct spa_meta_region *crop;
31
+  struct spa_meta_videotransform *videotransform;
32
   guint i;
33
 
34
   b = pw_stream_dequeue_buffer (pwsrc->stream);
35
@@ -568,6 +588,27 @@
36
       meta->height = crop->region.size.height;
37
     }
38
   }
39
+
40
+  videotransform = data->videotransform;
41
+  if (videotransform) {
42
+    if (pwsrc->transform_value != videotransform->transform) {
43
+      GstEvent *tag_event;
44
+      const char* tag_string;
45
+
46
+      tag_string =
47
+          spa_transform_value_to_gst_image_orientation(videotransform->transform);
48
+
49
+      GST_LOG_OBJECT (pwsrc, "got new videotransform: %u / %s",
50
+          videotransform->transform, tag_string);
51
+
52
+      tag_event = gst_event_new_tag(gst_tag_list_new(GST_TAG_IMAGE_ORIENTATION,
53
+          tag_string, NULL));
54
+      gst_pad_push_event (GST_BASE_SRC_PAD (pwsrc), tag_event);
55
+
56
+      pwsrc->transform_value = videotransform->transform;
57
+    }
58
+  }
59
+
60
   for (i = 0; i < b->buffer->n_datas; i++) {
61
     struct spa_data *d = &b->buffer->datasi;
62
     GstMemory *pmem = gst_buffer_peek_memory (data->buf, i);
63
@@ -913,7 +954,7 @@
64
   pwsrc->negotiated = pwsrc->caps != NULL;
65
 
66
   if (pwsrc->negotiated) {
67
-    const struct spa_pod *params3;
68
+    const struct spa_pod *params4;
69
     struct spa_pod_builder b = { NULL };
70
     uint8_t buffer512;
71
     uint32_t buffers = CLAMP (16, pwsrc->min_buffers, pwsrc->max_buffers);
72
@@ -939,9 +980,13 @@
73
         SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
74
         SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoCrop),
75
         SPA_PARAM_META_size, SPA_POD_Int(sizeof (struct spa_meta_region)));
76
+    params3 = spa_pod_builder_add_object (&b,
77
+        SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
78
+        SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform),
79
+        SPA_PARAM_META_size, SPA_POD_Int(sizeof (struct spa_meta_videotransform)));
80
 
81
     GST_DEBUG_OBJECT (pwsrc, "doing finish format");
82
-    pw_stream_update_params (pwsrc->stream, params, 3);
83
+    pw_stream_update_params (pwsrc->stream, params, SPA_N_ELEMENTS(params));
84
   } else {
85
     GST_WARNING_OBJECT (pwsrc, "finish format with error");
86
     pw_stream_set_error (pwsrc->stream, -EINVAL, "unhandled format");
87
pipewire-0.3.61.tar.gz/src/gst/gstpipewiresrc.h -> pipewire-0.3.62.tar.gz/src/gst/gstpipewiresrc.h Changed
10
 
1
@@ -95,6 +95,8 @@
2
   GstPipeWirePool *pool;
3
   GstClock *clock;
4
   GstClockTime last_time;
5
+
6
+  enum spa_meta_videotransform_value transform_value;
7
 };
8
 
9
 struct _GstPipeWireSrcClass {
10
pipewire-0.3.61.tar.gz/src/modules/meson.build -> pipewire-0.3.62.tar.gz/src/modules/meson.build Changed
16
 
1
@@ -289,6 +289,14 @@
2
   cdata.set('HAVE_AVAHI', true)
3
 endif
4
 
5
+if gio_dep.found()
6
+  pipewire_module_protocol_pulse_sources += 
7
+    'module-protocol-pulse/modules/module-gsettings.c',
8
+  
9
+  pipewire_module_protocol_pulse_deps += gio_dep
10
+  cdata.set('HAVE_GIO', true)
11
+endif
12
+
13
 if flatpak_support
14
   pipewire_module_protocol_pulse_deps += glib2_dep
15
 endif
16
pipewire-0.3.61.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.62.tar.gz/src/modules/module-client-node/remote-node.c Changed
10
 
1
@@ -1186,7 +1186,7 @@
2
    struct timespec ts;
3
    struct pw_impl_port *p;
4
 
5
-   pw_log_trace("node %p: ready driver:%d exported:%d status:%d", node,
6
+   pw_log_trace_fp("node %p: ready driver:%d exported:%d status:%d", node,
7
            node->driver, node->exported, status);
8
 
9
    if (status & SPA_STATUS_HAVE_DATA) {
10
pipewire-0.3.61.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.62.tar.gz/src/modules/module-echo-cancel.c Changed
17
 
1
@@ -936,8 +936,13 @@
2
 {
3
    struct impl *impl = data;
4
 
5
-   pw_log_error("error id:%u seq:%d res:%d (%s): %s",
6
-           id, seq, res, spa_strerror(res), message);
7
+   if (res == -ENOENT) {
8
+       pw_log_info("id:%u seq:%d res:%d (%s): %s",
9
+               id, seq, res, spa_strerror(res), message);
10
+   } else {
11
+       pw_log_warn("error id:%u seq:%d res:%d (%s): %s",
12
+               id, seq, res, spa_strerror(res), message);
13
+   }
14
 
15
    if (id == PW_ID_CORE && res == -EPIPE)
16
        pw_impl_module_schedule_destroy(impl->module);
17
pipewire-0.3.61.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.62.tar.gz/src/modules/module-filter-chain.c Changed
157
 
1
@@ -505,6 +505,7 @@
2
 
3
    unsigned int n_deps;
4
    unsigned int visited:1;
5
+   unsigned int disabled:1;
6
 };
7
 
8
 struct link {
9
@@ -521,6 +522,7 @@
10
    const struct fc_descriptor *desc;
11
    void **hndl;
12
    uint32_t port;
13
+   unsigned next:1;
14
 };
15
 
16
 struct graph_hndl {
17
@@ -599,7 +601,7 @@
18
    struct impl *impl = d;
19
    struct pw_buffer *in, *out;
20
    struct graph *graph = &impl->graph;
21
-   uint32_t i, insize = 0, outsize = 0, n_hndl = graph->n_hndl;
22
+   uint32_t i, j, insize = 0, outsize = 0, n_hndl = graph->n_hndl;
23
    int32_t stride = 0;
24
    struct graph_port *port;
25
    struct spa_data *bd;
26
@@ -613,7 +615,7 @@
27
    if (in == NULL || out == NULL)
28
        goto done;
29
 
30
-   for (i = 0; i < in->buffer->n_datas; i++) {
31
+   for (i = 0, j = 0; i < in->buffer->n_datas; i++) {
32
        uint32_t offs, size;
33
 
34
        bd = &in->buffer->datasi;
35
@@ -621,12 +623,15 @@
36
        offs = SPA_MIN(bd->chunk->offset, bd->maxsize);
37
        size = SPA_MIN(bd->chunk->size, bd->maxsize - offs);
38
 
39
-       port = i < graph->n_input ? &graph->inputi : NULL;
40
-
41
-       if (port && port->desc)
42
-           port->desc->connect_port(*port->hndl, port->port,
43
-               SPA_PTROFF(bd->data, offs, void));
44
+       while (j < graph->n_input) {
45
+           port = &graph->inputj++;
46
+           if (port->desc)
47
+               port->desc->connect_port(*port->hndl, port->port,
48
+                   SPA_PTROFF(bd->data, offs, void));
49
+           if (!port->next)
50
+               break;
51
 
52
+       }
53
        insize = i == 0 ? size : SPA_MIN(insize, size);
54
        stride = SPA_MAX(stride, bd->chunk->stride);
55
    }
56
@@ -1849,7 +1854,7 @@
57
        n_nodes++;
58
    }
59
    graph->n_input = 0;
60
-   graph->input = calloc(n_input * n_hndl, sizeof(struct graph_port));
61
+   graph->input = calloc(n_input * 16 * n_hndl, sizeof(struct graph_port));
62
    graph->n_output = 0;
63
    graph->output = calloc(n_output * n_hndl, sizeof(struct graph_port));
64
 
65
@@ -1869,8 +1874,8 @@
66
        } else {
67
            struct spa_json it = *inputs;
68
            while (spa_json_get_string(&it, v, sizeof(v)) > 0) {
69
-               gp = &graph->inputgraph->n_input;
70
                if (spa_streq(v, "null")) {
71
+                   gp = &graph->inputgraph->n_input++;
72
                    gp->desc = NULL;
73
                    pw_log_info("ignore input port %d", graph->n_input);
74
                } else if ((port = find_port(first, v, FC_PORT_INPUT)) == NULL) {
75
@@ -1893,14 +1898,41 @@
76
                        res = -EBUSY;
77
                        goto error;
78
                    }
79
-                   pw_log_info("input port %s%d:%s",
80
+
81
+                   if (d->flags & FC_DESCRIPTOR_COPY) {
82
+                       for (j = 0; j < desc->n_output; j++) {
83
+                           struct port *p = &port->node->output_portj;
84
+                           struct link *link;
85
+
86
+                           gp = NULL;
87
+                           spa_list_for_each(link, &p->link_list, output_link) {
88
+                               struct port *peer = link->input;
89
+
90
+                               pw_log_info("copy input port %s%d:%s",
91
+                                   port->node->name, i,
92
+                                   d->portsport->p.name);
93
+                               peer->external = graph->n_input;
94
+                               gp = &graph->inputgraph->n_input++;
95
+                               gp->desc = peer->node->desc->desc;
96
+                               gp->hndl = &peer->node->hndli;
97
+                               gp->port = peer->p;
98
+                               gp->next = true;
99
+                           }
100
+                           if (gp != NULL)
101
+                               gp->next = false;
102
+                       }
103
+                       port->node->disabled = true;
104
+                   } else {
105
+                       pw_log_info("input port %s%d:%s",
106
                            port->node->name, i, d->portsport->p.name);
107
-                   port->external = graph->n_input;
108
-                   gp->desc = d;
109
-                   gp->hndl = &port->node->hndli;
110
-                   gp->port = port->p;
111
+                       port->external = graph->n_input;
112
+                       gp = &graph->inputgraph->n_input++;
113
+                       gp->desc = d;
114
+                       gp->hndl = &port->node->hndli;
115
+                       gp->port = port->p;
116
+                       gp->next = false;
117
+                   }
118
                }
119
-               graph->n_input++;
120
            }
121
        }
122
        if (outputs == NULL) {
123
@@ -1965,11 +1997,12 @@
124
        desc = node->desc;
125
        d = desc->desc;
126
 
127
-       for (i = 0; i < n_hndl; i++) {
128
-           gh = &graph->hndlgraph->n_hndl++;
129
-           gh->hndl = &node->hndli;
130
-           gh->desc = d;
131
-
132
+       if (!node->disabled) {
133
+           for (i = 0; i < n_hndl; i++) {
134
+               gh = &graph->hndlgraph->n_hndl++;
135
+               gh->hndl = &node->hndli;
136
+               gh->desc = d;
137
+           }
138
        }
139
        for (i = 0; i < desc->n_output; i++) {
140
            spa_list_for_each(link, &node->output_porti.link_list, output_link)
141
@@ -2088,8 +2121,13 @@
142
 {
143
    struct impl *impl = data;
144
 
145
-   pw_log_error("error id:%u seq:%d res:%d (%s): %s",
146
-           id, seq, res, spa_strerror(res), message);
147
+   if (res == -ENOENT) {
148
+       pw_log_info("message id:%u seq:%d res:%d (%s): %s",
149
+               id, seq, res, spa_strerror(res), message);
150
+   } else {
151
+       pw_log_warn("error id:%u seq:%d res:%d (%s): %s",
152
+               id, seq, res, spa_strerror(res), message);
153
+   }
154
 
155
    if (id == PW_ID_CORE && res == -EPIPE)
156
        pw_impl_module_schedule_destroy(impl->module);
157
pipewire-0.3.61.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.62.tar.gz/src/modules/module-filter-chain/builtin_plugin.c Changed
56
 
1
@@ -101,6 +101,7 @@
2
 
3
 static const struct fc_descriptor copy_desc = {
4
    .name = "copy",
5
+   .flags = FC_DESCRIPTOR_COPY,
6
 
7
    .n_ports = 2,
8
    .ports = copy_ports,
9
@@ -260,14 +261,11 @@
10
 static void bq_run(struct builtin *impl, unsigned long samples, int type)
11
 {
12
    struct biquad *bq = &impl->bq;
13
-   unsigned long i;
14
    float *out = impl->port0;
15
    float *in = impl->port1;
16
    float freq = impl->port20;
17
    float Q = impl->port30;
18
    float gain = impl->port40;
19
-   float x1, x2, y1, y2;
20
-   float b0, b1, b2, a1, a2;
21
 
22
    if (impl->freq != freq || impl->Q != Q || impl->gain != gain) {
23
        impl->freq = freq;
24
@@ -275,30 +273,7 @@
25
        impl->gain = gain;
26
        biquad_set(bq, type, freq * 2 / impl->rate, Q, gain);
27
    }
28
-   x1 = bq->x1;
29
-   x2 = bq->x2;
30
-   y1 = bq->y1;
31
-   y2 = bq->y2;
32
-   b0 = bq->b0;
33
-   b1 = bq->b1;
34
-   b2 = bq->b2;
35
-   a1 = bq->a1;
36
-   a2 = bq->a2;
37
-   for (i = 0; i < samples; i++) {
38
-       float x = ini;
39
-       float y = b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;
40
-       outi = y;
41
-       x2 = x1;
42
-       x1 = x;
43
-       y2 = y1;
44
-       y1 = y;
45
-   }
46
-#define F(x) (-FLT_MIN < (x) && (x) < FLT_MIN ? 0.0f : (x))
47
-   bq->x1 = F(x1);
48
-   bq->x2 = F(x2);
49
-   bq->y1 = F(y1);
50
-   bq->y2 = F(y2);
51
-#undef F
52
+   dsp_ops_biquad_run(&dsp_ops, bq, out, in, samples);
53
 }
54
 
55
 /** bq_lowpass */
56
pipewire-0.3.61.tar.gz/src/modules/module-filter-chain/convolver.c -> pipewire-0.3.62.tar.gz/src/modules/module-filter-chain/convolver.c Changed
53
 
1
@@ -420,8 +420,6 @@
2
 
3
 int convolver_run(struct convolver *conv, const float *input, float *output, int length)
4
 {
5
-   int i;
6
-
7
    convolver1_run(conv->headConvolver, input, output, length);
8
 
9
    if (conv->tailInput) {
10
@@ -431,24 +429,14 @@
11
            int remaining = length - processed;
12
            int processing = SPA_MIN(remaining, conv->headBlockSize - (conv->tailInputFill % conv->headBlockSize));
13
 
14
-           const int sumBegin = processed;
15
-           const int sumEnd = processed + processing;
16
-
17
-           if (conv->tailPrecalculated0) {
18
-               int precalculatedPos = conv->precalculatedPos;
19
-               for (i = sumBegin; i < sumEnd; i++) {
20
-                   outputi += conv->tailPrecalculated0precalculatedPos;
21
-                   precalculatedPos++;
22
-               }
23
-           }
24
-
25
-           if (conv->tailPrecalculated) {
26
-               int precalculatedPos = conv->precalculatedPos;
27
-               for (i = sumBegin; i < sumEnd; i++) {
28
-                   outputi += conv->tailPrecalculatedprecalculatedPos;
29
-                   precalculatedPos++;
30
-               }
31
-           }
32
+           if (conv->tailPrecalculated0)
33
+               fft_sum(&outputprocessed, &outputprocessed,
34
+                       &conv->tailPrecalculated0conv->precalculatedPos,
35
+                       processing);
36
+           if (conv->tailPrecalculated)
37
+               fft_sum(&outputprocessed, &outputprocessed,
38
+                       &conv->tailPrecalculatedconv->precalculatedPos,
39
+                       processing);
40
            conv->precalculatedPos += processing;
41
 
42
            fft_copy(conv->tailInput + conv->tailInputFill, input + processed, processing);
43
@@ -467,7 +455,8 @@
44
            if (conv->tailPrecalculated &&
45
                conv->tailInputFill == conv->tailBlockSize) {
46
                SPA_SWAP(conv->tailPrecalculated, conv->tailOutput);
47
-               convolver1_run(conv->tailConvolver, conv->tailInput, conv->tailOutput, conv->tailBlockSize);
48
+               convolver1_run(conv->tailConvolver, conv->tailInput,
49
+                       conv->tailOutput, conv->tailBlockSize);
50
            }
51
            if (conv->tailInputFill == conv->tailBlockSize) {
52
                conv->tailInputFill = 0;
53
pipewire-0.3.61.tar.gz/src/modules/module-filter-chain/dsp-ops-c.c -> pipewire-0.3.62.tar.gz/src/modules/module-filter-chain/dsp-ops-c.c Changed
47
 
1
@@ -25,6 +25,7 @@
2
 #include <string.h>
3
 #include <stdio.h>
4
 #include <math.h>
5
+#include <float.h>
6
 
7
 #include <spa/utils/defs.h>
8
 
9
@@ -98,3 +99,37 @@
10
        }
11
    }
12
 }
13
+
14
+void dsp_biquad_run_c(struct dsp_ops *ops, struct biquad *bq,
15
+       float *out, const float *in, uint32_t n_samples)
16
+{
17
+   float x1, x2, y1, y2;
18
+   float b0, b1, b2, a1, a2;
19
+   uint32_t i;
20
+
21
+   x1 = bq->x1;
22
+   x2 = bq->x2;
23
+   y1 = bq->y1;
24
+   y2 = bq->y2;
25
+   b0 = bq->b0;
26
+   b1 = bq->b1;
27
+   b2 = bq->b2;
28
+   a1 = bq->a1;
29
+   a2 = bq->a2;
30
+   for (i = 0; i < n_samples; i++) {
31
+       float x = ini;
32
+       float y = b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2;
33
+       outi = y;
34
+       x2 = x1;
35
+       x1 = x;
36
+       y2 = y1;
37
+       y1 = y;
38
+   }
39
+#define F(x) (-FLT_MIN < (x) && (x) < FLT_MIN ? 0.0f : (x))
40
+   bq->x1 = F(x1);
41
+   bq->x2 = F(x2);
42
+   bq->y1 = F(y1);
43
+   bq->y2 = F(y2);
44
+#undef F
45
+}
46
+
47
pipewire-0.3.61.tar.gz/src/modules/module-filter-chain/dsp-ops.c -> pipewire-0.3.62.tar.gz/src/modules/module-filter-chain/dsp-ops.c Changed
32
 
1
@@ -42,6 +42,8 @@
2
            void * SPA_RESTRICT dst,
3
            const void * SPA_RESTRICT src,
4
            float gain, uint32_t n_src, uint32_t n_samples);
5
+   void (*biquad_run) (struct dsp_ops *ops, struct biquad *bq,
6
+           float *out, const float *in, uint32_t n_samples);
7
 };
8
 
9
 static struct dsp_info dsp_table =
10
@@ -50,11 +52,13 @@
11
    { SPA_CPU_FLAG_SSE,
12
        .copy = dsp_copy_c,
13
        .mix_gain = dsp_mix_gain_sse,
14
+       .biquad_run = dsp_biquad_run_c,
15
    },
16
 #endif
17
    { 0,
18
        .copy = dsp_copy_c,
19
        .mix_gain = dsp_mix_gain_c,
20
+       .biquad_run = dsp_biquad_run_c,
21
    },
22
 };
23
 
24
@@ -86,6 +90,7 @@
25
    ops->cpu_flags = info->cpu_flags;
26
    ops->copy = info->copy;
27
    ops->mix_gain = info->mix_gain;
28
+   ops->biquad_run = info->biquad_run;
29
    ops->free = impl_dsp_ops_free;
30
 
31
    return 0;
32
pipewire-0.3.61.tar.gz/src/modules/module-filter-chain/dsp-ops.h -> pipewire-0.3.62.tar.gz/src/modules/module-filter-chain/dsp-ops.h Changed
45
 
1
@@ -24,6 +24,8 @@
2
 
3
 #include <spa/utils/defs.h>
4
 
5
+#include "biquad.h"
6
+
7
 struct dsp_ops {
8
    uint32_t cpu_flags;
9
 
10
@@ -35,6 +37,8 @@
11
            void * SPA_RESTRICT dst,
12
            const void * SPA_RESTRICT src,
13
            float gain, uint32_t n_src, uint32_t n_samples);
14
+   void (*biquad_run) (struct dsp_ops *ops, struct biquad *bq,
15
+           float *out, const float *in, uint32_t n_samples);
16
    void (*free) (struct dsp_ops *ops);
17
 
18
    const void *priv;
19
@@ -44,19 +48,24 @@
20
 
21
 #define dsp_ops_copy(ops,...)      (ops)->copy(ops, __VA_ARGS__)
22
 #define dsp_ops_mix_gain(ops,...)  (ops)->mix_gain(ops, __VA_ARGS__)
23
+#define dsp_ops_biquad_run(ops,...)    (ops)->biquad_run(ops, __VA_ARGS__)
24
 #define dsp_ops_free(ops)      (ops)->free(ops)
25
 
26
 
27
 #define MAKE_COPY_FUNC(arch) \
28
 void dsp_copy_##arch(struct dsp_ops *ops, void * SPA_RESTRICT dst, \
29
-           const void * SPA_RESTRICT src, uint32_t n_samples)
30
+   const void * SPA_RESTRICT src, uint32_t n_samples)
31
 #define MAKE_MIX_GAIN_FUNC(arch) \
32
 void dsp_mix_gain_##arch(struct dsp_ops *ops, void * SPA_RESTRICT dst, \
33
    const void * SPA_RESTRICT src, float gain, uint32_t n_src, uint32_t n_samples)
34
+#define MAKE_BIQUAD_RUN_FUNC(arch) \
35
+void dsp_biquad_run_##arch (struct dsp_ops *ops, struct biquad *bq,    \
36
+   float *out, const float *in, uint32_t n_samples)
37
 
38
 
39
 MAKE_COPY_FUNC(c);
40
 MAKE_MIX_GAIN_FUNC(c);
41
+MAKE_BIQUAD_RUN_FUNC(c);
42
 #if defined (HAVE_SSE)
43
 MAKE_MIX_GAIN_FUNC(sse);
44
 #endif
45
pipewire-0.3.61.tar.gz/src/modules/module-filter-chain/plugin.h -> pipewire-0.3.62.tar.gz/src/modules/module-filter-chain/plugin.h Changed
9
 
1
@@ -64,6 +64,7 @@
2
 struct fc_descriptor {
3
    const char *name;
4
 #define FC_DESCRIPTOR_SUPPORTS_NULL_DATA   (1ULL << 0)
5
+#define FC_DESCRIPTOR_COPY         (1ULL << 1)
6
    uint64_t flags;
7
 
8
    void (*free) (const struct fc_descriptor *desc);
9
pipewire-0.3.61.tar.gz/src/modules/module-loopback.c -> pipewire-0.3.62.tar.gz/src/modules/module-loopback.c Changed
75
 
1
@@ -451,32 +451,31 @@
2
            &impl->playback_listener,
3
            &out_stream_events, impl);
4
 
5
+   /* connect playback first to activate it before capture triggers it */
6
    n_params = 0;
7
    spa_pod_builder_init(&b, buffer, sizeof(buffer));
8
    paramsn_params++ = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat,
9
-           &impl->capture_info);
10
-
11
-   if ((res = pw_stream_connect(impl->capture,
12
-           PW_DIRECTION_INPUT,
13
+           &impl->playback_info);
14
+   if ((res = pw_stream_connect(impl->playback,
15
+           PW_DIRECTION_OUTPUT,
16
            PW_ID_ANY,
17
            PW_STREAM_FLAG_AUTOCONNECT |
18
            PW_STREAM_FLAG_MAP_BUFFERS |
19
-           PW_STREAM_FLAG_RT_PROCESS,
20
+           PW_STREAM_FLAG_RT_PROCESS |
21
+           PW_STREAM_FLAG_TRIGGER,
22
            params, n_params)) < 0)
23
        return res;
24
 
25
    n_params = 0;
26
    spa_pod_builder_init(&b, buffer, sizeof(buffer));
27
    paramsn_params++ = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat,
28
-           &impl->playback_info);
29
-
30
-   if ((res = pw_stream_connect(impl->playback,
31
-           PW_DIRECTION_OUTPUT,
32
+           &impl->capture_info);
33
+   if ((res = pw_stream_connect(impl->capture,
34
+           PW_DIRECTION_INPUT,
35
            PW_ID_ANY,
36
            PW_STREAM_FLAG_AUTOCONNECT |
37
            PW_STREAM_FLAG_MAP_BUFFERS |
38
-           PW_STREAM_FLAG_RT_PROCESS |
39
-           PW_STREAM_FLAG_TRIGGER,
40
+           PW_STREAM_FLAG_RT_PROCESS,
41
            params, n_params)) < 0)
42
        return res;
43
 
44
@@ -487,8 +486,13 @@
45
 {
46
    struct impl *impl = data;
47
 
48
-   pw_log_error("error id:%u seq:%d res:%d (%s): %s",
49
-           id, seq, res, spa_strerror(res), message);
50
+   if (res == -ENOENT) {
51
+       pw_log_info("message id:%u seq:%d res:%d (%s): %s",
52
+               id, seq, res, spa_strerror(res), message);
53
+   } else {
54
+       pw_log_warn("error id:%u seq:%d res:%d (%s): %s",
55
+               id, seq, res, spa_strerror(res), message);
56
+   }
57
 
58
    if (id == PW_ID_CORE && res == -EPIPE)
59
        pw_impl_module_schedule_destroy(impl->module);
60
@@ -513,11 +517,11 @@
61
 
62
 static void impl_destroy(struct impl *impl)
63
 {
64
-   /* disconnect both streams before destroying any of them */
65
+   /* deactivate both streams before destroying any of them */
66
    if (impl->capture)
67
-       pw_stream_disconnect(impl->capture);
68
+       pw_stream_set_active(impl->capture, false);
69
    if (impl->playback)
70
-       pw_stream_disconnect(impl->playback);
71
+       pw_stream_set_active(impl->playback, false);
72
 
73
    if (impl->capture)
74
        pw_stream_destroy(impl->capture);
75
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/module.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/module.c Changed
47
 
1
@@ -36,7 +36,6 @@
2
 #include <pipewire/properties.h>
3
 #include <pipewire/work-queue.h>
4
 
5
-#include "client.h"
6
 #include "defs.h"
7
 #include "format.h"
8
 #include "internal.h"
9
@@ -84,14 +83,14 @@
10
    spa_hook_list_append(&module->listener_list, listener, events, data);
11
 }
12
 
13
-int module_load(struct client *client, struct module *module)
14
+int module_load(struct module *module)
15
 {
16
    pw_log_info("load module index:%u name:%s", module->index, module->info->name);
17
    if (module->info->load == NULL)
18
        return -ENOTSUP;
19
    /* subscription event is sent when the module does a
20
     * module_emit_loaded() */
21
-   return module->info->load(client, module);
22
+   return module->info->load(module);
23
 }
24
 
25
 void module_free(struct module *module)
26
@@ -119,9 +118,6 @@
27
    struct impl *impl = module->impl;
28
    int res = 0;
29
 
30
-   /* Note that client can be NULL (when the module is being unloaded
31
-    * internally and not by a client request */
32
-
33
    pw_log_info("unload module index:%u name:%s", module->index, module->info->name);
34
 
35
    if (module->info->unload)
36
@@ -283,9 +279,8 @@
37
    return spa_streq(module->info->name, name) ? 1 : 0;
38
 }
39
 
40
-struct module *module_create(struct client *client, const char *name, const char *args)
41
+struct module *module_create(struct impl *impl, const char *name, const char *args)
42
 {
43
-   struct impl *impl = client->impl;
44
    const struct module_info *info;
45
    struct module *module;
46
 
47
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/module.h -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/module.h Changed
30
 
1
@@ -29,7 +29,6 @@
2
 #include <spa/param/audio/raw.h>
3
 #include <spa/utils/hook.h>
4
 
5
-#include "client.h"
6
 #include "internal.h"
7
 
8
 struct module;
9
@@ -41,7 +40,7 @@
10
    unsigned int load_once:1;
11
 
12
    int (*prepare) (struct module *module);
13
-   int (*load) (struct client *client, struct module *module);
14
+   int (*load) (struct module *module);
15
    int (*unload) (struct module *module);
16
 
17
    const struct spa_dict *properties;
18
@@ -78,9 +77,9 @@
19
 #define module_emit_loaded(m,r) spa_hook_list_call(&m->listener_list, struct module_events, loaded, 0, r)
20
 #define module_emit_destroy(m) spa_hook_list_call(&(m)->listener_list, struct module_events, destroy, 0)
21
 
22
-struct module *module_create(struct client *client, const char *name, const char *args);
23
+struct module *module_create(struct impl *impl, const char *name, const char *args);
24
 void module_free(struct module *module);
25
-int module_load(struct client *client, struct module *module);
26
+int module_load(struct module *module);
27
 int module_unload(struct module *module);
28
 void module_schedule_unload(struct module *module);
29
 
30
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-always-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-always-sink.c Changed
10
 
1
@@ -51,7 +51,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_always_sink_load(struct client *client, struct module *module)
6
+static int module_always_sink_load(struct module *module)
7
 {
8
    struct module_always_sink_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-combine-sink.c Changed
21
 
1
@@ -391,7 +391,7 @@
2
    check_initialized(data);
3
 }
4
 
5
-static int module_combine_sink_load(struct client *client, struct module *module)
6
+static int module_combine_sink_load(struct module *module)
7
 {
8
    struct module_combine_sink_data *data = module->user_data;
9
    struct pw_properties *props;
10
@@ -402,9 +402,7 @@
11
    struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
12
    const char *str;
13
 
14
-   data->core = pw_context_connect(module->impl->context,
15
-           pw_properties_copy(client->props),
16
-           0);
17
+   data->core = pw_context_connect(module->impl->context, NULL, 0);
18
    if (data->core == NULL)
19
        return -errno;
20
 
21
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-echo-cancel.c Changed
10
 
1
@@ -63,7 +63,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_echo_cancel_load(struct client *client, struct module *module)
6
+static int module_echo_cancel_load(struct module *module)
7
 {
8
    struct module_echo_cancel_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-gsettings.c Added
201
 
1
@@ -0,0 +1,298 @@
2
+/* PipeWire
3
+ *
4
+ * Copyright © 2022 Wim Taymans <wim.taymans@gmail.com>
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 <gio/gio.h>
27
+#include <glib.h>
28
+
29
+#include <spa/debug/mem.h>
30
+#include <pipewire/pipewire.h>
31
+#include <pipewire/thread.h>
32
+
33
+#include "../module.h"
34
+
35
+#define NAME "gsettings"
36
+
37
+PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
38
+#define PW_LOG_TOPIC_DEFAULT mod_topic
39
+
40
+#define PA_GSETTINGS_MODULE_GROUP_SCHEMA "org.freedesktop.pulseaudio.module-group"
41
+#define PA_GSETTINGS_MODULE_GROUPS_SCHEMA "org.freedesktop.pulseaudio.module-groups"
42
+#define PA_GSETTINGS_MODULE_GROUPS_PATH "/org/freedesktop/pulseaudio/module-groups/"
43
+
44
+#define MAX_MODULES    10
45
+
46
+struct module_gsettings_data {
47
+   struct module *module;
48
+
49
+   GMainContext *context;
50
+   GMainLoop *loop;
51
+   struct spa_thread *thr;
52
+
53
+   GSettings *settings;
54
+   gchar **group_names;
55
+
56
+   struct spa_list groups;
57
+};
58
+
59
+struct group {
60
+   struct spa_list link;
61
+   char *name;
62
+   struct module *module;
63
+   struct spa_hook module_listener;
64
+};
65
+
66
+struct info {
67
+   bool enabled;
68
+   char *name;
69
+   char *moduleMAX_MODULES;
70
+   char *argsMAX_MODULES;
71
+};
72
+
73
+static void clean_info(const struct info *info)
74
+{
75
+   int i;
76
+   for (i = 0; i < MAX_MODULES; i++) {
77
+       g_free(info->modulei);
78
+       g_free(info->argsi);
79
+   }
80
+   g_free(info->name);
81
+}
82
+
83
+static void unload_module(struct module_gsettings_data *d, struct group *g)
84
+{
85
+   spa_list_remove(&g->link);
86
+   g_free(g->name);
87
+   if (g->module)
88
+       module_unload(g->module);
89
+   free(g);
90
+}
91
+
92
+static void unload_group(struct module_gsettings_data *d, const char *name)
93
+{
94
+   struct group *g, *t;
95
+   spa_list_for_each_safe(g, t, &d->groups, link) {
96
+       if (spa_streq(g->name, name))
97
+           unload_module(d, g);
98
+   }
99
+}
100
+static void module_destroy(void *data)
101
+{
102
+   struct group *g = data;
103
+   if (g->module) {
104
+       spa_hook_remove(&g->module_listener);
105
+       g->module = NULL;
106
+   }
107
+}
108
+
109
+static const struct module_events module_gsettings_events = {
110
+   VERSION_MODULE_EVENTS,
111
+   .destroy = module_destroy
112
+};
113
+
114
+static int load_group(struct module_gsettings_data *d, const struct info *info)
115
+{
116
+   struct group *g;
117
+   int i, res;
118
+
119
+   for (i = 0; i < MAX_MODULES; i++) {
120
+       if (info->modulei == NULL || strlen(info->modulei) <= 0)
121
+           break;
122
+
123
+       g = calloc(1, sizeof(struct group));
124
+       if (g == NULL)
125
+           return -errno;
126
+
127
+       g->name = strdup(info->name);
128
+       g->module = module_create(d->module->impl, info->modulei, info->argsi);
129
+       if (g->module == NULL) {
130
+           pw_log_info("can't create module:%s args:%s: %m",
131
+                   info->modulei, info->argsi);
132
+       } else {
133
+           module_add_listener(g->module, &g->module_listener,
134
+                   &module_gsettings_events, g);
135
+           if ((res = module_load(g->module)) < 0) {
136
+               pw_log_warn("can't load module:%s args:%s: %s",
137
+                       info->modulei, info->argsi,
138
+                       spa_strerror(res));
139
+           }
140
+       }
141
+       spa_list_append(&d->groups, &g->link);
142
+   }
143
+   return 0;
144
+}
145
+
146
+static int
147
+do_handle_info(struct spa_loop *loop,
148
+       bool async, uint32_t seq, const void *data, size_t size, void *user_data)
149
+{
150
+   struct module_gsettings_data *d = user_data;
151
+   const struct info *info = data;
152
+
153
+   unload_group(d, info->name);
154
+   if (info->enabled)
155
+       load_group(d, info);
156
+
157
+   clean_info(info);
158
+   return 0;
159
+}
160
+
161
+static void handle_module_group(struct module_gsettings_data *d, gchar *name)
162
+{
163
+   struct impl *impl = d->module->impl;
164
+   GSettings *settings;
165
+   gchar p1024;
166
+   struct info info;
167
+   int i;
168
+
169
+   snprintf(p, sizeof(p), PA_GSETTINGS_MODULE_GROUPS_PATH"%s/", name);
170
+
171
+   settings = g_settings_new_with_path(PA_GSETTINGS_MODULE_GROUP_SCHEMA, p);
172
+   if (settings == NULL)
173
+       return;
174
+
175
+   spa_zero(info);
176
+   info.name = strdup(p);
177
+   info.enabled = g_settings_get_boolean(settings, "enabled");
178
+
179
+   for (i = 0; i < MAX_MODULES; i++) {
180
+       snprintf(p, sizeof(p), "name%d", i);
181
+       info.modulei = g_settings_get_string(settings, p);
182
+
183
+       snprintf(p, sizeof(p), "args%i", i);
184
+       info.argsi = g_settings_get_string(settings, p);
185
+   }
186
+   pw_loop_invoke(impl->loop, do_handle_info, 0,
187
+           &info, sizeof(info), false, d);
188
+
189
+   g_object_unref(G_OBJECT(settings));
190
+}
191
+
192
+static void module_group_callback(GSettings *settings, gchar *key, gpointer user_data)
193
+{
194
+   struct module_gsettings_data *d = g_object_get_data(G_OBJECT(settings), "module-data");
195
+   handle_module_group(d, user_data);
196
+}
197
+
198
+static void *do_loop(void *user_data)
199
+{
200
+   struct module_gsettings_data *d = user_data;
201
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-sink.c Changed
10
 
1
@@ -59,7 +59,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_ladspa_sink_load(struct client *client, struct module *module)
6
+static int module_ladspa_sink_load(struct module *module)
7
 {
8
    struct module_ladspa_sink_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-ladspa-source.c Changed
10
 
1
@@ -59,7 +59,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_ladspa_source_load(struct client *client, struct module *module)
6
+static int module_ladspa_source_load(struct module *module)
7
 {
8
    struct module_ladspa_source_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-loopback.c Changed
10
 
1
@@ -63,7 +63,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_loopback_load(struct client *client, struct module *module)
6
+static int module_loopback_load(struct module *module)
7
 {
8
    struct module_loopback_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-native-protocol-tcp.c Changed
14
 
1
@@ -38,10 +38,10 @@
2
    struct pw_array servers;
3
 };
4
 
5
-static int module_native_protocol_tcp_load(struct client *client, struct module *module)
6
+static int module_native_protocol_tcp_load(struct module *module)
7
 {
8
    struct module_native_protocol_tcp_data *data = module->user_data;
9
-   struct impl *impl = client->impl;
10
+   struct impl *impl = module->impl;
11
    const char *address;
12
    int res;
13
 
14
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-null-sink.c Changed
15
 
1
@@ -104,11 +104,11 @@
2
    .error = module_null_sink_core_error,
3
 };
4
 
5
-static int module_null_sink_load(struct client *client, struct module *module)
6
+static int module_null_sink_load(struct module *module)
7
 {
8
    struct module_null_sink_data *d = module->user_data;
9
 
10
-   d->core = pw_context_connect(module->impl->context, pw_properties_copy(client->props), 0);
11
+   d->core = pw_context_connect(module->impl->context, NULL, 0);
12
    if (d->core == NULL)
13
        return -errno;
14
 
15
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-sink.c Changed
10
 
1
@@ -64,7 +64,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_pipe_sink_load(struct client *client, struct module *module)
6
+static int module_pipe_sink_load(struct module *module)
7
 {
8
    struct module_pipesink_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-pipe-source.c Changed
10
 
1
@@ -64,7 +64,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_pipe_source_load(struct client *client, struct module *module)
6
+static int module_pipe_source_load(struct module *module)
7
 {
8
    struct module_pipesrc_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-raop-discover.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-raop-discover.c Changed
10
 
1
@@ -55,7 +55,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_raop_discover_load(struct client *client, struct module *module)
6
+static int module_raop_discover_load(struct module *module)
7
 {
8
    struct module_raop_discover_data *data = module->user_data;
9
 
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-sink.c Changed
10
 
1
@@ -59,7 +59,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_remap_sink_load(struct client *client, struct module *module)
6
+static int module_remap_sink_load(struct module *module)
7
 {
8
    struct module_remap_sink_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-remap-source.c Changed
10
 
1
@@ -59,7 +59,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_remap_source_load(struct client *client, struct module *module)
6
+static int module_remap_source_load(struct module *module)
7
 {
8
    struct module_remap_source_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink-input.c Changed
10
 
1
@@ -58,7 +58,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_roc_sink_input_load(struct client *client, struct module *module)
6
+static int module_roc_sink_input_load(struct module *module)
7
 {
8
    struct module_roc_sink_input_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-sink.c Changed
10
 
1
@@ -58,7 +58,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_roc_sink_load(struct client *client, struct module *module)
6
+static int module_roc_sink_load(struct module *module)
7
 {
8
    struct module_roc_sink_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-roc-source.c Changed
10
 
1
@@ -58,7 +58,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_roc_source_load(struct client *client, struct module *module)
6
+static int module_roc_source_load(struct module *module)
7
 {
8
    struct module_roc_source_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-recv.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-recv.c Changed
10
 
1
@@ -57,7 +57,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_rtp_recv_load(struct client *client, struct module *module)
6
+static int module_rtp_recv_load(struct module *module)
7
 {
8
    struct module_rtp_recv_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-send.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-rtp-send.c Changed
10
 
1
@@ -58,7 +58,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_rtp_send_load(struct client *client, struct module *module)
6
+static int module_rtp_send_load(struct module *module)
7
 {
8
    struct module_rtp_send_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-simple-protocol-tcp.c Changed
14
 
1
@@ -58,10 +58,10 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_simple_protocol_tcp_load(struct client *client, struct module *module)
6
+static int module_simple_protocol_tcp_load(struct module *module)
7
 {
8
    struct module_simple_protocol_tcp_data *data = module->user_data;
9
-   struct impl *impl = client->impl;
10
+   struct impl *impl = module->impl;
11
    char *args;
12
    size_t size;
13
    uint32_t i;
14
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-switch-on-connect.c Changed
18
 
1
@@ -175,13 +175,13 @@
2
    .done = on_core_done,
3
 };
4
 
5
-static int module_switch_on_connect_load(struct client *client, struct module *module)
6
+static int module_switch_on_connect_load(struct module *module)
7
 {
8
-   struct impl *impl = client->impl;
9
+   struct impl *impl = module->impl;
10
    struct module_switch_on_connect_data *d = module->user_data;
11
    int res;
12
 
13
-   d->core = pw_context_connect(impl->context, pw_properties_copy(client->props), 0);
14
+   d->core = pw_context_connect(impl->context, NULL, 0);
15
    if (d->core == NULL) {
16
        res = -errno;
17
        goto error;
18
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-sink.c Changed
10
 
1
@@ -62,7 +62,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_tunnel_sink_load(struct client *client, struct module *module)
6
+static int module_tunnel_sink_load(struct module *module)
7
 {
8
    struct module_tunnel_sink_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-tunnel-source.c Changed
10
 
1
@@ -62,7 +62,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_tunnel_source_load(struct client *client, struct module *module)
6
+static int module_tunnel_source_load(struct module *module)
7
 {
8
    struct module_tunnel_source_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-x11-bell.c Changed
10
 
1
@@ -51,7 +51,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_x11_bell_load(struct client *client, struct module *module)
6
+static int module_x11_bell_load(struct module *module)
7
 {
8
    struct module_x11_bell_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-discover.c Changed
10
 
1
@@ -57,7 +57,7 @@
2
    .destroy = module_destroy
3
 };
4
 
5
-static int module_zeroconf_discover_load(struct client *client, struct module *module)
6
+static int module_zeroconf_discover_load(struct module *module)
7
 {
8
    struct module_zeroconf_discover_data *data = module->user_data;
9
    FILE *f;
10
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c Changed
99
 
1
@@ -73,6 +73,7 @@
2
 
3
    AvahiEntryGroup *entry_group;
4
    AvahiStringList *txt;
5
+   struct server *server;
6
 
7
    const char *service_type;
8
    enum service_subtype subtype;
9
@@ -154,6 +155,7 @@
10
    spa_list_remove(&s->link);
11
    spa_list_append(&s->userdata->pending, &s->link);
12
    s->published = false;
13
+   s->server = NULL;
14
 }
15
 
16
 static void unpublish_all_services(struct module_zeroconf_publish_data *d)
17
@@ -397,7 +399,7 @@
18
    return txt;
19
 }
20
 
21
-static int find_port(struct service *s, int *proto, uint16_t *port)
22
+static struct server *find_server(struct service *s, int *proto, uint16_t *port)
23
 {
24
    struct module_zeroconf_publish_data *d = s->userdata;
25
    struct impl *impl = d->module->impl;
26
@@ -407,14 +409,15 @@
27
        if (server->addr.ss_family == AF_INET) {
28
            *proto = AVAHI_PROTO_INET;
29
            *port = ntohs(((struct sockaddr_in*) &server->addr)->sin_port);
30
-           return 0;
31
+           return server;
32
        } else if (server->addr.ss_family == AF_INET6) {
33
            *proto = AVAHI_PROTO_INET6;
34
            *port = ntohs(((struct sockaddr_in6*) &server->addr)->sin6_port);
35
-           return 0;
36
+           return server;
37
        }
38
    }
39
-   return -ENODEV;
40
+
41
+   return NULL;
42
 }
43
 
44
 static void publish_service(struct service *s)
45
@@ -423,10 +426,11 @@
46
    int proto;
47
    uint16_t port;
48
 
49
-   if (find_port(s, &proto, &port) < 0)
50
+   struct server *server = find_server(s, &proto, &port);
51
+   if (!server)
52
        return;
53
 
54
-   pw_log_debug("found proto:%d port:%d", proto, port);
55
+   pw_log_debug("found server:%p proto:%d port:%d", server, proto, port);
56
 
57
    if (!d->client || avahi_client_get_state(d->client) != AVAHI_CLIENT_S_RUNNING)
58
        return;
59
@@ -499,6 +503,7 @@
60
 
61
    spa_list_remove(&s->link);
62
    spa_list_append(&d->published, &s->link);
63
+   s->server = server;
64
 
65
    pw_log_info("created service: %s", s->service_name);
66
    return;
67
@@ -626,7 +631,13 @@
68
 {
69
    struct module_zeroconf_publish_data *d = data;
70
    pw_log_info("a server stopped, try republish");
71
-   unpublish_all_services(d);
72
+
73
+   struct service *s, *tmp;
74
+   spa_list_for_each_safe(s, tmp, &d->published, link) {
75
+       if (s->server == server)
76
+           unpublish_service(s);
77
+   }
78
+
79
    publish_pending(d);
80
 }
81
 
82
@@ -636,14 +647,13 @@
83
    .server_stopped = impl_server_stopped,
84
 };
85
 
86
-static int module_zeroconf_publish_load(struct client *client, struct module *module)
87
+static int module_zeroconf_publish_load(struct module *module)
88
 {
89
    struct module_zeroconf_publish_data *data = module->user_data;
90
    struct pw_loop *loop;
91
    int error;
92
 
93
-   data->core = pw_context_connect(module->impl->context,
94
-           pw_properties_copy(client->props), 0);
95
+   data->core = pw_context_connect(module->impl->context, NULL, 0);
96
    if (data->core == NULL) {
97
        pw_log_error("failed to connect to pipewire: %m");
98
        return -errno;
99
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/pulse-server.c Changed
36
 
1
@@ -85,7 +85,7 @@
2
 #define DEFAULT_MIN_QUANTUM    "256/48000"
3
 #define DEFAULT_FORMAT     "F32"
4
 #define DEFAULT_POSITION   " FL FR "
5
-#define DEFAULT_IDLE_TIMEOUT   "5"
6
+#define DEFAULT_IDLE_TIMEOUT   "0"
7
 
8
 #define MAX_FORMATS    32
9
 /* The max amount of data we send in one block when capturing. In PulseAudio this
10
@@ -5131,6 +5131,7 @@
11
        .sync = on_load_module_manager_sync,
12
    };
13
 
14
+   struct impl *impl = client->impl;
15
    const char *name, *argument;
16
    struct module *module;
17
    struct pending_module *pm;
18
@@ -5145,7 +5146,7 @@
19
    pw_log_info("%s %s name:%s argument:%s",
20
            client->name, commandscommand.name, name, argument);
21
 
22
-   module = module_create(client, name, argument);
23
+   module = module_create(impl, name, argument);
24
    if (module == NULL)
25
        return -errno;
26
 
27
@@ -5159,7 +5160,7 @@
28
 
29
    pw_log_debug("pending module %p: start tag:%d", pm, tag);
30
 
31
-   r = module_load(client, module);
32
+   r = module_load(module);
33
 
34
    module_add_listener(module, &pm->module_listener, &module_events, pm);
35
    client_add_listener(client, &pm->client_listener, &client_events, pm);
36
pipewire-0.3.61.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.62.tar.gz/src/modules/module-protocol-pulse/server.c Changed
20
 
1
@@ -823,13 +823,14 @@
2
    if (len < 2)
3
        return -ENOSPC;
4
 
5
-   snprintf(ip, sizeof(ip), ":::%d", res);
6
-   spa_assert_se(parse_ipv6_address(ip, (struct sockaddr_in6 *) &addr) == 0);
7
-   addrs0 = addr;
8
-
9
    snprintf(ip, sizeof(ip), "0.0.0.0:%d", res);
10
    spa_assert_se(parse_ipv4_address(ip, (struct sockaddr_in *) &addr) == 0);
11
+   addrs0 = addr;
12
+
13
+   snprintf(ip, sizeof(ip), ":::%d", res);
14
+   spa_assert_se(parse_ipv6_address(ip, (struct sockaddr_in6 *) &addr) == 0);
15
    addrs1 = addr;
16
+
17
    return 2;
18
 }
19
 
20
pipewire-0.3.61.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.62.tar.gz/src/modules/module-pulse-tunnel.c Changed
113
 
1
@@ -189,6 +189,7 @@
2
    uint32_t target_latency;
3
    uint32_t current_latency;
4
    uint32_t target_buffer;
5
+   struct spa_io_rate_match *rate_match;
6
    struct spa_dll dll;
7
    float max_error;
8
    unsigned resync:1;
9
@@ -250,6 +251,28 @@
10
    }
11
 }
12
 
13
+static void update_rate(struct impl *impl, bool playback)
14
+{
15
+   float error, corr;
16
+
17
+   if (impl->rate_match == NULL)
18
+       return;
19
+
20
+   if (playback)
21
+       error = (float)impl->target_latency - (float)impl->current_latency;
22
+   else
23
+       error = (float)impl->current_latency - (float)impl->target_latency;
24
+   error = SPA_CLAMP(error, -impl->max_error, impl->max_error);
25
+
26
+   corr = spa_dll_update(&impl->dll, error);
27
+   pw_log_debug("error:%f corr:%f current:%u target:%u",
28
+           error, corr,
29
+           impl->current_latency, impl->target_latency);
30
+
31
+   SPA_FLAG_SET(impl->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE);
32
+   impl->rate_match->rate = corr;
33
+}
34
+
35
 static void playback_stream_process(void *d)
36
 {
37
    struct impl *impl = d;
38
@@ -279,17 +302,7 @@
39
                                         size, RINGBUFFER_SIZE);
40
        impl->resync = true;
41
    } else {
42
-       float error, corr;
43
-
44
-       error = (float)impl->target_latency - (float)impl->current_latency;
45
-       error = SPA_CLAMP(error, -impl->max_error, impl->max_error);
46
-
47
-       corr = spa_dll_update(&impl->dll, error);
48
-       pw_log_debug("filled:%u target:%u error:%f corr:%f %u %u", filled,
49
-               impl->target_buffer, error, corr,
50
-               impl->current_latency, impl->target_latency);
51
-       pw_stream_set_control(impl->stream,
52
-               SPA_PROP_rate, 1, &corr, NULL);
53
+       update_rate(impl, true);
54
    }
55
    spa_ringbuffer_write_data(&impl->ring,
56
                impl->buffer, RINGBUFFER_SIZE,
57
@@ -326,24 +339,12 @@
58
    if (avail < (int32_t)size) {
59
        memset(bd->data, 0, size);
60
    } else {
61
-       float error, corr;
62
-
63
        if (avail > (int32_t)RINGBUFFER_SIZE) {
64
            avail = impl->target_buffer;
65
            index += avail - impl->target_buffer;
66
        } else {
67
-           error = (float)(impl->current_latency) - (float)impl->target_latency;
68
-           error = SPA_CLAMP(error, -impl->max_error, impl->max_error);
69
-
70
-           corr = spa_dll_update(&impl->dll, error);
71
-
72
-           pw_log_debug("avail:%u target:%u error:%f corr:%f %u %u", avail,
73
-                   impl->target_buffer, error, corr,
74
-                   impl->current_latency, impl->target_latency);
75
-           pw_stream_set_control(impl->stream,
76
-                   SPA_PROP_rate, 1, &corr, NULL);
77
+           update_rate(impl, false);
78
        }
79
-
80
        spa_ringbuffer_read_data(&impl->ring,
81
                impl->buffer, RINGBUFFER_SIZE,
82
                index & RINGBUFFER_MASK,
83
@@ -359,10 +360,21 @@
84
    pw_stream_queue_buffer(impl->stream, buf);
85
 }
86
 
87
+static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size)
88
+{
89
+   struct impl *impl = data;
90
+   switch (id) {
91
+   case SPA_IO_RateMatch:
92
+       impl->rate_match = area;
93
+       break;
94
+   }
95
+}
96
+
97
 static const struct pw_stream_events playback_stream_events = {
98
    PW_VERSION_STREAM_EVENTS,
99
    .destroy = stream_destroy,
100
    .state_changed = stream_state_changed,
101
+   .io_changed = stream_io_changed,
102
    .process = playback_stream_process
103
 };
104
 
105
@@ -370,6 +382,7 @@
106
    PW_VERSION_STREAM_EVENTS,
107
    .destroy = stream_destroy,
108
    .state_changed = stream_state_changed,
109
+   .io_changed = stream_io_changed,
110
    .process = capture_stream_process
111
 };
112
 
113
pipewire-0.3.61.tar.gz/src/modules/module-rtp-sink.c -> pipewire-0.3.62.tar.gz/src/modules/module-rtp-sink.c Changed
21
 
1
@@ -306,8 +306,17 @@
2
            &iov1, tosend);
3
 
4
        n = sendmsg(impl->rtp_fd, &msg, MSG_NOSIGNAL);
5
-       if (n < 0)
6
-           pw_log_warn("sendmsg() failed: %m");
7
+       if (n < 0) {
8
+           switch (errno) {
9
+           case ECONNREFUSED:
10
+           case ECONNRESET:
11
+               pw_log_debug("remote end not listening");
12
+               break;
13
+           default:
14
+               pw_log_warn("sendmsg() failed: %m");
15
+               break;
16
+           }
17
+       }
18
 
19
        impl->seq++;
20
        impl->timestamp += tosend / impl->frame_size;
21
pipewire-0.3.61.tar.gz/src/modules/module-rtp-source.c -> pipewire-0.3.62.tar.gz/src/modules/module-rtp-source.c Changed
44
 
1
@@ -214,6 +214,7 @@
2
    struct spa_ringbuffer ring;
3
    uint8_t bufferBUFFER_SIZE;
4
 
5
+   struct spa_io_rate_match *rate_match;
6
    struct spa_dll dll;
7
    uint32_t target_buffer;
8
    float max_error;
9
@@ -269,8 +270,10 @@
10
            pw_log_debug("avail:%u target:%u error:%f corr:%f", avail,
11
                    sess->target_buffer, error, corr);
12
 
13
-           pw_stream_set_control(sess->stream,
14
-                   SPA_PROP_rate, 1, &corr, NULL);
15
+           if (sess->rate_match) {
16
+               SPA_FLAG_SET(sess->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE);
17
+               sess->rate_match->rate = corr;
18
+           }
19
        }
20
        spa_ringbuffer_read_data(&sess->ring,
21
                sess->buffer,
22
@@ -308,10 +311,21 @@
23
    }
24
 }
25
 
26
+static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size)
27
+{
28
+   struct session *sess = data;
29
+   switch (id) {
30
+   case SPA_IO_RateMatch:
31
+       sess->rate_match = area;
32
+       break;
33
+   }
34
+}
35
+
36
 static const struct pw_stream_events out_stream_events = {
37
    PW_VERSION_STREAM_EVENTS,
38
    .destroy = stream_destroy,
39
    .state_changed = on_stream_state_changed,
40
+   .io_changed = stream_io_changed,
41
    .process = stream_process
42
 };
43
 
44
pipewire-0.3.61.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.62.tar.gz/src/pipewire/impl-link.c Changed
21
 
1
@@ -622,8 +622,8 @@
2
    pw_log_debug("%p: activate activated:%d state:%s", this, impl->activated,
3
            pw_link_state_as_string(this->info.state));
4
 
5
-   if (impl->activated || !this->prepared || !impl->inode->active ||
6
-           !impl->inode->added || !impl->onode->active)
7
+   if (impl->activated || !this->prepared ||
8
+       !impl->inode->active || !impl->onode->active)
9
        return 0;
10
 
11
    if (!impl->io_set) {
12
@@ -812,7 +812,7 @@
13
    spa_list_remove(&this->rt.out_mix.rt_link);
14
    spa_list_remove(&this->rt.in_mix.rt_link);
15
 
16
-   if (this->input->node != this->output->node) {
17
+   if (impl->inode != impl->onode) {
18
        struct pw_node_activation_state *state;
19
 
20
        spa_list_remove(&this->rt.target.link);
21
pipewire-0.3.61.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.62.tar.gz/src/pipewire/impl-node.c Changed
201
 
1
@@ -158,12 +158,51 @@
2
    this->rt.driver_target.node = NULL;
3
 }
4
 
5
+static int
6
+do_node_add(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
7
+{
8
+   struct pw_impl_node *this = user_data;
9
+   struct pw_impl_node *driver = this->driver_node;
10
+
11
+   this->added = true;
12
+   if (this->source.loop == NULL) {
13
+       struct spa_system *data_system = this->context->data_system;
14
+       uint64_t dummy;
15
+       int res;
16
+
17
+       /* clear the eventfd in case it was written to while the node was stopped */
18
+       res = spa_system_eventfd_read(data_system, this->source.fd, &dummy);
19
+       if (SPA_UNLIKELY(res != -EAGAIN && res != 0))
20
+           pw_log_warn("%p: read failed %m", this);
21
+
22
+       spa_loop_add_source(loop, &this->source);
23
+       add_node(this, driver);
24
+   }
25
+   return 0;
26
+}
27
+
28
+static int
29
+do_node_remove(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data)
30
+{
31
+   struct pw_impl_node *this = user_data;
32
+   if (this->source.loop != NULL) {
33
+       spa_loop_remove_source(loop, &this->source);
34
+       remove_node(this);
35
+   }
36
+   this->added = false;
37
+   return 0;
38
+}
39
+
40
 static void node_deactivate(struct pw_impl_node *this)
41
 {
42
    struct pw_impl_port *port;
43
    struct pw_impl_link *link;
44
 
45
    pw_log_debug("%p: deactivate", this);
46
+
47
+   /* make sure the node doesn't get woken up while not active */
48
+   pw_loop_invoke(this->data_loop, do_node_remove, 1, NULL, 0, true, this);
49
+
50
    spa_list_for_each(port, &this->input_ports, link) {
51
        spa_list_for_each(link, &port->links, input_link)
52
            pw_impl_link_deactivate(link);
53
@@ -200,7 +239,7 @@
54
    return res;
55
 }
56
 
57
-static void node_activate_outputs(struct pw_impl_node *this)
58
+static void node_activate(struct pw_impl_node *this)
59
 {
60
    struct pw_impl_port *port;
61
 
62
@@ -210,13 +249,6 @@
63
        spa_list_for_each(link, &port->links, output_link)
64
            pw_impl_link_activate(link);
65
    }
66
-}
67
-
68
-static void node_activate_inputs(struct pw_impl_node *this)
69
-{
70
-   struct pw_impl_port *port;
71
-
72
-   pw_log_debug("%p: activate", this);
73
    spa_list_for_each(port, &this->input_ports, link) {
74
        struct pw_impl_link *link;
75
        spa_list_for_each(link, &port->links, input_link)
76
@@ -229,9 +261,7 @@
77
    struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
78
    int res = 0;
79
 
80
-   /* First activate the outputs so that when the node starts pushing,
81
-    * we can process the outputs */
82
-   node_activate_outputs(this);
83
+   node_activate(this);
84
 
85
    if (impl->pending_state >= PW_NODE_STATE_RUNNING)
86
        return 0;
87
@@ -243,6 +273,10 @@
88
        impl->pending_play = true;
89
        res = spa_node_send_command(this->node,
90
            &SPA_NODE_COMMAND_INIT(SPA_NODE_COMMAND_Start));
91
+   } else {
92
+       /* driver nodes will wait until all other nodes are started before
93
+        * they are started */
94
+       res = EBUSY;
95
    }
96
 
97
    if (res < 0)
98
@@ -325,34 +359,6 @@
99
    }
100
 }
101
 
102
-static int
103
-do_node_add(struct spa_loop *loop,
104
-       bool async, uint32_t seq, const void *data, size_t size, void *user_data)
105
-{
106
-   struct pw_impl_node *this = user_data;
107
-   struct pw_impl_node *driver = this->driver_node;
108
-
109
-   if (this->source.loop == NULL) {
110
-       spa_loop_add_source(loop, &this->source);
111
-       add_node(this, driver);
112
-   }
113
-   this->added = true;
114
-   return 0;
115
-}
116
-
117
-static int
118
-do_node_remove(struct spa_loop *loop,
119
-          bool async, uint32_t seq, const void *data, size_t size, void *user_data)
120
-{
121
-   struct pw_impl_node *this = user_data;
122
-   if (this->source.loop != NULL) {
123
-       spa_loop_remove_source(loop, &this->source);
124
-       remove_node(this);
125
-   }
126
-   this->added = false;
127
-   return 0;
128
-}
129
-
130
 static void node_update_state(struct pw_impl_node *node, enum pw_node_state state, int res, char *error)
131
 {
132
    struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this);
133
@@ -375,10 +381,6 @@
134
                pw_loop_invoke(node->data_loop, do_node_remove, 1, NULL, 0, true, node);
135
            }
136
        }
137
-       if (res >= 0) {
138
-           /* now activate the inputs */
139
-           node_activate_inputs(node);
140
-       }
141
        break;
142
    case PW_NODE_STATE_IDLE:
143
    case PW_NODE_STATE_SUSPENDED:
144
@@ -807,17 +809,9 @@
145
    struct impl *impl = user_data;
146
    struct pw_impl_node *driver = *(struct pw_impl_node **)data;
147
    struct pw_impl_node *node = &impl->this;
148
-   int res;
149
 
150
    pw_log_trace("%p: driver:%p->%p", node, node->driver_node, driver);
151
 
152
-   if ((res = spa_node_set_io(node->node,
153
-           SPA_IO_Position,
154
-           &driver->rt.activation->position,
155
-           sizeof(struct spa_io_position))) < 0) {
156
-       pw_log_debug("%p: set position: %s", node, spa_strerror(res));
157
-   }
158
-
159
    pw_log_trace("%p: set position %p", node, &driver->rt.activation->position);
160
    node->rt.position = &driver->rt.activation->position;
161
 
162
@@ -843,6 +837,8 @@
163
 {
164
    struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this);
165
    struct pw_impl_node *old = node->driver_node;
166
+   int res;
167
+   bool was_driving;
168
 
169
    if (driver == NULL)
170
        driver = node;
171
@@ -865,8 +861,16 @@
172
                old->name, old->info.id,
173
                driver->name, driver->info.id);
174
    }
175
+   was_driving = node->driving;
176
    node->driving = node->driver && driver == node;
177
 
178
+   /* When a node was driver (and is waiting for all nodes to complete
179
+    * the Start command) cancel the pending state and let the new driver
180
+    * calculate a new state so that the Start command is sent to the
181
+    * node */
182
+   if (was_driving && !node->driving)
183
+       impl->pending_state = node->info.state;
184
+
185
    pw_log_debug("%p: driver %p driving:%u", node,
186
        driver, node->driving);
187
    pw_log_info("(%s-%u) -> change driver (%s-%d -> %s-%d)",
188
@@ -876,6 +880,13 @@
189
    node->driver_node = driver;
190
    node->moved = true;
191
 
192
+   if ((res = spa_node_set_io(node->node,
193
+           SPA_IO_Position,
194
+           &driver->rt.activation->position,
195
+           sizeof(struct spa_io_position))) < 0) {
196
+       pw_log_debug("%p: set position: %s", node, spa_strerror(res));
197
+   }
198
+
199
    pw_loop_invoke(node->data_loop,
200
               do_move_nodes, SPA_ID_INVALID, &driver, sizeof(struct pw_impl_node *),
201
pipewire-0.3.61.tar.gz/src/pipewire/stream.c -> pipewire-0.3.62.tar.gz/src/pipewire/stream.c Changed
67
 
1
@@ -324,7 +324,8 @@
2
 {
3
    uint32_t index;
4
 
5
-   if (SPA_FLAG_IS_SET(buffer->flags, BUFFER_FLAG_QUEUED))
6
+   if (SPA_FLAG_IS_SET(buffer->flags, BUFFER_FLAG_QUEUED) ||
7
+       buffer->id >= stream->n_buffers)
8
        return -EINVAL;
9
 
10
    SPA_FLAG_SET(buffer->flags, BUFFER_FLAG_QUEUED);
11
@@ -921,6 +922,9 @@
12
    if (impl->disconnecting && n_buffers > 0)
13
        return -EIO;
14
 
15
+   if (n_buffers > MAX_BUFFERS)
16
+       return -EINVAL;
17
+
18
    prot = PROT_READ | (direction == SPA_DIRECTION_OUTPUT ? PROT_WRITE : 0);
19
 
20
    clear_buffers(stream);
21
@@ -956,6 +960,7 @@
22
        pw_log_debug("%p: got buffer id:%d datas:%d, mapped size %d", stream, i,
23
                buffersi->n_datas, size);
24
    }
25
+   impl->n_buffers = n_buffers;
26
 
27
    for (i = 0; i < n_buffers; i++) {
28
        struct buffer *b = &impl->buffersi;
29
@@ -972,9 +977,6 @@
30
 
31
        pw_stream_emit_add_buffer(stream, &b->this);
32
    }
33
-
34
-   impl->n_buffers = n_buffers;
35
-
36
    return 0;
37
 }
38
 
39
@@ -1000,6 +1002,7 @@
40
    if (io->status == SPA_STATUS_HAVE_DATA &&
41
        (b = get_buffer(stream, io->buffer_id)) != NULL) {
42
        /* push new buffer */
43
+       pw_log_trace_fp("%p: push %d %p", stream, b->id, io);
44
        if (queue_push(impl, &impl->dequeued, b) == 0) {
45
            copy_position(impl, impl->dequeued.incount);
46
            if (b->busy)
47
@@ -1007,13 +1010,15 @@
48
            call_process(impl);
49
        }
50
    }
51
-   if (io->status != SPA_STATUS_NEED_DATA) {
52
+   if (io->status != SPA_STATUS_NEED_DATA || io->buffer_id == SPA_ID_INVALID) {
53
        /* pop buffer to recycle */
54
        if ((b = queue_pop(impl, &impl->queued))) {
55
            pw_log_trace_fp("%p: recycle buffer %d", stream, b->id);
56
-       } else if (io->status == -EPIPE)
57
-           return io->status;
58
-       io->buffer_id = b ? b->id : SPA_ID_INVALID;
59
+           io->buffer_id = b->id;
60
+       } else {
61
+           pw_log_trace_fp("%p: no buffers to recycle", stream);
62
+           io->buffer_id = SPA_ID_INVALID;
63
+       }
64
        io->status = SPA_STATUS_NEED_DATA;
65
    }
66
    if (impl->driving && impl->using_trigger)
67
pipewire-0.3.61.tar.gz/src/tools/pw-top.c -> pipewire-0.3.62.tar.gz/src/tools/pw-top.c Changed
27
 
1
@@ -663,11 +663,20 @@
2
 {
3
    struct data *data = _data;
4
 
5
-   pw_log_error("error id:%u seq:%d res:%d (%s): %s",
6
-           id, seq, res, spa_strerror(res), message);
7
-
8
-   if (id == PW_ID_CORE && res == -EPIPE)
9
-       pw_main_loop_quit(data->loop);
10
+   if (id == PW_ID_CORE) {
11
+       switch (res) {
12
+       case -EPIPE:
13
+           pw_main_loop_quit(data->loop);
14
+           break;
15
+       default:
16
+           pw_log_error("error id:%u seq:%d res:%d (%s): %s",
17
+               id, seq, res, spa_strerror(res), message);
18
+           break;
19
+       }
20
+   } else {
21
+       pw_log_info("error id:%u seq:%d res:%d (%s): %s",
22
+               id, seq, res, spa_strerror(res), message);
23
+   }
24
 }
25
 
26
 static void on_core_done(void *_data, uint32_t id, int seq)
27
pipewire-0.3.61.tar.gz/test/test-spa-buffer.c -> pipewire-0.3.62.tar.gz/test/test-spa-buffer.c Changed
27
 
1
@@ -47,7 +47,8 @@
2
    pwtest_int_eq(SPA_META_Cursor, 5);
3
    pwtest_int_eq(SPA_META_Control, 6);
4
    pwtest_int_eq(SPA_META_Busy, 7);
5
-   pwtest_int_eq(_SPA_META_LAST, 8);
6
+   pwtest_int_eq(SPA_META_VideoTransform, 8);
7
+   pwtest_int_eq(_SPA_META_LAST, 9);
8
 
9
    return PWTEST_PASS;
10
 }
11
@@ -64,6 +65,7 @@
12
    pwtest_int_eq(sizeof(struct spa_meta_region), 16U);
13
    pwtest_int_eq(sizeof(struct spa_meta_bitmap), 20U);
14
    pwtest_int_eq(sizeof(struct spa_meta_cursor), 28U);
15
+   pwtest_int_eq(sizeof(struct spa_meta_videotransform), 4U);
16
 
17
    return PWTEST_PASS;
18
 #else
19
@@ -75,6 +77,7 @@
20
    fprintf(stderr, "%zd\n", sizeof(struct spa_meta_region));
21
    fprintf(stderr, "%zd\n", sizeof(struct spa_meta_bitmap));
22
    fprintf(stderr, "%zd\n", sizeof(struct spa_meta_cursor));
23
+   fprintf(stderr, "%zd\n", sizeof(struct spa_meta_videotransform));
24
    return PWTEST_SKIP;
25
 #endif
26
 }
27