Changes of Revision 50

_service Changed
x
 
1
@@ -2,6 +2,6 @@
2
   <service name="download_url">
3
     <param name="host">gitlab.freedesktop.org</param>
4
     <param name="protocol">https</param>
5
-    <param name="path">/pipewire/pipewire/-/archive/1.4.0/pipewire-1.4.0.tar.bz2</param>
6
+    <param name="path">/pipewire/pipewire/-/archive/1.4.1/pipewire-1.4.1.tar.bz2</param>
7
   </service>
8
 </services>
9
\ No newline at end of file
10
_service:download_url:pipewire-1.4.0.tar.bz2/NEWS -> _service:download_url:pipewire-1.4.1.tar.bz2/NEWS Changed
55
 
1
@@ -1,3 +1,43 @@
2
+# PipeWire 1.4.1 (2025-03-14)
3
+
4
+This is a quick bugfix release that is API and ABI compatible with
5
+previous 1.x releases.
6
+
7
+## Highlights
8
+  - Handle SplitPCM wrong channels specifications. This fixes some
9
+    problems with disappearing devices.
10
+  - Add backwards compatibility support for when the kernel does not
11
+    support UMP. Also fix UMP output. This restores MIDI support for
12
+    older kernels/ALSA.
13
+  - Fix a crash in audioconvert because the resampler was not using the
14
+    right number of channels.
15
+  - Some compilation fixes and small improvements.
16
+
17
+
18
+## PipeWire
19
+  - Don't emit events when disconnecting a stream. (#3314)
20
+  - Fix some compilation problems. (#4603)
21
+
22
+## Modules
23
+  - Bump the ROC requirement to version 0.4.0
24
+
25
+## SPA
26
+  - Handle SplitPCM too few or too many channels. Add an error string
27
+    to the device names when the UCM config has an error.
28
+  - Add backwards compatibility support for when the kernel does not
29
+    support UMP.
30
+  - Configure the channels in the resampler correctly in all
31
+    cases. (#4595)
32
+  - Fix UMP output.
33
+  - Use the right samplerate of the filter-graph in audioconvert in
34
+    all cases.
35
+
36
+## Bluetooth
37
+  - Fix a crash with an incomming call.
38
+
39
+
40
+Older versions:
41
+
42
 # PipeWire 1.4.0 (2025-03-06)
43
 
44
 This is the 1.4 release that is API and ABI compatible with previous
45
@@ -99,9 +139,6 @@
46
 ## JACK
47
   - Add an option to disable the MIDI2 port flags. (#4584)
48
 
49
-
50
-Older versions:
51
-
52
 # PipeWire 1.3.83 (2025-02-20)
53
 
54
 This is the third and hopefully last 1.4 release candidate that
55
_service:download_url:pipewire-1.4.0.tar.bz2/meson.build -> _service:download_url:pipewire-1.4.1.tar.bz2/meson.build Changed
63
 
1
@@ -1,5 +1,5 @@
2
 project('pipewire', 'c' ,
3
-  version : '1.4.0',
4
+  version : '1.4.1',
5
   license :  'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
   meson_version : '>= 0.61.1',
7
   default_options :  'warning_level=3',
8
@@ -127,21 +127,30 @@
9
   add_project_arguments(cxx.get_supported_arguments(cxx_flags), language: 'cpp')
10
 endif
11
 
12
-sse_args = '-msse'
13
-sse2_args = '-msse2'
14
-ssse3_args = '-mssse3'
15
-sse41_args = '-msse4.1'
16
-fma_args = '-mfma'
17
-avx_args = '-mavx'
18
-avx2_args = '-mavx2'
19
-
20
-have_sse = cc.has_argument(sse_args)
21
-have_sse2 = cc.has_argument(sse2_args)
22
-have_ssse3 = cc.has_argument(ssse3_args)
23
-have_sse41 = cc.has_argument(sse41_args)
24
-have_fma = cc.has_argument(fma_args)
25
-have_avx = cc.has_argument(avx_args)
26
-have_avx2 = cc.has_argument(avx2_args)
27
+have_sse = false
28
+have_sse2 = false
29
+have_ssse3 = false
30
+have_sse41 = false
31
+have_fma = false
32
+have_avx = false
33
+have_avx2 = false
34
+if host_machine.cpu_family() in 'x86', 'x86_64'
35
+  sse_args = '-msse'
36
+  sse2_args = '-msse2'
37
+  ssse3_args = '-mssse3'
38
+  sse41_args = '-msse4.1'
39
+  fma_args = '-mfma'
40
+  avx_args = '-mavx'
41
+  avx2_args = '-mavx2'
42
+
43
+  have_sse = cc.has_argument(sse_args)
44
+  have_sse2 = cc.has_argument(sse2_args)
45
+  have_ssse3 = cc.has_argument(ssse3_args)
46
+  have_sse41 = cc.has_argument(sse41_args)
47
+  have_fma = cc.has_argument(fma_args)
48
+  have_avx = cc.has_argument(avx_args)
49
+  have_avx2 = cc.has_argument(avx2_args)
50
+endif
51
 
52
 have_neon = false
53
 if host_machine.cpu_family() == 'aarch64'
54
@@ -481,7 +490,7 @@
55
 summary({'intl support': libintl_dep.found()}, bool_yn: true)
56
 
57
 need_alsa = get_option('pipewire-alsa').enabled() or 'media-session' in get_option('session-managers')
58
-alsa_dep = dependency('alsa', version : '>=1.2.10', required: need_alsa)
59
+alsa_dep = dependency('alsa', version : '>=1.2.6', required: need_alsa)
60
 summary({'pipewire-alsa': alsa_dep.found()}, bool_yn: true)
61
 
62
 if host_machine.system() == 'freebsd' or host_machine.system() == 'midnightbsd'
63
_service:download_url:pipewire-1.4.0.tar.bz2/spa/meson.build -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/meson.build Changed
16
 
1
@@ -43,9 +43,13 @@
2
   endif
3
 
4
   # plugin-specific dependencies
5
-  alsa_dep = dependency('alsa', version : '>=1.2.10', required: get_option('alsa'))
6
+  alsa_dep = dependency('alsa', version : '>=1.2.6', required: get_option('alsa'))
7
   summary({'ALSA': alsa_dep.found()}, bool_yn: true, section: 'Backend')
8
 
9
+  if alsa_dep.version().version_compare('>=1.2.10')
10
+    cdata.set('HAVE_ALSA_UMP', true)
11
+  endif
12
+
13
   bluez_dep = dependency('bluez', version : '>= 4.101', required: get_option('bluez5'))
14
   bluez_gio_dep = dependency('gio-2.0', required : get_option('bluez5'))
15
   bluez_gio_unix_dep = dependency('gio-unix-2.0', required : get_option('bluez5'))
16
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp-tool.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp-tool.c Changed
20
 
1
@@ -132,6 +132,18 @@
2
        int level, const char *file, int line, const char *func,
3
        const char *fmt, va_list arg)
4
 {
5
+   static const char * const levels = { "E", "W", "N", "I", "D", "T" };
6
+   const char *level_str = levelsSPA_CLAMP(level, 0, (int)SPA_N_ELEMENTS(levels) - 1);
7
+
8
+   if (file) {
9
+       const char *p = strrchr(file, '/');
10
+       if (p)
11
+           file = p + 1;
12
+   }
13
+
14
+   fprintf(stderr, "%s %16s:%-5d ", level_str, file ? file : "", line);
15
+   while (level-- > 1)
16
+       fprintf(stderr, "  ");
17
    vfprintf(stderr, fmt, arg);
18
    fprintf(stderr, "\n");
19
 }
20
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp/acp.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp/acp.c Changed
52
 
1
@@ -498,6 +498,7 @@
2
    int n_profiles, n_ports, n_devices;
3
    uint32_t idx;
4
    const char *arr;
5
+   bool broken_ucm = false;
6
 
7
    n_devices = 0;
8
    pa_dynarray_init(&impl->out.devices, device_free);
9
@@ -541,6 +542,9 @@
10
                            dev->ports, NULL);
11
 
12
                pa_dynarray_append(&ap->out.devices, dev);
13
+
14
+               if (m->split && m->split->broken)
15
+                   broken_ucm = true;
16
            }
17
        }
18
 
19
@@ -564,6 +568,9 @@
20
                            dev->ports, NULL);
21
 
22
                pa_dynarray_append(&ap->out.devices, dev);
23
+
24
+               if (m->split && m->split->broken)
25
+                   broken_ucm = true;
26
            }
27
        }
28
        cp->n_devices = pa_dynarray_size(&ap->out.devices);
29
@@ -571,6 +578,22 @@
30
        pa_hashmap_put(impl->profiles, ap->name, cp);
31
    }
32
 
33
+
34
+   /* Add a conspicuous notice if there are errors in the UCM profile */
35
+   if (broken_ucm) {
36
+       const char *desc;
37
+       char *new_desc = NULL;
38
+
39
+       desc = pa_proplist_gets(impl->proplist, PA_PROP_DEVICE_DESCRIPTION);
40
+       if (!desc)
41
+           desc = "";
42
+       new_desc = spa_aprintf(_("%s ALSA UCM error"), desc);
43
+       pa_log_notice("Errors in ALSA UCM profile for card %s", desc);
44
+       if (new_desc)
45
+           pa_proplist_sets(impl->proplist, PA_PROP_DEVICE_DESCRIPTION, new_desc);
46
+       free(new_desc);
47
+   }
48
+
49
    pa_dynarray_init(&impl->out.ports, NULL);
50
    n_ports = 0;
51
    PA_HASHMAP_FOREACH(dp, impl->ports, state) {
52
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.c Changed
201
 
1
@@ -353,6 +353,15 @@
2
     const char *device_name;
3
     int i;
4
     uint32_t hw_channels;
5
+    const char *pcm_name;
6
+    const char *rule_name;
7
+
8
+    if (spa_streq(prefix, "Playback"))
9
+        pcm_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_SINK);
10
+    else
11
+        pcm_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_SOURCE);
12
+    if (!pcm_name)
13
+        pcm_name = "";
14
 
15
     device_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_NAME);
16
     if (!device_name)
17
@@ -372,16 +381,23 @@
18
         if (pa_atou(value, &idx) < 0)
19
             break;
20
 
21
-        if (idx >= hw_channels)
22
-            goto fail;
23
+        if (idx >= hw_channels) {
24
+            pa_log_notice("Error in ALSA UCM profile for %s (%s): %sChannel%d=%d >= %sChannels=%d",
25
+                          pcm_name, device_name, prefix, i, idx, prefix, hw_channels);
26
+            split->broken = true;
27
+   }
28
 
29
         value = ucm_get_string(uc_mgr, "%sChannelPos%d/%s", prefix, i, device_name);
30
-        if (!value)
31
+        if (!value) {
32
+            rule_name = "ChannelPos";
33
             goto fail;
34
+        }
35
 
36
         map = snd_pcm_chmap_parse_string(value);
37
-        if (!map)
38
+        if (!map) {
39
+            rule_name = "ChannelPos value";
40
             goto fail;
41
+        }
42
 
43
         if (map->channels == 1) {
44
             pa_log_debug("Split %s channel %d -> device %s channel %d: %s (%d)",
45
@@ -391,6 +407,7 @@
46
             free(map);
47
         } else {
48
             free(map);
49
+            rule_name = "channel map parsing";
50
             goto fail;
51
         }
52
     }
53
@@ -405,7 +422,7 @@
54
     return split;
55
 
56
 fail:
57
-    pa_log_warn("Invalid SplitPCM ALSA UCM rule for device %s", device_name);
58
+    pa_log_warn("Invalid SplitPCM ALSA UCM %s for device %s (%s)", rule_name, pcm_name, device_name);
59
     pa_xfree(split);
60
     return NULL;
61
 }
62
@@ -2383,7 +2400,7 @@
63
     dev->eld_device = pcm_device;
64
 }
65
 
66
-static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, int mode) {
67
+static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, int mode, bool max_channels) {
68
     snd_pcm_t* pcm;
69
     pa_sample_spec try_ss = ucm->default_sample_spec;
70
     pa_channel_map try_map;
71
@@ -2391,6 +2408,11 @@
72
     bool exact_channels = m->channel_map.channels > 0;
73
 
74
     if (!m->split) {
75
+        if (max_channels) {
76
+            errno = EINVAL;
77
+            return NULL;
78
+        }
79
+
80
         if (exact_channels) {
81
             try_map = m->channel_map;
82
             try_ss.channels = try_map.channels;
83
@@ -2402,8 +2424,8 @@
84
             return NULL;
85
         }
86
 
87
-        exact_channels = true;
88
-        try_ss.channels = m->split->hw_channels;
89
+        exact_channels = false;
90
+        try_ss.channels = max_channels ? PA_CHANNELS_MAX : m->split->hw_channels;
91
         pa_channel_map_init_extend(&try_map, try_ss.channels, PA_CHANNEL_MAP_AUX);
92
     }
93
 
94
@@ -2416,15 +2438,40 @@
95
             &try_map, mode, &try_period_size, &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels);
96
 
97
     if (pcm) {
98
-        if (!exact_channels)
99
+        if (m->split) {
100
+            const char *mode_name = mode == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture";
101
+
102
+            if (try_map.channels < m->split->hw_channels) {
103
+                pa_logl((max_channels ? PA_LOG_NOTICE : PA_LOG_DEBUG),
104
+                        "Error in ALSA UCM profile for %s (%s): %sChannels=%d > avail %d",
105
+                        m->device_strings0, m->name, mode_name, m->split->hw_channels, try_map.channels);
106
+
107
+                /* Retry with max channel count, in case ALSA rounded down */
108
+                if (!max_channels) {
109
+                    pa_alsa_close(&pcm);
110
+                    return mapping_open_pcm(ucm, m, mode, true);
111
+                }
112
+
113
+                /* Just accept whatever we got... Some of the routings won't get connected
114
+                 * anywhere */
115
+                m->split->hw_channels = try_map.channels;
116
+                m->split->broken = true;
117
+            } else if (try_map.channels > m->split->hw_channels) {
118
+                pa_log_notice("Error in ALSA UCM profile for %s (%s): %sChannels=%d < avail %d",
119
+                            m->device_strings0, m->name, mode_name, m->split->hw_channels, try_map.channels);
120
+                m->split->hw_channels = try_map.channels;
121
+                m->split->broken = true;
122
+            }
123
+        } else if (!exact_channels) {
124
             m->channel_map = try_map;
125
+        }
126
         mapping_init_eld(m, pcm);
127
     }
128
 
129
     return pcm;
130
 }
131
 
132
-static void pa_alsa_init_proplist_split_pcm(pa_idxset *mappings, pa_alsa_mapping *leader, pa_direction_t direction)
133
+static void pa_alsa_init_split_pcm(pa_idxset *mappings, pa_alsa_mapping *leader, pa_direction_t direction)
134
 {
135
     pa_proplist *props = pa_proplist_new();
136
     uint32_t idx;
137
@@ -2445,6 +2492,9 @@
138
        pa_proplist_update(m->output_proplist, PA_UPDATE_REPLACE, props);
139
         else
140
             pa_proplist_update(m->input_proplist, PA_UPDATE_REPLACE, props);
141
+
142
+        /* Update HW channel count to match probed one */
143
+        m->split->hw_channels = leader->split->hw_channels;
144
     }
145
 
146
     pa_proplist_free(props);
147
@@ -2464,7 +2514,7 @@
148
         if (!m->split)
149
             pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm);
150
         else
151
-            pa_alsa_init_proplist_split_pcm(p->output_mappings, m, PA_DIRECTION_OUTPUT);
152
+            pa_alsa_init_split_pcm(p->output_mappings, m, PA_DIRECTION_OUTPUT);
153
 
154
         pa_alsa_close(&m->output_pcm);
155
     }
156
@@ -2479,7 +2529,7 @@
157
         if (!m->split)
158
             pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm);
159
         else
160
-            pa_alsa_init_proplist_split_pcm(p->input_mappings, m, PA_DIRECTION_INPUT);
161
+            pa_alsa_init_split_pcm(p->input_mappings, m, PA_DIRECTION_INPUT);
162
 
163
         pa_alsa_close(&m->input_pcm);
164
     }
165
@@ -2521,7 +2571,7 @@
166
         pa_log_info("Set ucm verb to %s", verb_name);
167
 
168
         if ((snd_use_case_set(ucm->ucm_mgr, "_verb", verb_name)) < 0) {
169
-            pa_log("Failed to set verb %s", verb_name);
170
+            pa_log("Profile '%s': failed to set verb %s", p->name, verb_name);
171
             p->supported = false;
172
             continue;
173
         }
174
@@ -2536,8 +2586,10 @@
175
             if (m->split && !m->split->leader)
176
                 continue;
177
 
178
-            m->output_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_PLAYBACK);
179
+            m->output_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_PLAYBACK, false);
180
             if (!m->output_pcm) {
181
+                pa_log_info("Profile '%s' mapping '%s': output PCM open failed",
182
+                            p->name, m->name);
183
                 p->supported = false;
184
                 break;
185
             }
186
@@ -2554,8 +2606,10 @@
187
                 if (m->split && !m->split->leader)
188
                     continue;
189
 
190
-                m->input_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_CAPTURE);
191
+                m->input_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_CAPTURE, false);
192
                 if (!m->input_pcm) {
193
+                    pa_log_info("Profile '%s' mapping '%s': input PCM open failed",
194
+                                p->name, m->name);
195
                     p->supported = false;
196
                     break;
197
                 }
198
@@ -2564,6 +2618,7 @@
199
 
200
         if (!p->supported) {
201
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.h -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.h Changed
9
 
1
@@ -185,6 +185,7 @@
2
     int channels;
3
     int idxPA_CHANNELS_MAX;
4
     enum snd_pcm_chmap_position posPA_CHANNELS_MAX;
5
+    bool broken;
6
 };
7
 
8
 struct pa_alsa_ucm_device {
9
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/alsa-seq-bridge.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/alsa-seq-bridge.c Changed
26
 
1
@@ -931,6 +931,7 @@
2
    this->quantum_limit = 8192;
3
    this->min_pool_size = 500;
4
    this->max_pool_size = 2000;
5
+   this->ump = true;
6
 
7
    for (i = 0; info && i < info->n_items; i++) {
8
        const char *k = info->itemsi.key;
9
@@ -949,6 +950,8 @@
10
            spa_atou32(s, &this->min_pool_size, 0);
11
        } else if (spa_streq(k, "api.alsa.seq.max-pool")) {
12
            spa_atou32(s, &this->max_pool_size, 0);
13
+       } else if (spa_streq(k, "api.alsa.seq.ump")) {
14
+           this->ump = spa_atob(s);
15
        }
16
    }
17
 
18
@@ -992,6 +995,7 @@
19
        ""SPA_KEY_API_ALSA_DISABLE_LONGNAME"=<bool, default false> "
20
        " api.alsa.seq.min-pool=<min-pool, default 500> "
21
        " api.alsa.seq.max-pool=<max-pool, default 2000>"
22
+       " api.alsa.seq.ump = <boolean> "
23
    },
24
 };
25
 
26
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/alsa-seq.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/alsa-seq.c Changed
201
 
1
@@ -24,7 +24,7 @@
2
 
3
 #define CHECK(s,msg,...) if ((res = (s)) < 0) { spa_log_error(state->log, msg ": %s", ##__VA_ARGS__, snd_strerror(res)); return res; }
4
 
5
-static int seq_open(struct seq_state *state, struct seq_conn *conn, bool with_queue)
6
+static int seq_open(struct seq_state *state, struct seq_conn *conn, bool with_queue, bool probe_ump)
7
 {
8
    struct props *props = &state->props;
9
    int res;
10
@@ -37,11 +37,28 @@
11
               0)) < 0)
12
        return res;
13
 
14
-   if ((res = snd_seq_set_client_midi_version(conn->hndl, SND_SEQ_CLIENT_UMP_MIDI_2_0)) < 0) {
15
-       snd_seq_close(conn->hndl);
16
-       spa_log_info(state->log, "%p: ALSA failed to enable UMP MIDI: %s",
17
-               state, snd_strerror(res));
18
-       return res;
19
+   if (!state->ump) {
20
+       spa_log_info(state->log, "%p: ALSA UMP MIDI disabled", state);
21
+       return 0;
22
+   }
23
+
24
+#ifdef HAVE_ALSA_UMP
25
+   res = snd_seq_set_client_midi_version(conn->hndl, SND_SEQ_CLIENT_UMP_MIDI_2_0);
26
+#else
27
+   res = -EOPNOTSUPP;
28
+#endif
29
+   if (res < 0) {
30
+       spa_log_lev(state->log, (probe_ump ? SPA_LOG_LEVEL_INFO : SPA_LOG_LEVEL_ERROR),
31
+               "%p: ALSA failed to enable UMP MIDI: %s", state, snd_strerror(res));
32
+       if (!probe_ump) {
33
+           snd_seq_close(conn->hndl);
34
+           return res;  /* either all are UMP or none are UMP */
35
+       }
36
+
37
+       state->ump = false;
38
+   } else {
39
+       spa_log_debug(state->log, "%p: ALSA UMP MIDI enabled", state);
40
+       state->ump = true;
41
    }
42
 
43
    return 0;
44
@@ -172,7 +189,32 @@
45
    }
46
 }
47
 
48
-static void debug_event(struct seq_state *state, snd_seq_ump_event_t *ev)
49
+static void debug_event(struct seq_state *state, snd_seq_event_t *ev)
50
+{
51
+   if (SPA_LIKELY(!spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE)))
52
+       return;
53
+
54
+   spa_log_trace(state->log, "event type:%d flags:0x%x", ev->type, ev->flags);
55
+   switch (ev->flags & SND_SEQ_TIME_STAMP_MASK) {
56
+   case SND_SEQ_TIME_STAMP_TICK:
57
+       spa_log_trace(state->log, " time: %d ticks", ev->time.tick);
58
+       break;
59
+   case SND_SEQ_TIME_STAMP_REAL:
60
+       spa_log_trace(state->log, " time = %d.%09d",
61
+           (int)ev->time.time.tv_sec,
62
+           (int)ev->time.time.tv_nsec);
63
+       break;
64
+   }
65
+   spa_log_trace(state->log, " source:%d.%d dest:%d.%d queue:%d",
66
+       ev->source.client,
67
+       ev->source.port,
68
+       ev->dest.client,
69
+       ev->dest.port,
70
+       ev->queue);
71
+}
72
+
73
+#ifdef HAVE_ALSA_UMP
74
+static void debug_ump_event(struct seq_state *state, snd_seq_ump_event_t *ev)
75
 {
76
    if (SPA_LIKELY(!spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE)))
77
        return;
78
@@ -195,22 +237,50 @@
79
        ev->dest.port,
80
        ev->queue);
81
 }
82
+#endif
83
 
84
 static void alsa_seq_on_sys(struct spa_source *source)
85
 {
86
    struct seq_state *state = source->data;
87
-   snd_seq_ump_event_t *ev;
88
+   const bool ump = state->ump;
89
    int res;
90
 
91
-   while (snd_seq_ump_event_input(state->sys.hndl, &ev) > 0) {
92
-       const snd_seq_addr_t *addr = &ev->data.addr;
93
+   while (1) {
94
+       const snd_seq_addr_t *addr;
95
+       snd_seq_event_type_t type;
96
+
97
+       if (ump) {
98
+#ifdef HAVE_ALSA_UMP
99
+           snd_seq_ump_event_t *ev;
100
+
101
+           res = snd_seq_ump_event_input(state->sys.hndl, &ev);
102
+           if (res <= 0)
103
+               break;
104
+
105
+           debug_ump_event(state, ev);
106
+
107
+           addr = &ev->data.addr;
108
+           type = ev->type;
109
+#else
110
+           spa_assert_not_reached();
111
+#endif
112
+       } else {
113
+           snd_seq_event_t *ev;
114
+
115
+           res = snd_seq_event_input(state->sys.hndl, &ev);
116
+           if (res <= 0)
117
+               break;
118
+
119
+           debug_event(state, ev);
120
+
121
+           addr = &ev->data.addr;
122
+           type = ev->type;
123
+       }
124
 
125
        if (addr->client == state->event.addr.client)
126
            continue;
127
 
128
-       debug_event(state, ev);
129
-
130
-       switch (ev->type) {
131
+       switch (type) {
132
        case SND_SEQ_EVENT_CLIENT_START:
133
        case SND_SEQ_EVENT_CLIENT_CHANGE:
134
            spa_log_info(state->log, "client add/change %d", addr->client);
135
@@ -244,7 +314,7 @@
136
            break;
137
        default:
138
            spa_log_info(state->log, "unhandled event %d: %d:%d",
139
-                   ev->type, addr->client, addr->port);
140
+                   type, addr->client, addr->port);
141
            break;
142
 
143
        }
144
@@ -269,8 +339,8 @@
145
 
146
    spa_zero(reserve);
147
    for (i = 0; i < 16; i++) {
148
-       spa_log_debug(state->log, "close %d", i);
149
-       if ((res = seq_open(state, &reservei, false)) < 0)
150
+       spa_log_debug(state->log, "open %d", i);
151
+       if ((res = seq_open(state, &reservei, false, (i == 0))) < 0)
152
            break;
153
    }
154
    if (i >= 2) {
155
@@ -529,21 +599,58 @@
156
 
157
 static int process_read(struct seq_state *state)
158
 {
159
-   snd_seq_ump_event_t *ev;
160
    struct seq_stream *stream = &state->streamsSPA_DIRECTION_OUTPUT;
161
+   const bool ump = state->ump;
162
    uint32_t i;
163
    uint32_t *data;
164
+   uint8_t midi1_dataMAX_EVENT_SIZE;
165
+   uint32_t ump_dataMAX_EVENT_SIZE;
166
    long size;
167
-   int res;
168
+   int res = -1;
169
 
170
    /* copy all new midi events into their port buffers */
171
-   while ((res = snd_seq_ump_event_input(state->event.hndl, &ev)) > 0) {
172
-       const snd_seq_addr_t *addr = &ev->source;
173
+   while (1) {
174
+       const snd_seq_addr_t *addr;
175
        struct seq_port *port;
176
        uint64_t ev_time, diff;
177
        uint32_t offset;
178
+       void *event;
179
+       uint8_t *midi1_ptr;
180
+       size_t midi1_size = 0;
181
+       uint64_t ump_state = 0;
182
+       snd_seq_event_type_t SPA_UNUSED type;
183
+
184
+       if (ump) {
185
+#ifdef HAVE_ALSA_UMP
186
+           snd_seq_ump_event_t *ev;
187
+
188
+           res = snd_seq_ump_event_input(state->event.hndl, &ev);
189
+           if (res <= 0)
190
+               break;
191
+
192
+           debug_ump_event(state, ev);
193
+
194
+           event = ev;
195
+           addr = &ev->source;
196
+           ev_time = SPA_TIMESPEC_TO_NSEC(&ev->time.time);
197
+           type = ev->type;
198
+#else
199
+           spa_assert_not_reached();
200
+#endif
201
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/alsa-seq.h -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/alsa-seq.h Changed
22
 
1
@@ -12,8 +12,12 @@
2
 #include <stddef.h>
3
 #include <math.h>
4
 
5
+#include "config.h"
6
+
7
 #include <alsa/asoundlib.h>
8
+#ifdef HAVE_ALSA_UMP
9
 #include <alsa/ump_msg.h>
10
+#endif
11
 
12
 #include <spa/support/plugin.h>
13
 #include <spa/support/loop.h>
14
@@ -153,6 +157,7 @@
15
    unsigned int opened:1;
16
    unsigned int started:1;
17
    unsigned int following:1;
18
+   unsigned int ump:1;
19
 
20
    struct seq_stream streams2;
21
 
22
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/audioconvert/audioconvert.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/audioconvert/audioconvert.c Changed
167
 
1
@@ -210,7 +210,6 @@
2
    uint32_t src_idx;
3
    uint32_t dst_idx;
4
    uint32_t final_idx;
5
-   uint32_t n_datas;
6
    struct port *ctrlport;
7
 };
8
 
9
@@ -219,8 +218,6 @@
10
    bool passthrough;
11
    uint32_t in_idx;
12
    uint32_t out_idx;
13
-   uint32_t n_in;
14
-   uint32_t n_out;
15
    void *data;
16
    void (*run) (struct stage *stage, struct stage_context *c);
17
 };
18
@@ -1003,13 +1000,13 @@
19
 {
20
    int res;
21
    char rate_str64;
22
-   struct dir *in;
23
+   struct dir *dir;
24
 
25
    if (graph == NULL)
26
        return 0;
27
 
28
-   in = &this->dirSPA_DIRECTION_INPUT;
29
-   snprintf(rate_str, sizeof(rate_str), "%d", in->format.info.raw.rate);
30
+   dir = &this->dirSPA_DIRECTION_REVERSE(this->direction);
31
+   snprintf(rate_str, sizeof(rate_str), "%d", dir->format.info.raw.rate);
32
 
33
    spa_filter_graph_deactivate(graph);
34
    res = spa_filter_graph_activate(graph,
35
@@ -1971,13 +1968,19 @@
36
    struct dir *in = &this->dirSPA_DIRECTION_INPUT;
37
    struct dir *out = &this->dirSPA_DIRECTION_OUTPUT;
38
    int res;
39
+   uint32_t channels;
40
+
41
+   if (this->direction == SPA_DIRECTION_INPUT)
42
+       channels = in->format.info.raw.channels;
43
+   else
44
+       channels = out->format.info.raw.channels;
45
 
46
    spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d", this,
47
            spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32),
48
-           out->format.info.raw.channels,
49
+           channels,
50
            in->format.info.raw.rate,
51
            spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32),
52
-           out->format.info.raw.channels,
53
+           channels,
54
            out->format.info.raw.rate);
55
 
56
    if (this->props.resample_disabled && !this->resample_peaks &&
57
@@ -1987,7 +1990,7 @@
58
    if (this->resample.free)
59
        resample_free(&this->resample);
60
 
61
-   this->resample.channels = out->format.info.raw.channels;
62
+   this->resample.channels = channels;
63
    this->resample.i_rate = in->format.info.raw.rate;
64
    this->resample.o_rate = out->format.info.raw.rate;
65
    this->resample.log = this->log;
66
@@ -3217,8 +3220,6 @@
67
    s->passthrough = false;
68
    s->in_idx = ctx->src_idx;
69
    s->out_idx = ctx->src_idx;
70
-   s->n_in = ctx->n_datas;
71
-   s->n_out = ctx->n_datas;
72
    s->data = NULL;
73
    s->run = run_wav_stage;
74
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
75
@@ -3230,7 +3231,7 @@
76
    struct impl *impl = s->impl;
77
    struct dir *dir = &impl->dirSPA_DIRECTION_OUTPUT;
78
    uint32_t i;
79
-   for (i = 0; i < s->n_in; i++) {
80
+   for (i = 0; i < dir->conv.n_channels; i++) {
81
        c->datass->out_idxi = c->datass->in_idxdir->remapi;
82
        spa_log_trace_fp(impl->log, "%p: output remap %d -> %d", impl, i, dir->remapi);
83
    }
84
@@ -3242,8 +3243,6 @@
85
    s->passthrough = false;
86
    s->in_idx = ctx->dst_idx;
87
    s->out_idx = CTX_DATA_REMAP_DST;
88
-   s->n_in = ctx->n_datas;
89
-   s->n_out = ctx->n_datas;
90
    s->data = NULL;
91
    s->run = run_dst_remap_stage;
92
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
93
@@ -3269,8 +3268,6 @@
94
    s->passthrough = false;
95
    s->in_idx = ctx->src_idx;
96
    s->out_idx = CTX_DATA_REMAP_SRC;
97
-   s->n_in = ctx->n_datas;
98
-   s->n_out = ctx->n_datas;
99
    s->data = NULL;
100
    s->run = run_src_remap_stage;
101
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
102
@@ -3304,8 +3301,6 @@
103
    s->passthrough = false;
104
    s->in_idx = ctx->src_idx;
105
    s->out_idx = ctx->dst_idx;
106
-   s->n_in = ctx->n_datas;
107
-   s->n_out = ctx->n_datas;
108
    s->data = NULL;
109
    s->run = run_src_convert_stage;
110
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
111
@@ -3334,8 +3329,6 @@
112
    s->passthrough = false;
113
    s->in_idx = ctx->src_idx;
114
    s->out_idx = ctx->dst_idx;
115
-   s->n_in = ctx->n_datas;
116
-   s->n_out = ctx->n_datas;
117
    s->data = NULL;
118
    s->run = run_resample_stage;
119
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
120
@@ -3383,8 +3376,6 @@
121
    s->passthrough = false;
122
    s->in_idx = ctx->src_idx;
123
    s->out_idx = ctx->dst_idx;
124
-   s->n_in = ctx->n_datas;
125
-   s->n_out = ctx->n_datas;
126
    s->data = fg;
127
    s->run = run_filter_stage;
128
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
129
@@ -3399,8 +3390,6 @@
130
    s->passthrough = false;
131
    s->in_idx = ctx->src_idx;
132
    s->out_idx = ctx->dst_idx;
133
-   s->n_in = ctx->n_datas;
134
-   s->n_out = ctx->n_datas;
135
    s->data = NULL;
136
    s->run = run_channelmix_stage;
137
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
138
@@ -3434,8 +3423,6 @@
139
    s->passthrough = false;
140
    s->in_idx = ctx->src_idx;
141
    s->out_idx = ctx->final_idx;
142
-   s->n_in = ctx->n_datas;
143
-   s->n_out = ctx->n_datas;
144
    s->data = NULL;
145
    s->run = run_dst_convert_stage;
146
    spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages);
147
@@ -3828,14 +3815,14 @@
148
    ctx.in_samples = n_samples;
149
    ctx.n_samples = n_samples;
150
    ctx.n_out = n_out;
151
-   ctx.src_idx = CTX_DATA_SRC;
152
-   ctx.dst_idx = CTX_DATA_DST;
153
-   ctx.final_idx = CTX_DATA_DST;
154
-   ctx.n_datas = dir->conv.n_channels;
155
    ctx.ctrlport = ctrlport;
156
 
157
-   if (this->recalc)
158
+   if (SPA_UNLIKELY(this->recalc)) {
159
+       ctx.src_idx = CTX_DATA_SRC;
160
+       ctx.dst_idx = CTX_DATA_DST;
161
+       ctx.final_idx = CTX_DATA_DST;
162
        recalc_stages(this, &ctx);
163
+   }
164
 
165
    for (i = 0; i < this->n_stages; i++) {
166
        struct stage *s = &this->stagesi;
167
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/bluez5/backend-native.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/bluez5/backend-native.c Changed
133
 
1
@@ -1406,18 +1406,44 @@
2
    struct rfcomm_call_data *call_data = data;
3
    struct rfcomm *rfcomm = call_data->rfcomm;
4
    struct impl *backend = rfcomm->backend;
5
+   struct spa_bt_telephony_call *call, *tcall;
6
+   bool found_held = false;
7
+   bool hfp_hf_in_progress = false;
8
    char reply20;
9
    bool res;
10
 
11
+   spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
12
+       if (call->state == CALL_STATE_HELD)
13
+           found_held = true;
14
+   }
15
+
16
    switch (call_data->call->state) {
17
    case CALL_STATE_ACTIVE:
18
    case CALL_STATE_DIALING:
19
    case CALL_STATE_ALERTING:
20
    case CALL_STATE_INCOMING:
21
-       rfcomm_send_cmd(rfcomm, "AT+CHUP");
22
+       if (found_held) {
23
+           if (!rfcomm->chld_supported) {
24
+               *err = BT_TELEPHONY_ERROR_NOT_SUPPORTED;
25
+               return;
26
+           } else if (rfcomm->hfp_hf_in_progress) {
27
+               *err = BT_TELEPHONY_ERROR_IN_PROGRESS;
28
+               return;
29
+           }
30
+
31
+           rfcomm_send_cmd(rfcomm, "AT+CHLD=1");
32
+           hfp_hf_in_progress = true;
33
+       } else {
34
+           rfcomm_send_cmd(rfcomm, "AT+CHUP");
35
+       }
36
        break;
37
    case CALL_STATE_WAITING:
38
+       if (rfcomm->hfp_hf_in_progress) {
39
+           *err = BT_TELEPHONY_ERROR_IN_PROGRESS;
40
+           return;
41
+       }
42
        rfcomm_send_cmd(rfcomm, "AT+CHLD=0");
43
+       hfp_hf_in_progress = true;
44
        break;
45
    default:
46
        spa_log_info(backend->log, "Call not incoming, waiting or active: skip hangup");
47
@@ -1435,6 +1461,24 @@
48
        return;
49
    }
50
 
51
+   if (hfp_hf_in_progress) {
52
+       if (call_data->call->state != CALL_STATE_WAITING) {
53
+           spa_list_for_each_safe(call, tcall, &rfcomm->telephony_ag->call_list, link) {
54
+               if (call->state == CALL_STATE_ACTIVE) {
55
+                   call->state = CALL_STATE_DISCONNECTED;
56
+                   telephony_call_notify_updated_props(call);
57
+                   telephony_call_destroy(call);
58
+               }
59
+           }
60
+           spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
61
+               if (call->state == CALL_STATE_HELD) {
62
+                   call->state = CALL_STATE_ACTIVE;
63
+                   telephony_call_notify_updated_props(call);
64
+               }
65
+           }
66
+       }
67
+       rfcomm->hfp_hf_in_progress = true;
68
+   }
69
    *err = BT_TELEPHONY_ERROR_NONE;
70
 }
71
 
72
@@ -2286,6 +2330,26 @@
73
                }
74
                SPA_FALLTHROUGH;
75
            case hfp_hf_chld:
76
+               rfcomm->slc_configured = true;
77
+
78
+               if (!rfcomm->codec_negotiation_supported) {
79
+                   if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) < 0) {
80
+                       // TODO: We should manage the missing transport
81
+                   } else {
82
+                       spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
83
+                   }
84
+               }
85
+
86
+               rfcomm->telephony_ag = telephony_ag_new(backend->telephony, 0);
87
+               rfcomm->telephony_ag->address = strdup(rfcomm->device->address);
88
+               telephony_ag_set_callbacks(rfcomm->telephony_ag,
89
+                           &telephony_ag_callbacks, rfcomm);
90
+               if (rfcomm->transport) {
91
+                   rfcomm->telephony_ag->transport.codec = rfcomm->transport->codec;
92
+                   rfcomm->telephony_ag->transport.state = rfcomm->transport->state;
93
+               }
94
+               telephony_ag_register(rfcomm->telephony_ag);
95
+
96
                rfcomm_send_cmd(rfcomm, "AT+CLIP=1");
97
                rfcomm->hf_state = hfp_hf_clip;
98
                break;
99
@@ -2312,25 +2376,6 @@
100
                SPA_FALLTHROUGH;
101
            case hfp_hf_nrec:
102
                rfcomm->hf_state = hfp_hf_slc1;
103
-               rfcomm->slc_configured = true;
104
-
105
-               if (!rfcomm->codec_negotiation_supported) {
106
-                   if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) < 0) {
107
-                       // TODO: We should manage the missing transport
108
-                   } else {
109
-                       spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile);
110
-                   }
111
-               }
112
-
113
-               rfcomm->telephony_ag = telephony_ag_new(backend->telephony, 0);
114
-               rfcomm->telephony_ag->address = strdup(rfcomm->device->address);
115
-               telephony_ag_set_callbacks(rfcomm->telephony_ag,
116
-                           &telephony_ag_callbacks, rfcomm);
117
-               if (rfcomm->transport) {
118
-                   rfcomm->telephony_ag->transport.codec = rfcomm->transport->codec;
119
-                   rfcomm->telephony_ag->transport.state = rfcomm->transport->state;
120
-               }
121
-               telephony_ag_register(rfcomm->telephony_ag);
122
 
123
                if (rfcomm->hfp_hf_clcc) {
124
                    rfcomm_send_cmd(rfcomm, "AT+CLCC");
125
@@ -3318,6 +3363,7 @@
126
    } else if (profile == SPA_BT_PROFILE_HFP_AG) {
127
        /* Start SLC connection */
128
        unsigned int hf_features = SPA_BT_HFP_HF_FEATURE_CLIP | SPA_BT_HFP_HF_FEATURE_3WAY |
129
+                                   SPA_BT_HFP_HF_FEATURE_ECNR |
130
                                    SPA_BT_HFP_HF_FEATURE_ENHANCED_CALL_STATUS |
131
                                    SPA_BT_HFP_HF_FEATURE_ESCO_S4;
132
        bool has_msbc = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_MSBC);
133
_service:download_url:pipewire-1.4.0.tar.bz2/src/daemon/systemd/user/pipewire.service.in -> _service:download_url:pipewire-1.4.1.tar.bz2/src/daemon/systemd/user/pipewire.service.in Changed
9
 
1
@@ -14,6 +14,7 @@
2
 # After=pipewire.socket is not needed, as it is already implicit in the
3
 # socket-service relationship, see systemd.socket(5).
4
 Requires=pipewire.socket
5
+ConditionUser=!root
6
 
7
 Service
8
 LockPersonality=yes
9
_service:download_url:pipewire-1.4.0.tar.bz2/src/daemon/systemd/user/pipewire.socket -> _service:download_url:pipewire-1.4.1.tar.bz2/src/daemon/systemd/user/pipewire.socket Changed
8
 
1
@@ -1,5 +1,6 @@
2
 Unit
3
 Description=PipeWire Multimedia System Sockets
4
+ConditionUser=!root
5
 
6
 Socket
7
 Priority=6
8
_service:download_url:pipewire-1.4.0.tar.bz2/src/modules/meson.build -> _service:download_url:pipewire-1.4.1.tar.bz2/src/modules/meson.build Changed
10
 
1
@@ -620,7 +620,7 @@
2
 endif
3
 summary({'raop-sink (requires OpenSSL)': build_module_raop}, bool_yn: true, section: 'Optional Modules')
4
 
5
-roc_dep = dependency('roc', version: '>= 0.3.0', required: get_option('roc'))
6
+roc_dep = dependency('roc', version: '>= 0.4.0', required: get_option('roc'))
7
 summary({'ROC': roc_dep.found()}, bool_yn: true, section: 'Streaming between daemons')
8
 
9
 pipewire_module_rtp_source = shared_library('pipewire-module-rtp-source',
10
_service:download_url:pipewire-1.4.0.tar.bz2/src/pipewire/loop.h -> _service:download_url:pipewire-1.4.1.tar.bz2/src/pipewire/loop.h Changed
10
 
1
@@ -141,7 +141,7 @@
2
 PW_API_LOOP_IMPL void pw_loop_destroy_source(struct pw_loop *object,
3
                 struct spa_source *source)
4
 {
5
-   return spa_loop_utils_destroy_source(object->utils, source);
6
+   spa_loop_utils_destroy_source(object->utils, source);
7
 }
8
 
9
 /**
10
_service:download_url:pipewire-1.4.0.tar.bz2/src/pipewire/stream.c -> _service:download_url:pipewire-1.4.1.tar.bz2/src/pipewire/stream.c Changed
10
 
1
@@ -446,7 +446,7 @@
2
    if (impl->n_buffers == 0 ||
3
        (impl->direction == SPA_DIRECTION_OUTPUT && update_requested(impl) <= 0))
4
        return;
5
-   if (impl->rt_callbacks.funcs)
6
+   if (impl->rt_callbacks.funcs && !impl->disconnecting)
7
        spa_callbacks_call_fast(&impl->rt_callbacks, struct pw_stream_events, process, 0);
8
 }
9
 
10