Overview
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Wed Aug 9 15:43:07 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.77
6
+
7
+-------------------------------------------------------------------
8
Mon Jul 31 19:02:32 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.76
11
pipewire-aptx.spec
Changed
10
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.76
6
+Version: 0.3.77
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
pipewire-0.3.76.tar.gz/NEWS -> pipewire-0.3.77.tar.gz/NEWS
Changed
69
1
2
+# PipeWire 0.3.77 (2023-08-04)
3
+
4
+This is a quick bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+ - Fix a bug in ALSA source where the available number of samples was miscaluclated
9
+ and resulted in xruns in some cases.
10
+ - A new L permission was added to make it possible to force a link between
11
+ nodes even when the nodes can't see eachother.
12
+ - The VBAN module now supports midi send and receive as well.
13
+ - Many cleanups and small fixes.
14
+
15
+
16
+## PipeWire
17
+ - Global objects now only show permissions that apply to them. The permissions
18
+ required to perform various API calls are documented.
19
+ - A new L permission was added to make it possible to force a link between
20
+ nodes even when the nodes can't see eachother.
21
+ - Config files need to end with .conf.
22
+ - The client.api is added the to global properties of a node.
23
+
24
+## modules
25
+ - The VBAN module now supports midi send and receive as well.
26
+ - Fix module-profiler alignment and make sure we don't overrun our buffers with
27
+ many nodes.
28
+ - Protect libcanberra calls with a mutex because it is not thread safe. (#2834)
29
+
30
+## SPA
31
+ - Support older compilers for spa_clear_ptr().
32
+ - Fix a bug in ALSA source where the available number of samples was miscaluclated
33
+ and resulted in xruns. (#3395)
34
+ - Don't set inotify on /dev but on the videoX devices directly. Setting inotify
35
+ on /dev would cause a lot of spurious wakeups and lock contention in the
36
+ fsnotify subsystem on some benchmarks.
37
+ - Audioconvert now rate limits the warnings when it runs out of buffers. (#3384)
38
+
39
+## pulse-server
40
+ - Some bugs and inconsistencies were fixed in device lookup.
41
+ - Improve subscribe event emission, detect changes to the sink or the monitor
42
+ and send the right sink/source event. (#3388)
43
+
44
+## JACK
45
+ - The libjack.so now has a minor version of 3 and a micro version of the pipewire
46
+ version.
47
+ - JACK clients will now see portregistration from other jack clients when they
48
+ activate/deactivate like real JACK. (#3260)
49
+
50
+## bluetooth
51
+ - Use some more autoptr cleanups, fix some leaks.
52
+
53
+Older versions:
54
+
55
+
56
# PipeWire 0.3.76 (2023-07-28)
57
58
This is a quick bugfix release that is API and ABI compatible with previous
59
60
- LE Audio support is now enabled by default when liblc3 is available now that
61
bluez has support for detecting the hardware features.
62
63
-Older versions:
64
-
65
-
66
# PipeWire 0.3.75 (2023-07-21)
67
68
This is a bugfix release that is API and ABI compatible with previous
69
pipewire-0.3.76.tar.gz/doc/dma-buf.dox -> pipewire-0.3.77.tar.gz/doc/dma-buf.dox
Changed
20
1
2
In cases where mapping a single plane is required the size should be obtained locally
3
via the filedescriptor.
4
5
+# SPA param video format helpers
6
+
7
+SPA offers helper functions to parse and build a spa_pod object to/from the spa_video_info_*
8
+struct. The flags `SPA_VIDEO_FLAG_MODIFIER` and `SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED`
9
+are used to indicate modifier usage with the format. `SPA_VIDEO_FLAG_MODIFIER` declares the
10
+parsed/provided spa_video_info_* struct contains valid modifier information. For legacy
11
+reasons `spa_format_video_*_build` will announce any modifier != 0 even when this flag is
12
+unused. `SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED` is exclusive to the parse helpers and
13
+declares that the parsed spa_pod contains modifier information which needs to be fixated as
14
+described aboath. The list of available modifiers has to be parsed manually from the spa_pod
15
+object.
16
+
17
# v4l2
18
19
Another use case for streaming via DMA-BUFs are exporting a camera feed from v4l2
20
pipewire-0.3.76.tar.gz/meson.build -> pipewire-0.3.77.tar.gz/meson.build
Changed
24
1
2
project('pipewire', 'c' ,
3
- version : '0.3.76',
4
+ version : '0.3.77',
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
9
soversion = 0
10
libversion = '@0@.@1@.0'.format(soversion, pipewire_version_minor.to_int() * 100 + pipewire_version_micro.to_int())
11
12
+# LADI/jack
13
+# 3, for PipeWire being the third JACK implementation, after JACK1 and jackdmp/JACK2)
14
+jack_version_major = 3
15
+jack_version_minor = pipewire_version_minor.to_int() * 100 + pipewire_version_micro.to_int()
16
+# libjackserver version has 0 for major (for compatibility with other implementations),
17
+# 3 for minor, and "100*pipewire_version_minor + pipewire_version_micro"
18
+# as micro version (the minor libpipewire soversion number)
19
+libjackversion = '@0@.@1@.@2@'.format(soversion, jack_version_major, jack_version_minor)
20
+
21
pipewire_name = 'pipewire-@0@'.format(apiversion)
22
spa_name = 'spa-@0@'.format(spaversion)
23
24
pipewire-0.3.76.tar.gz/pipewire-jack/src/meson.build -> pipewire-0.3.77.tar.gz/pipewire-jack/src/meson.build
Changed
28
1
2
pipewire_jack = shared_library('jack',
3
pipewire_jack_sources,
4
soversion : soversion,
5
- version : libversion,
6
+ version : libjackversion,
7
c_args : pipewire_jack_c_args,
8
include_directories : configinc, jack_inc,
9
dependencies : pipewire_dep, mathlib,
10
11
pipewire_jackserver = shared_library('jackserver',
12
pipewire_jackserver_sources,
13
soversion : soversion,
14
- version : libversion,
15
+ version : libjackversion,
16
c_args : pipewire_jack_c_args,
17
include_directories : configinc, jack_inc,
18
dependencies : pipewire_dep, mathlib,
19
20
pipewire_jacknet = shared_library('jacknet',
21
pipewire_net_sources,
22
soversion : soversion,
23
- version : libversion,
24
+ version : libjackversion,
25
c_args : pipewire_jack_c_args,
26
include_directories : configinc, jack_inc,
27
dependencies : pipewire_dep, mathlib,
28
pipewire-0.3.76.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.77.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
169
1
2
char node_name512;
3
int32_t priority;
4
uint32_t client_id;
5
+ unsigned is_jack:1;
6
+ unsigned is_running:1;
7
} node;
8
struct {
9
uint32_t src;
10
11
int32_t avail;
12
uint32_t index;
13
struct notify *notify;
14
+ bool do_graph = false;
15
16
if (c->frozen_callbacks != 0 || !c->pending_callbacks)
17
return;
18
19
o->port_link.dst_serial,
20
notify->arg1,
21
c->connect_arg);
22
+
23
+ do_graph = true;
24
break;
25
case NOTIFY_TYPE_GRAPH:
26
pw_log_debug("%p: graph", c);
27
- recompute_latencies(c);
28
- do_callback(c, graph_callback, c->active, c->graph_arg);
29
+ do_graph = true;
30
break;
31
case NOTIFY_TYPE_BUFFER_FRAMES:
32
pw_log_debug("%p: buffer frames %d", c, notify->arg1);
33
34
index += sizeof(struct notify);
35
spa_ringbuffer_read_update(&c->notify_ring, index);
36
}
37
+ if (do_graph) {
38
+ recompute_latencies(c);
39
+ do_callback(c, graph_callback, c->active, c->graph_arg);
40
+ }
41
thaw_callbacks(c);
42
pw_log_debug("%p: leave", c);
43
}
44
45
.destroy = proxy_destroy,
46
};
47
48
+static void node_info(void *data, const struct pw_node_info *info)
49
+{
50
+ struct object *n = data;
51
+ struct client *c = n->client;
52
+
53
+ pw_log_info("DSP node %d state change %s", info->id,
54
+ pw_node_state_as_string(info->state));
55
+
56
+ n->node.is_running = (info->state == PW_NODE_STATE_RUNNING);
57
+
58
+ if (info->change_mask & PW_NODE_CHANGE_MASK_STATE) {
59
+ struct object *p;
60
+ spa_list_for_each(p, &c->context.objects, link) {
61
+ if (p->type != INTERFACE_Port || p->removed ||
62
+ p->port.node_id != info->id)
63
+ continue;
64
+ if (n->node.is_running)
65
+ queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, p, 1, NULL);
66
+ else
67
+ queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, p, 0, NULL);
68
+ }
69
+ }
70
+}
71
+
72
+static const struct pw_node_events node_events = {
73
+ PW_VERSION_NODE,
74
+ .info = node_info,
75
+};
76
+
77
static void port_param(void *data, int seq,
78
uint32_t id, uint32_t index, uint32_t next,
79
const struct spa_pod *param)
80
81
struct client *c = (struct client *) data;
82
struct object *o, *ot, *op;
83
const char *str;
84
- bool is_first = true;
85
+ bool do_emit = true;
86
uint32_t serial;
87
88
if (props == NULL)
89
90
snprintf(o->node.name, sizeof(o->node.name), "%.*s-%d",
91
(int)(sizeof(tmp)-11), tmp, id);
92
} else {
93
- is_first = ot == NULL;
94
+ do_emit = ot == NULL;
95
snprintf(o->node.name, sizeof(o->node.name), "%s", tmp);
96
}
97
if (id == c->node_id) {
98
99
100
if ((str = spa_dict_lookup(props, PW_KEY_PRIORITY_SESSION)) != NULL)
101
o->node.priority = pw_properties_parse_int(str);
102
+ if ((str = spa_dict_lookup(props, PW_KEY_CLIENT_API)) != NULL)
103
+ o->node.is_jack = spa_streq(str, "jack");
104
105
pw_log_debug("%p: add node %d", c, id);
106
107
+ if (o->node.is_jack) {
108
+ o->proxy = pw_registry_bind(c->registry,
109
+ id, type, PW_VERSION_NODE, 0);
110
+ if (o->proxy) {
111
+ pw_proxy_add_listener(o->proxy,
112
+ &o->proxy_listener, &proxy_events, o);
113
+ pw_proxy_add_object_listener(o->proxy,
114
+ &o->object_listener, &node_events, o);
115
+ }
116
+ }
117
pthread_mutex_lock(&c->context.lock);
118
spa_list_append(&c->context.objects, &o->link);
119
pthread_mutex_unlock(&c->context.lock);
120
121
o->port.latencySPA_DIRECTION_INPUT = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
122
o->port.latencySPA_DIRECTION_OUTPUT = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
123
124
+ do_emit = !ot->node.is_jack || ot->node.is_running;
125
+
126
o->proxy = pw_registry_bind(c->registry,
127
id, type, PW_VERSION_PORT, 0);
128
if (o->proxy) {
129
130
131
switch (o->type) {
132
case INTERFACE_Node:
133
- if (is_first) {
134
- pw_log_info("%p: client added \"%s\"", c, o->node.name);
135
+ pw_log_info("%p: client added \"%s\" emit:%d", c, o->node.name, do_emit);
136
+ if (do_emit)
137
queue_notify(c, NOTIFY_TYPE_REGISTRATION, o, 1, NULL);
138
- }
139
break;
140
141
case INTERFACE_Port:
142
- pw_log_info("%p: port added %u/%u \"%s\"", c, o->id, o->serial, o->port.name);
143
- queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, o, 1, NULL);
144
+ pw_log_info("%p: port added %u/%u \"%s\" emit:%d", c, o->id,
145
+ o->serial, o->port.name, do_emit);
146
+ if (do_emit)
147
+ queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, o, 1, NULL);
148
break;
149
150
case INTERFACE_Link:
151
pw_log_info("%p: link %u %u/%u -> %u/%u added", c,
152
o->id, o->port_link.src, o->port_link.src_serial,
153
o->port_link.dst, o->port_link.dst_serial);
154
- queue_notify(c, NOTIFY_TYPE_CONNECT, o, 1, NULL);
155
- queue_notify(c, NOTIFY_TYPE_GRAPH, NULL, 0, NULL);
156
+ if (do_emit)
157
+ queue_notify(c, NOTIFY_TYPE_CONNECT, o, 1, NULL);
158
break;
159
}
160
emit_callbacks(c);
161
162
o->port_link.src, o->port_link.src_serial,
163
o->port_link.dst, o->port_link.dst_serial);
164
queue_notify(c, NOTIFY_TYPE_CONNECT, o, 0, NULL);
165
- queue_notify(c, NOTIFY_TYPE_GRAPH, NULL, 0, NULL);
166
} else {
167
pw_log_warn("unlink between unknown ports %d and %d",
168
o->port_link.src, o->port_link.dst);
169
pipewire-0.3.76.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c -> pipewire-0.3.77.tar.gz/pipewire-v4l2/src/pipewire-v4l2.c
Changed
11
1
2
MAKE_FORMAT(Y10, video, raw, 2, UNKNOWN),
3
MAKE_FORMAT(Y12, video, raw, 2, UNKNOWN),
4
MAKE_FORMAT(Y16, video, raw, 2, GRAY16_LE),
5
+#ifdef V4L2_PIX_FMT_Y16_BE
6
MAKE_FORMAT(Y16_BE, video, raw, 2, GRAY16_BE),
7
+#endif
8
MAKE_FORMAT(Y10BPACK, video, raw, 2, UNKNOWN),
9
10
/* Palette formats */
11
pipewire-0.3.76.tar.gz/spa/include/spa/utils/cleanup.h -> pipewire-0.3.77.tar.gz/spa/include/spa/utils/cleanup.h
Changed
38
1
2
_old_value; \
3
})
4
5
+#if __GNUC__ > 10 || defined(__clang__)
6
#define spa_steal_ptr(ptr) ((__typeof__(*(ptr)) *) spa_exchange((ptr), NULL))
7
+#else
8
+#define spa_steal_ptr(ptr) ((__typeof__(ptr)) spa_exchange((ptr), NULL))
9
+#endif
10
+
11
#define spa_steal_fd(fd) spa_exchange((fd), -1)
12
13
/* ========================================================================== */
14
15
#include <stdlib.h>
16
17
+
18
+#if __GNUC__ > 10 || defined(__clang__)
19
#define spa_clear_ptr(ptr, destructor) \
20
__extension__ ({ \
21
__typeof__(*(ptr)) *_old_value = spa_steal_ptr(ptr); \
22
23
destructor(_old_value); \
24
(void) 0; \
25
})
26
+#else
27
+#define spa_clear_ptr(ptr, destructor) \
28
+__extension__ ({ \
29
+ __typeof__(ptr) _old_value = spa_steal_ptr(ptr); \
30
+ if (_old_value) \
31
+ destructor(_old_value); \
32
+ (void) 0; \
33
+})
34
+#endif
35
36
static inline void _spa_autofree_cleanup_func(void *p)
37
{
38
pipewire-0.3.76.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.77.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
14
1
2
3
if (avail < target)
4
max_read = target - avail;
5
- else if (avail > target)
6
+ else if (avail > target) {
7
snd_pcm_forward(state->hndl, avail - target);
8
- avail = target;
9
+ avail = target;
10
+ }
11
state->alsa_sync = false;
12
} else
13
state->alsa_sync_warning = true;
14
pipewire-0.3.76.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.77.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
129
1
2
3
#include <spa/support/plugin.h>
4
#include <spa/support/cpu.h>
5
+#include <spa/support/loop.h>
6
#include <spa/support/log.h>
7
#include <spa/utils/result.h>
8
#include <spa/utils/list.h>
9
#include <spa/utils/json.h>
10
#include <spa/utils/names.h>
11
#include <spa/utils/string.h>
12
+#include <spa/utils/ratelimit.h>
13
#include <spa/node/node.h>
14
#include <spa/node/io.h>
15
#include <spa/node/utils.h>
16
17
uint32_t quantum_limit;
18
enum spa_direction direction;
19
20
+ struct spa_ratelimit rate_limit;
21
+
22
struct props props;
23
24
struct spa_io_position *io_position;
25
26
{
27
struct buffer *b;
28
29
- if (spa_list_is_empty(&port->queue)) {
30
- if (port->n_buffers > 0)
31
- spa_log_warn(this->log, "%p: out of buffers on port %d %d",
32
- this, port->id, port->n_buffers);
33
+ if (spa_list_is_empty(&port->queue))
34
return NULL;
35
- }
36
37
b = spa_list_first(&port->queue, struct buffer, link);
38
spa_log_trace_fp(this->log, "%p: peek buffer %d/%d on port %d %u",
39
40
41
static inline void dequeue_buffer(struct impl *this, struct port *port, struct buffer *b)
42
{
43
- spa_list_remove(&b->link);
44
- SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_QUEUED);
45
spa_log_trace_fp(this->log, "%p: dequeue buffer %d on port %d %u",
46
this, b->id, port->id, b->flags);
47
+ if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_QUEUED))
48
+ return;
49
+ spa_list_remove(&b->link);
50
+ SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_QUEUED);
51
}
52
53
static int
54
55
return true;
56
}
57
58
+static uint64_t get_time_ns(struct impl *impl)
59
+{
60
+ struct timespec now;
61
+ if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
62
+ return 0;
63
+ return SPA_TIMESPEC_TO_NSEC(&now);
64
+}
65
+
66
static int impl_node_process(void *object)
67
{
68
struct impl *this = object;
69
70
struct buffer *buf, *out_bufsMAX_PORTS;
71
struct spa_data *bd;
72
struct dir *dir;
73
- int tmp = 0, res = 0;
74
+ int tmp = 0, res = 0, missed;
75
bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough;
76
bool in_avail = false, flush_in = false, flush_out = false;
77
bool draining = false, in_empty = this->out_offset == 0;
78
struct spa_io_buffers *io, *ctrlio = NULL;
79
const struct spa_pod_sequence *ctrl = NULL;
80
+ uint64_t current_time;
81
82
/* calculate quantum scale, this is how many samples we need to produce or
83
* consume. Also update the rate scale, this is sent to the resampler to adjust
84
85
if (SPA_LIKELY(this->io_position)) {
86
double r = this->rate_scale;
87
88
+ current_time = this->io_position->clock.nsec;
89
quant_samples = this->io_position->clock.duration;
90
if (this->direction == SPA_DIRECTION_INPUT) {
91
if (this->io_position->clock.rate.denom != this->resample.o_rate)
92
93
this->rate_scale = r;
94
}
95
}
96
- else
97
+ else {
98
+ current_time = get_time_ns(this);
99
quant_samples = this->quantum_limit;
100
+ }
101
102
dir = &this->dirSPA_DIRECTION_INPUT;
103
in_passthrough = dir->conv.is_passthrough;
104
105
queue_buffer(this, port, io->buffer_id);
106
107
buf = peek_buffer(this, port);
108
+ if (buf == NULL && port->n_buffers > 0 &&
109
+ (missed = spa_ratelimit_test(&this->rate_limit, current_time)) >= 0) {
110
+ spa_log_warn(this->log, "%p: (%d missed) out of buffers on port %d %d",
111
+ this, missed, port->id, port->n_buffers);
112
+ }
113
}
114
out_bufsi = buf;
115
116
117
this->cpu_flags = spa_cpu_get_flags(this->cpu);
118
this->max_align = SPA_MIN(MAX_ALIGN, spa_cpu_get_max_align(this->cpu));
119
}
120
-
121
props_reset(&this->props);
122
123
+ this->rate_limit.interval = 2 * SPA_NSEC_PER_SEC;
124
+ this->rate_limit.burst = 1;
125
+
126
this->mix.options = CHANNELMIX_OPTION_UPMIX | CHANNELMIX_OPTION_MIX_LFE;
127
this->mix.upmix = CHANNELMIX_UPMIX_NONE;
128
this->mix.log = this->log;
129
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/backend-hsphfpd.c
Changed
510
1
2
{
3
spa_list_remove(&endpoint->link);
4
free(endpoint->path);
5
- if (endpoint->local_address)
6
- free(endpoint->local_address);
7
- if (endpoint->remote_address)
8
- free(endpoint->remote_address);
9
+ free(endpoint->local_address);
10
+ free(endpoint->remote_address);
11
+ free(endpoint);
12
}
13
14
static bool hsphfpd_cmp_transport_path(struct spa_bt_transport *t, const void *data)
15
16
int type,
17
void *value)
18
{
19
- DBusMessage *m, *r;
20
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
21
DBusMessageIter iter;
22
- DBusError err;
23
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
24
25
m = dbus_message_new_method_call(HSPHFPD_SERVICE, path, DBUS_INTERFACE_PROPERTIES, "Set");
26
if (m == NULL)
27
28
dbus_message_iter_init_append(m, &iter);
29
dbus_message_iter_append_basic(&iter, type, value);
30
31
- dbus_error_init(&err);
32
-
33
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
34
- dbus_message_unref(m);
35
- m = NULL;
36
-
37
if (r == NULL) {
38
spa_log_error(backend->log, "Transport Set() failed for transport %s (%s)", path, err.message);
39
- dbus_error_free(&err);
40
return -EIO;
41
}
42
43
44
return -EIO;
45
}
46
47
- dbus_message_unref(r);
48
return 0;
49
}
50
51
52
const char *interface;
53
const char *property;
54
const char *agent_codec;
55
- DBusMessage *r = NULL;
56
+ spa_autoptr(DBusMessage) r = NULL;
57
58
if (!check_signature(m, "ss")) {
59
r = dbus_message_new_error(m, DBUS_ERROR_INVALID_ARGS, "Invalid signature in method call");
60
61
if (!dbus_connection_send(conn, r, NULL))
62
return DBUS_HANDLER_RESULT_NEED_MEMORY;
63
64
- dbus_message_unref(r);
65
return DBUS_HANDLER_RESULT_HANDLED;
66
}
67
68
69
const char *interface;
70
DBusMessageIter iter, array, dict, data;
71
const char *agent_codec;
72
- DBusMessage *r = NULL;
73
+ spa_autoptr(DBusMessage) r = NULL;
74
75
if (!check_signature(m, "s")) {
76
r = dbus_message_new_error(m, DBUS_ERROR_INVALID_ARGS, "Invalid signature in method call");
77
78
if (!dbus_connection_send(conn, r, NULL))
79
return DBUS_HANDLER_RESULT_NEED_MEMORY;
80
81
- dbus_message_unref(r);
82
return DBUS_HANDLER_RESULT_HANDLED;
83
}
84
85
86
struct impl *backend = userdata;
87
DBusMessageIter arg_i;
88
const char *transport_path;
89
- int fd;
90
const char *sender;
91
const char *endpoint_path = NULL;
92
const char *air_codec = NULL;
93
94
struct hsphfpd_endpoint *endpoint;
95
struct spa_bt_transport *transport;
96
struct hsphfpd_transport_data *transport_data;
97
- DBusMessage *r = NULL;
98
+ spa_autoptr(DBusMessage) r = NULL;
99
+ spa_autoclose int fd = -1;
100
101
if (!check_signature(m, "oha{sv}")) {
102
r = dbus_message_new_error(m, DBUS_ERROR_INVALID_ARGS, "Invalid signature in method call");
103
104
105
sender = dbus_message_get_sender(m);
106
if (!spa_streq(sender, backend->hsphfpd_service_id)) {
107
- close(fd);
108
spa_log_error(backend->log, "Sender '%s' is not authorized", sender);
109
r = dbus_message_new_error_printf(m, HSPHFPD_ERROR_REJECTED, "Sender '%s' is not authorized", sender);
110
goto fail;
111
112
&mtu);
113
114
if (!endpoint_path) {
115
- close(fd);
116
spa_log_error(backend->log, "Endpoint property was not specified");
117
r = dbus_message_new_error(m, HSPHFPD_ERROR_REJECTED, "Endpoint property was not specified");
118
goto fail;
119
}
120
121
if (!air_codec) {
122
- close(fd);
123
spa_log_error(backend->log, "AirCodec property was not specified");
124
r = dbus_message_new_error(m, HSPHFPD_ERROR_REJECTED, "AirCodec property was not specified");
125
goto fail;
126
}
127
128
if (!rx_volume_control) {
129
- close(fd);
130
spa_log_error(backend->log, "RxVolumeControl property was not specified");
131
r = dbus_message_new_error(m, HSPHFPD_ERROR_REJECTED, "RxVolumeControl property was not specified");
132
goto fail;
133
}
134
135
if (!tx_volume_control) {
136
- close(fd);
137
spa_log_error(backend->log, "TxVolumeControl property was not specified");
138
r = dbus_message_new_error(m, HSPHFPD_ERROR_REJECTED, "TxVolumeControl property was not specified");
139
goto fail;
140
141
142
if (rx_volume_control != HSPHFPD_VOLUME_CONTROL_NONE) {
143
if (rx_volume_gain == (uint16_t)-1) {
144
- close(fd);
145
spa_log_error(backend->log, "RxVolumeGain property was not specified, but VolumeControl is not none");
146
r = dbus_message_new_error(m, HSPHFPD_ERROR_REJECTED, "RxVolumeGain property was not specified, but VolumeControl is not none");
147
goto fail;
148
149
150
if (tx_volume_control != HSPHFPD_VOLUME_CONTROL_NONE) {
151
if (tx_volume_gain == (uint16_t)-1) {
152
- close(fd);
153
spa_log_error(backend->log, "TxVolumeGain property was not specified, but VolumeControl is not none");
154
r = dbus_message_new_error(m, HSPHFPD_ERROR_REJECTED, "TxVolumeGain property was not specified, but VolumeControl is not none");
155
goto fail;
156
157
}
158
159
if (!mtu) {
160
- close(fd);
161
spa_log_error(backend->log, "MTU property was not specified");
162
r = dbus_message_new_error(m, HSPHFPD_ERROR_REJECTED, "MTU property was not specified");
163
goto fail;
164
165
166
endpoint = endpoint_find(backend, endpoint_path);
167
if (!endpoint) {
168
- close(fd);
169
spa_log_error(backend->log, "Endpoint %s does not exist", endpoint_path);
170
r = dbus_message_new_error_printf(m, HSPHFPD_ERROR_REJECTED, "Endpoint %s does not exist", endpoint_path);
171
goto fail;
172
}
173
174
if (!endpoint->valid) {
175
- close(fd);
176
spa_log_error(backend->log, "Endpoint %s is not valid", endpoint_path);
177
r = dbus_message_new_error_printf(m, HSPHFPD_ERROR_REJECTED, "Endpoint %s is not valid", endpoint_path);
178
goto fail;
179
180
181
transport = spa_bt_transport_find(backend->monitor, endpoint_path);
182
if (!transport) {
183
- close(fd);
184
spa_log_error(backend->log, "Endpoint %s is not connected", endpoint_path);
185
r = dbus_message_new_error_printf(m, HSPHFPD_ERROR_REJECTED, "Endpoint %s is not connected", endpoint_path);
186
goto fail;
187
188
spa_log_warn(backend->log, "Expecting codec to be %d, got %d", transport->codec, codec);
189
190
if (transport->fd >= 0) {
191
- close(fd);
192
spa_log_error(backend->log, "Endpoint %s has already active transport", endpoint_path);
193
r = dbus_message_new_error_printf(m, HSPHFPD_ERROR_REJECTED, "Endpoint %s has already active transport", endpoint_path);
194
goto fail;
195
196
transport->read_mtu = mtu;
197
transport->write_mtu = mtu;
198
199
- transport->fd = fd;
200
+ transport->fd = spa_steal_fd(fd);
201
202
if ((r = dbus_message_new_method_return(m)) == NULL)
203
return DBUS_HANDLER_RESULT_NEED_MEMORY;
204
205
fail:
206
if (r) {
207
- DBusHandlerResult res = DBUS_HANDLER_RESULT_HANDLED;
208
if (!dbus_connection_send(backend->conn, r, NULL))
209
- res = DBUS_HANDLER_RESULT_NEED_MEMORY;
210
- dbus_message_unref(r);
211
- return res;
212
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
213
}
214
215
return DBUS_HANDLER_RESULT_HANDLED;
216
217
{
218
struct impl *backend = userdata;
219
const char *path, *interface, *member;
220
- DBusMessage *r;
221
DBusHandlerResult res;
222
223
path = dbus_message_get_path(m);
224
225
226
if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
227
const char *xml = AUDIO_AGENT_ENDPOINT_INTROSPECT_XML;
228
+ spa_autoptr(DBusMessage) r = NULL;
229
230
if ((r = dbus_message_new_method_return(m)) == NULL)
231
return DBUS_HANDLER_RESULT_NEED_MEMORY;
232
233
if (!dbus_connection_send(backend->conn, r, NULL))
234
return DBUS_HANDLER_RESULT_NEED_MEMORY;
235
236
- dbus_message_unref(r);
237
res = DBUS_HANDLER_RESULT_HANDLED;
238
} else if (dbus_message_is_method_call(m, DBUS_INTERFACE_PROPERTIES, "Get"))
239
res = audio_agent_get_property(c, m, path, userdata);
240
241
{
242
struct impl *backend = userdata;
243
const char *path, *interface, *member;
244
- DBusMessage *r;
245
+ spa_autoptr(DBusMessage) r = NULL;
246
247
path = dbus_message_get_path(m);
248
interface = dbus_message_get_interface(m);
249
250
251
if (!dbus_connection_send(backend->conn, r, NULL))
252
return DBUS_HANDLER_RESULT_NEED_MEMORY;
253
- dbus_message_unref(r);
254
255
- return DBUS_HANDLER_RESULT_HANDLED;
256
+ return DBUS_HANDLER_RESULT_HANDLED;
257
}
258
259
static void hsphfpd_audio_acquire_reply(DBusPendingCall *pending, void *user_data)
260
{
261
struct spa_bt_transport *transport = user_data;
262
struct impl *backend = SPA_CONTAINER_OF(transport->backend, struct impl, this);
263
- DBusMessage *r;
264
const char *transport_path;
265
const char *service_id;
266
const char *agent_path;
267
- DBusError error;
268
+ spa_auto(DBusError) error = DBUS_ERROR_INIT;
269
int ret = 0;
270
271
- dbus_error_init(&error);
272
-
273
backend->acquire_in_progress = false;
274
275
- r = steal_reply_and_unref(&pending);
276
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
277
if (r == NULL)
278
return;
279
280
281
spa_log_debug(backend->log, "hsphfpd audio acquired");
282
283
finish:
284
- dbus_message_unref(r);
285
-
286
if (ret < 0)
287
spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ERROR);
288
else
289
290
{
291
struct spa_bt_transport *transport = data;
292
struct impl *backend = SPA_CONTAINER_OF(transport->backend, struct impl, this);
293
- DBusMessage *m;
294
+ spa_autoptr(DBusMessage) m = NULL;
295
const char *air_codec = HSPHFP_AIR_CODEC_CVSD;
296
const char *agent_codec = HSPHFP_AGENT_CODEC_PCM;
297
- DBusPendingCall *call;
298
299
spa_log_debug(backend->log, "transport %p: Acquire %s",
300
transport, transport->path);
301
302
return -ENOMEM;
303
dbus_message_append_args(m, DBUS_TYPE_STRING, &air_codec, DBUS_TYPE_STRING, &agent_codec, DBUS_TYPE_INVALID);
304
305
- dbus_connection_send_with_reply(backend->conn, m, &call, -1);
306
- dbus_pending_call_set_notify(call, hsphfpd_audio_acquire_reply, transport, NULL);
307
- dbus_message_unref(m);
308
+ if (!send_with_reply(backend->conn, m, hsphfpd_audio_acquire_reply, transport))
309
+ return -EIO;
310
311
backend->acquire_in_progress = true;
312
313
314
static void hsphfpd_get_endpoints_reply(DBusPendingCall *pending, void *user_data)
315
{
316
struct impl *backend = user_data;
317
- DBusMessage *r;
318
DBusMessageIter i, array_i;
319
320
- r = steal_reply_and_unref(&pending);
321
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
322
if (r == NULL)
323
return;
324
325
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
326
spa_log_error(backend->log, "Failed to get a list of endpoints from hsphfpd: %s",
327
dbus_message_get_error_name(r));
328
- goto finish;
329
+ return;
330
}
331
332
if (!spa_streq(dbus_message_get_sender(r), backend->hsphfpd_service_id)) {
333
spa_log_error(backend->log, "Reply for GetManagedObjects() from invalid sender");
334
- goto finish;
335
+ return;
336
}
337
338
if (!dbus_message_iter_init(r, &i) || !check_signature(r, "a{oa{sa{sv}}}")) {
339
spa_log_error(backend->log, "Invalid arguments in GetManagedObjects() reply");
340
- goto finish;
341
+ return;
342
}
343
344
dbus_message_iter_recurse(&i, &array_i);
345
346
}
347
348
backend->endpoints_listed = true;
349
-
350
-finish:
351
- dbus_message_unref(r);
352
}
353
354
-static int backend_hsphfpd_register(void *data)
355
+static int hsphfpd_register(struct impl *backend)
356
{
357
- struct impl *backend = data;
358
- DBusMessage *m, *r;
359
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
360
const char *path = APPLICATION_OBJECT_MANAGER_PATH;
361
- DBusPendingCall *call;
362
- DBusError err;
363
- int res;
364
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
365
366
spa_log_debug(backend->log, "Registering to hsphfpd");
367
368
369
370
dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
371
372
- dbus_error_init(&err);
373
-
374
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
375
- dbus_message_unref(m);
376
-
377
if (r == NULL) {
378
if (dbus_error_has_name(&err, "org.freedesktop.DBus.Error.ServiceUnknown")) {
379
spa_log_info(backend->log, "hsphfpd not available: %s",
380
err.message);
381
- res = -ENOTSUP;
382
+ return -ENOTSUP;
383
} else {
384
spa_log_warn(backend->log, "Registering application %s failed: %s (%s)",
385
path, err.message, err.name);
386
- res = -EIO;
387
+ return -EIO;
388
}
389
- dbus_error_free(&err);
390
- return res;
391
}
392
393
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
394
spa_log_error(backend->log, "RegisterApplication() failed: %s",
395
dbus_message_get_error_name(r));
396
- goto finish;
397
+ return -EIO;
398
}
399
- dbus_message_unref(r);
400
401
backend->hsphfpd_service_id = strdup(dbus_message_get_sender(r));
402
403
spa_log_debug(backend->log, "Registered to hsphfpd");
404
405
+ return 0;
406
+}
407
+
408
+static int hsphfpd_get_endpoints(struct impl *backend)
409
+{
410
+ spa_autoptr(DBusMessage) m = NULL;
411
+
412
m = dbus_message_new_method_call(HSPHFPD_SERVICE, "/",
413
DBUS_INTERFACE_OBJECTMANAGER, "GetManagedObjects");
414
if (m == NULL)
415
- goto finish;
416
+ return -ENOMEM;
417
418
- dbus_connection_send_with_reply(backend->conn, m, &call, -1);
419
- dbus_pending_call_set_notify(call, hsphfpd_get_endpoints_reply, backend, NULL);
420
- dbus_message_unref(m);
421
+ if (!send_with_reply(backend->conn, m, hsphfpd_get_endpoints_reply, backend))
422
+ return -EIO;
423
424
return 0;
425
+}
426
427
-finish:
428
- dbus_message_unref(r);
429
- return -EIO;
430
+static int backend_hsphfpd_register(void *data)
431
+{
432
+ int ret = hsphfpd_register(data);
433
+ if (ret < 0)
434
+ return ret;
435
+
436
+ ret = hsphfpd_get_endpoints(data);
437
+ if (ret < 0)
438
+ return ret;
439
+
440
+ return 0;
441
}
442
443
static int backend_hsphfpd_unregistered(void *data)
444
445
static int add_filters(void *data)
446
{
447
struct impl *backend = data;
448
- DBusError err;
449
450
if (backend->filters_added)
451
return 0;
452
453
- dbus_error_init(&err);
454
-
455
if (!dbus_connection_add_filter(backend->conn, hsphfpd_filter_cb, backend, NULL)) {
456
spa_log_error(backend->log, "failed to add filter function");
457
- goto fail;
458
+ return -EIO;
459
}
460
461
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
462
+
463
dbus_bus_add_match(backend->conn,
464
"type='signal',sender='" HSPHFPD_SERVICE "',"
465
"interface='" DBUS_INTERFACE_OBJECTMANAGER "',member='InterfacesAdded'", &err);
466
467
backend->filters_added = true;
468
469
return 0;
470
-
471
-fail:
472
- dbus_error_free(&err);
473
- return -EIO;
474
}
475
476
static int backend_hsphfpd_free(void *data)
477
478
479
static bool is_available(struct impl *backend)
480
{
481
- DBusMessage *m, *r;
482
- DBusError err;
483
- bool success = false;
484
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
485
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
486
487
m = dbus_message_new_method_call(HSPHFPD_SERVICE, "/",
488
DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
489
if (m == NULL)
490
return false;
491
492
- dbus_error_init(&err);
493
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
494
- dbus_message_unref(m);
495
-
496
if (r && dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
497
- success = true;
498
-
499
- if (r)
500
- dbus_message_unref(r);
501
- else
502
- dbus_error_free(&err);
503
+ return true;
504
505
- return success;
506
+ return false;
507
}
508
509
struct spa_bt_backend *backend_hsphfpd_new(struct spa_bt_monitor *monitor,
510
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
471
1
2
3
static DBusHandlerResult profile_release(DBusConnection *conn, DBusMessage *m, void *userdata)
4
{
5
- DBusMessage *r;
6
-
7
- r = dbus_message_new_error(m, BLUEZ_PROFILE_INTERFACE ".Error.NotImplemented",
8
- "Method not implemented");
9
- if (r == NULL)
10
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
11
- if (!dbus_connection_send(conn, r, NULL))
12
+ if (!reply_with_error(conn, m, BLUEZ_PROFILE_INTERFACE ".Error.NotImplemented", "Method not implemented"))
13
return DBUS_HANDLER_RESULT_NEED_MEMORY;
14
15
- dbus_message_unref(r);
16
return DBUS_HANDLER_RESULT_HANDLED;
17
}
18
19
20
struct sockaddr_sco addr;
21
socklen_t len;
22
bdaddr_t src;
23
- int sock = -1;
24
25
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_SCO);
26
+ spa_autoclose int sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_SCO);
27
if (sock < 0) {
28
spa_log_error(backend->log, "socket(SEQPACKET, SCO) %s", strerror(errno));
29
- goto fail;
30
+ return -1;
31
}
32
33
str2ba(adapter->address, &src);
34
35
36
if (bind(sock, (struct sockaddr *) &addr, len) < 0) {
37
spa_log_error(backend->log, "bind(): %s", strerror(errno));
38
- goto fail;
39
+ return -1;
40
}
41
42
spa_log_debug(backend->log, "msbc=%d", (int)msbc);
43
44
voice_config.setting = BT_VOICE_TRANSPARENT;
45
if (setsockopt(sock, SOL_BLUETOOTH, BT_VOICE, &voice_config, sizeof(voice_config)) < 0) {
46
spa_log_error(backend->log, "setsockopt(): %s", strerror(errno));
47
- goto fail;
48
+ return -1;
49
}
50
}
51
52
- return sock;
53
-
54
-fail:
55
- if (sock >= 0)
56
- close(sock);
57
- return -1;
58
+ return spa_steal_fd(sock);
59
}
60
61
static int sco_do_connect(struct spa_bt_transport *t)
62
63
struct spa_bt_device *d = t->device;
64
struct transport_data *td = t->user_data;
65
struct sockaddr_sco addr;
66
- socklen_t len;
67
int err;
68
- int sock;
69
- bdaddr_t dst;
70
- int retry = 2;
71
72
spa_log_debug(backend->log, "transport %p: enter sco_do_connect, codec=%u",
73
t, t->codec);
74
75
if (d->adapter == NULL)
76
return -EIO;
77
78
- str2ba(d->address, &dst);
79
-
80
-again:
81
- sock = sco_create_socket(backend, d->adapter, (t->codec == HFP_AUDIO_CODEC_MSBC));
82
- if (sock < 0)
83
- return -1;
84
-
85
- len = sizeof(addr);
86
- memset(&addr, 0, len);
87
+ spa_zero(addr);
88
addr.sco_family = AF_BLUETOOTH;
89
- bacpy(&addr.sco_bdaddr, &dst);
90
-
91
- spa_log_debug(backend->log, "transport %p: doing connect", t);
92
- err = connect(sock, (struct sockaddr *) &addr, len);
93
- if (err < 0 && errno == ECONNABORTED && retry-- > 0) {
94
- spa_log_warn(backend->log, "connect(): %s. Remaining retry:%d",
95
- strerror(errno), retry);
96
- close(sock);
97
- goto again;
98
- } else if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
99
- spa_log_error(backend->log, "connect(): %s", strerror(errno));
100
+ str2ba(d->address, &addr.sco_bdaddr);
101
+
102
+ for (int retry = 2;;) {
103
+ spa_autoclose int sock = sco_create_socket(backend, d->adapter, (t->codec == HFP_AUDIO_CODEC_MSBC));
104
+ if (sock < 0)
105
+ return -1;
106
+
107
+ spa_log_debug(backend->log, "transport %p: doing connect", t);
108
+ err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
109
+ if (err < 0 && errno == ECONNABORTED && retry-- > 0) {
110
+ spa_log_warn(backend->log, "connect(): %s. Remaining retry:%d",
111
+ strerror(errno), retry);
112
+ continue;
113
+ } else if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
114
+ spa_log_error(backend->log, "connect(): %s", strerror(errno));
115
#ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE
116
- if (errno == EOPNOTSUPP && t->codec == HFP_AUDIO_CODEC_MSBC &&
117
- td->rfcomm->msbc_supported_by_hfp) {
118
- /* Adapter doesn't support msbc. Renegotiate. */
119
- d->adapter->msbc_probed = true;
120
- d->adapter->has_msbc = false;
121
- td->rfcomm->msbc_supported_by_hfp = false;
122
- if (t->profile == SPA_BT_PROFILE_HFP_HF) {
123
- td->rfcomm->hfp_ag_switching_codec = true;
124
- rfcomm_send_reply(td->rfcomm, "+BCS: 1");
125
- } else if (t->profile == SPA_BT_PROFILE_HFP_AG) {
126
- rfcomm_send_cmd(td->rfcomm, "AT+BAC=1");
127
+ if (errno == EOPNOTSUPP && t->codec == HFP_AUDIO_CODEC_MSBC &&
128
+ td->rfcomm->msbc_supported_by_hfp) {
129
+ /* Adapter doesn't support msbc. Renegotiate. */
130
+ d->adapter->msbc_probed = true;
131
+ d->adapter->has_msbc = false;
132
+ td->rfcomm->msbc_supported_by_hfp = false;
133
+ if (t->profile == SPA_BT_PROFILE_HFP_HF) {
134
+ td->rfcomm->hfp_ag_switching_codec = true;
135
+ rfcomm_send_reply(td->rfcomm, "+BCS: 1");
136
+ } else if (t->profile == SPA_BT_PROFILE_HFP_AG) {
137
+ rfcomm_send_cmd(td->rfcomm, "AT+BAC=1");
138
+ }
139
}
140
- }
141
#endif
142
- goto fail_close;
143
- }
144
-
145
- td->err = -EINPROGRESS;
146
+ return -1;
147
+ }
148
149
- return sock;
150
+ td->err = -EINPROGRESS;
151
152
-fail_close:
153
- close(sock);
154
- return -1;
155
+ return spa_steal_fd(sock);
156
+ }
157
}
158
159
static int rfcomm_ag_sync_volume(struct rfcomm *rfcomm, bool later);
160
161
struct impl *backend = source->data;
162
struct sockaddr_sco addr;
163
socklen_t addrlen;
164
- int sock = -1;
165
char local_address18, remote_address18;
166
struct rfcomm *rfcomm;
167
struct spa_bt_transport *t = NULL;
168
169
if (source->rmask & (SPA_IO_HUP | SPA_IO_ERR)) {
170
spa_log_error(backend->log, "error listening SCO connection: %s", strerror(errno));
171
- goto fail;
172
+ return;
173
}
174
175
memset(&addr, 0, sizeof(addr));
176
addrlen = sizeof(addr);
177
178
spa_log_debug(backend->log, "doing accept");
179
- sock = accept(source->fd, (struct sockaddr *) &addr, &addrlen);
180
+ spa_autoclose int sock = accept(source->fd, (struct sockaddr *) &addr, &addrlen);
181
if (sock < 0) {
182
if (errno != EAGAIN)
183
spa_log_error(backend->log, "SCO accept(): %s", strerror(errno));
184
- goto fail;
185
+ return;
186
}
187
188
ba2str(&addr.sco_bdaddr, remote_address);
189
190
191
if (getsockname(sock, (struct sockaddr *) &addr, &addrlen) < 0) {
192
spa_log_error(backend->log, "SCO getsockname(): %s", strerror(errno));
193
- goto fail;
194
+ return;
195
}
196
197
ba2str(&addr.sco_bdaddr, local_address);
198
199
if (!t) {
200
spa_log_debug(backend->log, "No transport for adapter %s and remote %s",
201
local_address, remote_address);
202
- goto fail;
203
+ return;
204
}
205
206
/* The Synchronous Connection shall always be established by the AG, i.e. the remote profile
207
should be a HSP AG or HFP AG profile */
208
if ((t->profile & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY) == 0) {
209
spa_log_debug(backend->log, "transport %p: Rejecting incoming audio connection to an AG profile", t);
210
- goto fail;
211
+ return;
212
}
213
214
if (t->fd >= 0) {
215
spa_log_debug(backend->log, "transport %p: Rejecting, audio already connected", t);
216
- goto fail;
217
+ return;
218
}
219
220
spa_log_debug(backend->log, "transport %p: codec=%u", t, t->codec);
221
222
voice_config.setting = BT_VOICE_TRANSPARENT;
223
if (setsockopt(sock, SOL_BLUETOOTH, BT_VOICE, &voice_config, sizeof(voice_config)) < 0) {
224
spa_log_error(backend->log, "transport %p: setsockopt(): %s", t, strerror(errno));
225
- goto fail;
226
+ return;
227
}
228
}
229
230
/* First read from the accepted socket is non-blocking and returns a zero length buffer. */
231
if (read(sock, &buff, 1) == -1) {
232
spa_log_error(backend->log, "transport %p: Couldn't authorize SCO connection: %s", t, strerror(errno));
233
- goto fail;
234
+ return;
235
}
236
}
237
238
- t->fd = sock;
239
+ t->fd = spa_steal_fd(sock);
240
241
sco_start_source(t);
242
243
244
}
245
246
spa_bt_transport_set_state(t, SPA_BT_TRANSPORT_STATE_PENDING);
247
- return;
248
-
249
-fail:
250
- if (sock >= 0)
251
- close(sock);
252
- return;
253
}
254
255
-static int sco_listen(struct impl *backend)
256
+static void sco_listen(struct impl *backend)
257
{
258
struct sockaddr_sco addr;
259
- int sock;
260
uint32_t defer = 1;
261
262
- sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, BTPROTO_SCO);
263
+ spa_autoclose int sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, BTPROTO_SCO);
264
if (sock < 0) {
265
spa_log_error(backend->log, "socket(SEQPACKET, SCO) %m");
266
- return -errno;
267
+ return;
268
}
269
270
/* Bind to local address */
271
272
273
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
274
spa_log_error(backend->log, "bind(): %m");
275
- goto fail_close;
276
+ return;
277
}
278
279
if (setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &defer, sizeof(defer)) < 0) {
280
281
spa_log_debug(backend->log, "doing listen");
282
if (listen(sock, 1) < 0) {
283
spa_log_error(backend->log, "listen(): %m");
284
- goto fail_close;
285
+ return;
286
}
287
288
backend->sco.func = sco_listen_event;
289
backend->sco.data = backend;
290
- backend->sco.fd = sock;
291
+ backend->sco.fd = spa_steal_fd(sock);
292
backend->sco.mask = SPA_IO_IN;
293
backend->sco.rmask = 0;
294
spa_loop_add_source(backend->main_loop, &backend->sco);
295
296
- return sock;
297
-
298
-fail_close:
299
- close(sock);
300
- return -1;
301
+ return;
302
}
303
304
static int rfcomm_ag_set_volume(struct spa_bt_transport *t, int id)
305
306
static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessage *m, void *userdata)
307
{
308
struct impl *backend = userdata;
309
- DBusMessage *r;
310
+ spa_autoptr(DBusMessage) r = NULL;
311
DBusMessageIter it;
312
const char *handler, *path;
313
enum spa_bt_profile profile;
314
struct rfcomm *rfcomm;
315
struct spa_bt_device *d;
316
struct spa_bt_transport *t = NULL;
317
- int fd;
318
+ spa_autoclose int fd = -1;
319
320
if (!dbus_message_has_signature(m, "oha{sv}")) {
321
spa_log_warn(backend->log, "invalid NewConnection() signature");
322
323
rfcomm->path = strdup(path);
324
rfcomm->source.func = rfcomm_event;
325
rfcomm->source.data = rfcomm;
326
- rfcomm->source.fd = fd;
327
+ rfcomm->source.fd = spa_steal_fd(fd);
328
rfcomm->source.mask = SPA_IO_IN;
329
rfcomm->source.rmask = 0;
330
/* By default all indicators are enabled */
331
332
goto fail_need_memory;
333
if (!dbus_connection_send(conn, r, NULL))
334
goto fail_need_memory;
335
- dbus_message_unref(r);
336
337
return DBUS_HANDLER_RESULT_HANDLED;
338
339
340
static DBusHandlerResult profile_request_disconnection(DBusConnection *conn, DBusMessage *m, void *userdata)
341
{
342
struct impl *backend = userdata;
343
- DBusMessage *r;
344
+ spa_autoptr(DBusMessage) r = NULL;
345
const char *handler, *path;
346
struct spa_bt_device *d;
347
enum spa_bt_profile profile = SPA_BT_PROFILE_NULL;
348
349
if (!dbus_connection_send(conn, r, NULL))
350
return DBUS_HANDLER_RESULT_NEED_MEMORY;
351
352
- dbus_message_unref(r);
353
return DBUS_HANDLER_RESULT_HANDLED;
354
}
355
356
357
{
358
struct impl *backend = userdata;
359
const char *path, *interface, *member;
360
- DBusMessage *r;
361
DBusHandlerResult res;
362
363
path = dbus_message_get_path(m);
364
365
366
if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
367
const char *xml = PROFILE_INTROSPECT_XML;
368
+ spa_autoptr(DBusMessage) r = NULL;
369
370
if ((r = dbus_message_new_method_return(m)) == NULL)
371
return DBUS_HANDLER_RESULT_NEED_MEMORY;
372
373
if (!dbus_connection_send(backend->conn, r, NULL))
374
return DBUS_HANDLER_RESULT_NEED_MEMORY;
375
376
- dbus_message_unref(r);
377
res = DBUS_HANDLER_RESULT_HANDLED;
378
}
379
else if (dbus_message_is_method_call(m, BLUEZ_PROFILE_INTERFACE, "Release"))
380
381
static void register_profile_reply(DBusPendingCall *pending, void *user_data)
382
{
383
struct impl *backend = user_data;
384
- DBusMessage *r;
385
386
- r = steal_reply_and_unref(&pending);
387
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
388
if (r == NULL)
389
return;
390
391
if (dbus_message_is_error(r, BLUEZ_ERROR_NOT_SUPPORTED)) {
392
spa_log_warn(backend->log, "Register profile not supported");
393
- goto finish;
394
+ return;
395
}
396
if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
397
spa_log_warn(backend->log, "Error registering profile");
398
- goto finish;
399
+ return;
400
}
401
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
402
spa_log_error(backend->log, "RegisterProfile() failed: %s",
403
dbus_message_get_error_name(r));
404
- goto finish;
405
+ return;
406
}
407
-
408
-finish:
409
- dbus_message_unref(r);
410
}
411
412
static int register_profile(struct impl *backend, const char *profile, const char *uuid)
413
{
414
- DBusMessage *m;
415
+ spa_autoptr(DBusMessage) m = NULL;
416
DBusMessageIter it4;
417
dbus_bool_t autoconnect;
418
dbus_uint16_t version, chan, features;
419
char *str;
420
- DBusPendingCall *call;
421
422
if (!(backend->enabled_profiles & spa_bt_profile_from_uuid(uuid)))
423
return -ECANCELED;
424
425
}
426
dbus_message_iter_close_container(&it0, &it1);
427
428
- dbus_connection_send_with_reply(backend->conn, m, &call, -1);
429
- dbus_pending_call_set_notify(call, register_profile_reply, backend, NULL);
430
- dbus_message_unref(m);
431
+ if (!send_with_reply(backend->conn, m, register_profile_reply, backend))
432
+ return -EIO;
433
+
434
return 0;
435
}
436
437
static void unregister_profile(struct impl *backend, const char *profile)
438
{
439
- DBusMessage *m, *r;
440
- DBusError err;
441
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
442
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
443
444
spa_log_debug(backend->log, "Unregistering Profile %s", profile);
445
446
447
448
dbus_message_append_args(m, DBUS_TYPE_OBJECT_PATH, &profile, DBUS_TYPE_INVALID);
449
450
- dbus_error_init(&err);
451
-
452
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
453
- dbus_message_unref(m);
454
- m = NULL;
455
-
456
if (r == NULL) {
457
spa_log_info(backend->log, "Unregistering Profile %s failed", profile);
458
- dbus_error_free(&err);
459
return;
460
}
461
462
463
spa_log_error(backend->log, "UnregisterProfile() returned error: %s", dbus_message_get_error_name(r));
464
return;
465
}
466
-
467
- dbus_message_unref(r);
468
}
469
470
static int backend_native_register_profiles(void *data)
471
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/backend-ofono.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/backend-ofono.c
Changed
353
1
2
3
static int _audio_acquire(struct impl *backend, const char *path, uint8_t *codec)
4
{
5
- DBusMessage *m, *r;
6
- DBusError err;
7
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
8
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
9
int ret = 0;
10
11
m = dbus_message_new_method_call(OFONO_SERVICE, path,
12
13
if (m == NULL)
14
return -ENOMEM;
15
16
- dbus_error_init(&err);
17
18
/*
19
* XXX: We assume here oFono replies. It however can happen that the headset does
20
21
* XXX: do better here right now.
22
*/
23
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
24
- dbus_message_unref(m);
25
- m = NULL;
26
-
27
if (r == NULL) {
28
spa_log_error(backend->log, "Transport Acquire() failed for transport %s (%s)",
29
path, err.message);
30
- dbus_error_free(&err);
31
return -EIO;
32
}
33
34
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
35
spa_log_error(backend->log, "Acquire returned error: %s", dbus_message_get_error_name(r));
36
- ret = -EIO;
37
- goto finish;
38
+ return -EIO;
39
}
40
41
if (!dbus_message_get_args(r, &err,
42
43
DBUS_TYPE_BYTE, codec,
44
DBUS_TYPE_INVALID)) {
45
spa_log_error(backend->log, "Failed to parse Acquire() reply: %s", err.message);
46
- dbus_error_free(&err);
47
- ret = -EIO;
48
- goto finish;
49
+ return -EIO;
50
}
51
52
-finish:
53
- dbus_message_unref(r);
54
return ret;
55
}
56
57
58
static DBusHandlerResult ofono_release(DBusConnection *conn, DBusMessage *m, void *userdata)
59
{
60
struct impl *backend = userdata;
61
- DBusMessage *r;
62
63
spa_log_warn(backend->log, "release");
64
65
- r = dbus_message_new_error(m, OFONO_HF_AUDIO_AGENT_INTERFACE ".Error.NotImplemented",
66
- "Method not implemented");
67
- if (r == NULL)
68
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
69
- if (!dbus_connection_send(conn, r, NULL))
70
+ if (!reply_with_error(conn, m, OFONO_HF_AUDIO_AGENT_INTERFACE ".Error.NotImplemented", "Method not implemented"))
71
return DBUS_HANDLER_RESULT_NEED_MEMORY;
72
73
- dbus_message_unref(r);
74
return DBUS_HANDLER_RESULT_HANDLED;
75
}
76
77
78
uint8_t codec;
79
struct spa_bt_transport *t;
80
struct transport_data *td;
81
- DBusMessage *r = NULL;
82
+ spa_autoptr(DBusMessage) r = NULL;
83
84
if (dbus_message_get_args(m, NULL,
85
DBUS_TYPE_OBJECT_PATH, &path,
86
87
88
fail:
89
if (r) {
90
- DBusHandlerResult res = DBUS_HANDLER_RESULT_HANDLED;
91
if (!dbus_connection_send(backend->conn, r, NULL))
92
- res = DBUS_HANDLER_RESULT_NEED_MEMORY;
93
- dbus_message_unref(r);
94
- return res;
95
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
96
+ return DBUS_HANDLER_RESULT_HANDLED;
97
}
98
99
return DBUS_HANDLER_RESULT_HANDLED;
100
101
{
102
struct impl *backend = userdata;
103
const char *path, *interface, *member;
104
- DBusMessage *r;
105
DBusHandlerResult res;
106
107
path = dbus_message_get_path(m);
108
109
110
if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
111
const char *xml = OFONO_INTROSPECT_XML;
112
+ spa_autoptr(DBusMessage) r = NULL;
113
114
if ((r = dbus_message_new_method_return(m)) == NULL)
115
return DBUS_HANDLER_RESULT_NEED_MEMORY;
116
117
if (!dbus_connection_send(backend->conn, r, NULL))
118
return DBUS_HANDLER_RESULT_NEED_MEMORY;
119
120
- dbus_message_unref(r);
121
res = DBUS_HANDLER_RESULT_HANDLED;
122
}
123
else if (dbus_message_is_method_call(m, OFONO_HF_AUDIO_AGENT_INTERFACE, "Release"))
124
125
static void ofono_getcards_reply(DBusPendingCall *pending, void *user_data)
126
{
127
struct impl *backend = user_data;
128
- DBusMessage *r;
129
DBusMessageIter i, array_i, struct_i, props_i;
130
131
- r = steal_reply_and_unref(&pending);
132
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
133
if (r == NULL)
134
return;
135
136
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
137
spa_log_error(backend->log, "Failed to get a list of handsfree audio cards: %s",
138
dbus_message_get_error_name(r));
139
- goto finish;
140
+ return;
141
}
142
143
if (!dbus_message_iter_init(r, &i) || !spa_streq(dbus_message_get_signature(r), "a(oa{sv})")) {
144
spa_log_error(backend->log, "Invalid arguments in GetCards() reply");
145
- goto finish;
146
+ return;
147
}
148
149
dbus_message_iter_recurse(&i, &array_i);
150
151
152
dbus_message_iter_next(&array_i);
153
}
154
-
155
-finish:
156
- dbus_message_unref(r);
157
}
158
159
-static int backend_ofono_register(void *data)
160
+static int ofono_register(struct impl *backend)
161
{
162
- struct impl *backend = data;
163
-
164
- DBusMessage *m, *r;
165
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
166
const char *path = OFONO_AUDIO_CLIENT;
167
uint8_t codecs2;
168
const uint8_t *pcodecs = codecs;
169
- int ncodecs = 0, res;
170
- DBusPendingCall *call;
171
- DBusError err;
172
+ int ncodecs = 0;
173
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
174
175
spa_log_debug(backend->log, "Registering");
176
177
178
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pcodecs, ncodecs,
179
DBUS_TYPE_INVALID);
180
181
- dbus_error_init(&err);
182
-
183
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
184
- dbus_message_unref(m);
185
-
186
if (r == NULL) {
187
if (dbus_error_has_name(&err, "org.freedesktop.DBus.Error.ServiceUnknown")) {
188
spa_log_info(backend->log, "oFono not available: %s",
189
err.message);
190
- res = -ENOTSUP;
191
+ return -ENOTSUP;
192
} else {
193
spa_log_warn(backend->log, "Registering Profile %s failed: %s (%s)",
194
path, err.message, err.name);
195
- res = -EIO;
196
+ return -EIO;
197
}
198
- dbus_error_free(&err);
199
- return res;
200
}
201
202
if (dbus_message_is_error(r, OFONO_ERROR_INVALID_ARGUMENTS)) {
203
spa_log_warn(backend->log, "invalid arguments");
204
- goto finish;
205
+ return -EIO;
206
}
207
if (dbus_message_is_error(r, OFONO_ERROR_IN_USE)) {
208
spa_log_warn(backend->log, "already in use");
209
- goto finish;
210
+ return -EIO;
211
}
212
if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
213
spa_log_warn(backend->log, "Error registering profile");
214
- goto finish;
215
+ return -EIO;
216
}
217
if (dbus_message_is_error(r, DBUS_ERROR_SERVICE_UNKNOWN)) {
218
spa_log_info(backend->log, "oFono not available, disabling");
219
- goto finish;
220
+ return -EIO;
221
}
222
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
223
spa_log_error(backend->log, "Register() failed: %s",
224
dbus_message_get_error_name(r));
225
- goto finish;
226
+ return -EIO;
227
}
228
- dbus_message_unref(r);
229
230
spa_log_debug(backend->log, "registered");
231
232
+ return 0;
233
+}
234
+
235
+static int ofono_getcards(struct impl *backend)
236
+{
237
+ spa_autoptr(DBusMessage) m = NULL;
238
+
239
m = dbus_message_new_method_call(OFONO_SERVICE, "/",
240
OFONO_HF_AUDIO_MANAGER_INTERFACE, "GetCards");
241
if (m == NULL)
242
- goto finish;
243
+ return -ENOMEM;
244
245
- dbus_connection_send_with_reply(backend->conn, m, &call, -1);
246
- dbus_pending_call_set_notify(call, ofono_getcards_reply, backend, NULL);
247
- dbus_message_unref(m);
248
+ if (!send_with_reply(backend->conn, m, ofono_getcards_reply, backend))
249
+ return -EIO;
250
251
return 0;
252
+}
253
254
-finish:
255
- dbus_message_unref(r);
256
- return -EIO;
257
+static int backend_ofono_register(void *data)
258
+{
259
+ int ret = ofono_register(data);
260
+ if (ret < 0)
261
+ return ret;
262
+
263
+ ret = ofono_getcards(data);
264
+ if (ret < 0)
265
+ return ret;
266
+
267
+ return 0;
268
}
269
270
static DBusHandlerResult ofono_filter_cb(DBusConnection *bus, DBusMessage *m, void *user_data)
271
{
272
struct impl *backend = user_data;
273
- DBusError err;
274
-
275
- dbus_error_init(&err);
276
277
if (dbus_message_is_signal(m, OFONO_HF_AUDIO_MANAGER_INTERFACE, "CardAdded")) {
278
char *p;
279
280
return ofono_audio_card_found(backend, p, &props_i);
281
} else if (dbus_message_is_signal(m, OFONO_HF_AUDIO_MANAGER_INTERFACE, "CardRemoved")) {
282
const char *p;
283
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
284
285
if (!dbus_message_get_args(m, &err, DBUS_TYPE_OBJECT_PATH, &p, DBUS_TYPE_INVALID)) {
286
spa_log_error(backend->log, "Failed to parse org.ofono.HandsfreeAudioManager.CardRemoved: %s", err.message);
287
288
289
static int add_filters(struct impl *backend)
290
{
291
- DBusError err;
292
-
293
if (backend->filters_added)
294
return 0;
295
296
- dbus_error_init(&err);
297
-
298
if (!dbus_connection_add_filter(backend->conn, ofono_filter_cb, backend, NULL)) {
299
spa_log_error(backend->log, "failed to add filter function");
300
- goto fail;
301
+ return -EIO;
302
}
303
304
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
305
+
306
dbus_bus_add_match(backend->conn,
307
"type='signal',sender='" OFONO_SERVICE "',"
308
"interface='" OFONO_HF_AUDIO_MANAGER_INTERFACE "',member='CardAdded'", &err);
309
310
backend->filters_added = true;
311
312
return 0;
313
-
314
-fail:
315
- dbus_error_free(&err);
316
- return -EIO;
317
}
318
319
static int backend_ofono_free(void *data)
320
321
322
static bool is_available(struct impl *backend)
323
{
324
- DBusMessage *m, *r;
325
- DBusError err;
326
- bool success = false;
327
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
328
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
329
330
m = dbus_message_new_method_call(OFONO_SERVICE, "/",
331
DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
332
if (m == NULL)
333
return false;
334
335
- dbus_error_init(&err);
336
r = dbus_connection_send_with_reply_and_block(backend->conn, m, -1, &err);
337
- dbus_message_unref(m);
338
-
339
if (r && dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
340
- success = true;
341
-
342
- if (r)
343
- dbus_message_unref(r);
344
- else
345
- dbus_error_free(&err);
346
+ return true;
347
348
- return success;
349
+ return false;
350
}
351
352
struct spa_bt_backend *backend_ofono_new(struct spa_bt_monitor *monitor,
353
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
1085
1
2
}
3
4
// Unregister virtual battery of device
5
-static void battery_remove(struct spa_bt_device *device) {
6
+static void battery_remove(struct spa_bt_device *device)
7
+{
8
DBusMessageIter i, entry;
9
- DBusMessage *m;
10
+ spa_autoptr(DBusMessage) m = NULL;
11
const char *interface;
12
13
cancel_and_unref(&device->battery_pending_call);
14
15
spa_log_error(device->monitor->log, "sending " DBUS_SIGNAL_INTERFACES_REMOVED " failed");
16
}
17
18
- dbus_message_unref(m);
19
-
20
device->has_battery = false;
21
}
22
23
24
{
25
spa_log_debug(device->monitor->log, "updating battery: %s", device->battery_path);
26
27
- DBusMessage *msg;
28
+ spa_autoptr(DBusMessage) msg = NULL;
29
DBusMessageIter iter;
30
31
msg = dbus_message_new_signal(device->battery_path,
32
33
34
if (!dbus_connection_send(device->monitor->conn, msg, NULL))
35
spa_log_error(device->monitor->log, "Error updating battery");
36
-
37
- dbus_message_unref(msg);
38
}
39
40
// Create new virtual battery with value stored in current device object
41
-static void battery_create(struct spa_bt_device *device) {
42
- DBusMessage *msg;
43
+static void battery_create(struct spa_bt_device *device)
44
+{
45
+ spa_autoptr(DBusMessage) msg = NULL;
46
DBusMessageIter iter, entry, dict;
47
msg = dbus_message_new_signal(PIPEWIRE_BATTERY_PROVIDER,
48
DBUS_INTERFACE_OBJECT_MANAGER,
49
50
return;
51
}
52
53
- dbus_message_unref(msg);
54
-
55
spa_log_debug(device->monitor->log, "Created virtual battery for %s", device->address);
56
device->has_battery = true;
57
}
58
59
static void on_battery_provider_registered(DBusPendingCall *pending_call,
60
void *data)
61
{
62
- DBusMessage *reply;
63
struct spa_bt_device *device = data;
64
65
spa_assert(device->battery_pending_call == pending_call);
66
- reply = steal_reply_and_unref(&device->battery_pending_call);
67
+ spa_autoptr(DBusMessage) reply = steal_reply_and_unref(&device->battery_pending_call);
68
69
if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
70
spa_log_error(device->monitor->log, "Failed to register battery provider. Error: %s", dbus_message_get_error_name(reply));
71
spa_log_error(device->monitor->log, "BlueZ Battery Provider is not available, won't retry to register it. Make sure you are running BlueZ 5.56+ with experimental features to use Battery Provider.");
72
device->adapter->battery_provider_unavailable = true;
73
- dbus_message_unref(reply);
74
return;
75
}
76
77
78
79
if (!device->has_battery)
80
battery_create(device);
81
-
82
- dbus_message_unref(reply);
83
}
84
85
// Register Battery Provider for adapter and then create virtual battery for device
86
static void register_battery_provider(struct spa_bt_device *device)
87
{
88
- DBusMessage *method_call;
89
+ spa_autoptr(DBusMessage) method_call = NULL;
90
DBusMessageIter message_iter;
91
92
if (device->battery_pending_call) {
93
94
dbus_message_iter_append_basic(&message_iter, DBUS_TYPE_OBJECT_PATH,
95
&object_path);
96
97
- if (!dbus_connection_send_with_reply(device->monitor->conn, method_call, &device->battery_pending_call,
98
- DBUS_TIMEOUT_USE_DEFAULT)) {
99
- dbus_message_unref(method_call);
100
- spa_log_error(device->monitor->log, "Failed to register battery provider");
101
- return;
102
- }
103
-
104
- dbus_message_unref(method_call);
105
-
106
+ device->battery_pending_call = send_with_reply(device->monitor->conn, method_call,
107
+ on_battery_provider_registered, device);
108
if (!device->battery_pending_call) {
109
spa_log_error(device->monitor->log, "Failed to register battery provider");
110
return;
111
}
112
-
113
- if (!dbus_pending_call_set_notify(
114
- device->battery_pending_call, on_battery_provider_registered,
115
- device, NULL)) {
116
- spa_log_error(device->monitor->log, "Failed to register battery provider");
117
- cancel_and_unref(&device->battery_pending_call);
118
- }
119
}
120
121
static int media_codec_to_endpoint(const struct media_codec *codec,
122
123
const char *path;
124
uint8_t *cap, configA2DP_MAX_CAPS_SIZE;
125
uint8_t *pconf = (uint8_t *) config;
126
- DBusMessage *r;
127
- DBusError err;
128
+ spa_autoptr(DBusMessage) r = NULL;
129
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
130
int size, res;
131
const struct media_codec *codec;
132
bool sink;
133
134
- dbus_error_init(&err);
135
-
136
path = dbus_message_get_path(m);
137
138
if (!dbus_message_get_args(m, &err, DBUS_TYPE_ARRAY,
139
DBUS_TYPE_BYTE, &cap, &size, DBUS_TYPE_INVALID)) {
140
spa_log_error(monitor->log, "Endpoint SelectConfiguration(): %s", err.message);
141
- dbus_error_free(&err);
142
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
143
}
144
spa_log_info(monitor->log, "%p: %s select conf %d", monitor, path, size);
145
146
if (!dbus_connection_send(conn, r, NULL))
147
return DBUS_HANDLER_RESULT_NEED_MEMORY;
148
149
- dbus_message_unref(r);
150
-
151
return DBUS_HANDLER_RESULT_HANDLED;
152
}
153
154
155
struct spa_bt_monitor *monitor = userdata;
156
const char *path;
157
DBusMessageIter args, props, iter;
158
- DBusMessage *r = NULL;
159
+ spa_autoptr(DBusMessage) r = NULL;
160
int res;
161
const struct media_codec *codec;
162
bool sink;
163
164
165
dbus_message_iter_close_container(&iter, &dict);
166
167
- if (r) {
168
- if (!dbus_connection_send(conn, r, NULL))
169
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
170
-
171
- dbus_message_unref(r);
172
- }
173
+ if (!dbus_connection_send(conn, r, NULL))
174
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
175
176
return DBUS_HANDLER_RESULT_HANDLED;
177
178
179
goto error;
180
181
error:
182
- if (r)
183
- dbus_message_unref(r);
184
- if ((r = dbus_message_new_error(m, "org.bluez.Error.InvalidArguments", err_msg)) == NULL)
185
+ if (!reply_with_error(conn, m, "org.bluez.Error.InvalidArguments", err_msg))
186
return DBUS_HANDLER_RESULT_NEED_MEMORY;
187
- if (!dbus_connection_send(conn, r, NULL)) {
188
- dbus_message_unref(r);
189
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
190
- }
191
- dbus_message_unref(r);
192
return DBUS_HANDLER_RESULT_HANDLED;
193
}
194
195
196
static int adapter_init_modalias(struct spa_bt_monitor *monitor, struct spa_bt_adapter *d)
197
{
198
char path1024;
199
- FILE *f = NULL;
200
int vendor_id, product_id;
201
const char *str;
202
- int res = -EINVAL;
203
204
/* Lookup vendor/product id for the device, if present */
205
str = strrchr(d->path, '/'); /* hciXX */
206
if (str == NULL)
207
- goto fail;
208
+ return -EINVAL;
209
+
210
snprintf(path, sizeof(path), "/sys/class/bluetooth/%s/device/modalias", str);
211
- if ((f = fopen(path, "rbe")) == NULL) {
212
- res = -errno;
213
- goto fail;
214
- }
215
+
216
+ spa_autoptr(FILE) f = fopen(path, "rbe");
217
+ if (f == NULL)
218
+ return -errno;
219
+
220
if (fscanf(f, "usb:v%04Xp%04X", &vendor_id, &product_id) != 2)
221
- goto fail;
222
+ return -EINVAL;
223
+
224
d->source_id = SOURCE_ID_USB;
225
d->vendor_id = vendor_id;
226
d->product_id = product_id;
227
- fclose(f);
228
229
spa_log_debug(monitor->log, "adapter %p: usb vendor:%04x product:%04x",
230
d, vendor_id, product_id);
231
return 0;
232
-
233
-fail:
234
- if (f)
235
- fclose(f);
236
- return res;
237
}
238
239
static struct spa_bt_adapter *adapter_create(struct spa_bt_monitor *monitor, const char *path)
240
241
const char *profile_uuid)
242
{
243
struct spa_bt_monitor *monitor = device->monitor;
244
- DBusMessage *m;
245
+ spa_autoptr(DBusMessage) m = NULL;
246
247
spa_log_info(monitor->log, "device %p %s: profile %s not connected; try ConnectProfile()",
248
device, device->path, profile_uuid);
249
250
if (m == NULL)
251
return -ENOMEM;
252
dbus_message_append_args(m, DBUS_TYPE_STRING, &profile_uuid, DBUS_TYPE_INVALID);
253
- if (!dbus_connection_send(monitor->conn, m, NULL)) {
254
- dbus_message_unref(m);
255
+ if (!dbus_connection_send(monitor->conn, m, NULL))
256
return -EIO;
257
- }
258
- dbus_message_unref(m);
259
260
return 0;
261
}
262
263
{
264
struct spa_bt_monitor *monitor = device->monitor;
265
const struct media_codec * const * const media_codecs = monitor->media_codecs;
266
- const struct media_codec **supported_codecs;
267
+ spa_autofree const struct media_codec **supported_codecs = NULL;
268
size_t i, j, size;
269
270
*count = 0;
271
-
272
size = 8;
273
supported_codecs = malloc(size * sizeof(const struct media_codec *));
274
if (supported_codecs == NULL)
275
276
#else
277
p = realloc(supported_codecs, size * sizeof(const struct media_codec *));
278
#endif
279
- if (p == NULL) {
280
- free(supported_codecs);
281
+ if (p == NULL)
282
return NULL;
283
- }
284
+
285
supported_codecs = p;
286
}
287
}
288
289
supported_codecsj = NULL;
290
*count = j;
291
292
- return supported_codecs;
293
+ return spa_steal_ptr(supported_codecs);
294
}
295
296
static struct spa_bt_remote_endpoint *device_remote_endpoint_find(struct spa_bt_device *device, const char *path)
297
298
{
299
struct spa_bt_transport *transport = user_data;
300
struct spa_bt_monitor *monitor = transport->monitor;
301
- DBusError err = DBUS_ERROR_INIT;
302
- DBusMessage *r;
303
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
304
305
spa_assert(transport->volume_call == pending);
306
- r = steal_reply_and_unref(&transport->volume_call);
307
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&transport->volume_call);
308
309
if (dbus_set_error_from_message(&err, r)) {
310
spa_log_info(monitor->log, "transport %p: set volume failed for transport %s: %s",
311
transport, transport->path, err.message);
312
- dbus_error_free(&err);
313
} else {
314
spa_log_debug(monitor->log, "transport %p: set volume complete",
315
transport);
316
}
317
-
318
- dbus_message_unref(r);
319
}
320
321
static void transport_set_property_volume(struct spa_bt_transport *transport, uint16_t value)
322
{
323
struct spa_bt_monitor *monitor = transport->monitor;
324
- DBusMessage *m;
325
+ spa_autoptr(DBusMessage) m = NULL;
326
DBusMessageIter it2;
327
const char *interface = BLUEZ_MEDIA_TRANSPORT_INTERFACE;
328
const char *name = "Volume";
329
int res = 0;
330
- dbus_bool_t ret;
331
332
cancel_and_unref(&transport->volume_call);
333
334
335
dbus_message_iter_append_basic(&it1, DBUS_TYPE_UINT16, &value);
336
dbus_message_iter_close_container(&it0, &it1);
337
338
- ret = dbus_connection_send_with_reply(monitor->conn, m, &transport->volume_call, -1);
339
- dbus_message_unref(m);
340
-
341
- if (!ret || !transport->volume_call) {
342
- res = -EIO;
343
- goto fail;
344
- }
345
-
346
- ret = dbus_pending_call_set_notify(transport->volume_call,
347
- transport_set_property_volume_reply, transport, NULL);
348
- if (!ret) {
349
+ transport->volume_call = send_with_reply(monitor->conn, m, transport_set_property_volume_reply, transport);
350
+ if (!transport->volume_call) {
351
res = -EIO;
352
goto fail;
353
}
354
355
struct spa_bt_monitor *monitor = transport->monitor;
356
struct spa_bt_device *device = transport->device;
357
int ret = 0;
358
- DBusError err;
359
- DBusMessage *r;
360
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
361
struct spa_bt_transport *t, *t_linked;
362
363
spa_assert(transport->acquire_call == pending);
364
- r = steal_reply_and_unref(&transport->acquire_call);
365
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&transport->acquire_call);
366
367
spa_bt_device_update_last_bluez_action_time(device);
368
369
370
goto finish;
371
}
372
373
- dbus_error_init(&err);
374
-
375
if (transport->fd >= 0) {
376
spa_log_error(monitor->log, "transport %p: invalid duplicate acquire", transport);
377
ret = -EINVAL;
378
379
DBUS_TYPE_INVALID)) {
380
spa_log_error(monitor->log, "Failed to parse Acquire %s reply: %s",
381
transport->path, err.message);
382
- dbus_error_free(&err);
383
ret = -EIO;
384
goto finish;
385
}
386
387
transport_sync_volume(transport);
388
389
finish:
390
- if (r)
391
- dbus_message_unref(r);
392
if (ret < 0)
393
spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ERROR);
394
else {
395
396
static int do_transport_acquire(struct spa_bt_transport *transport)
397
{
398
struct spa_bt_monitor *monitor = transport->monitor;
399
- DBusMessage *m;
400
- dbus_bool_t ret;
401
+ spa_autoptr(DBusMessage) m = NULL;
402
struct spa_bt_transport *t_linked;
403
404
spa_list_for_each(t_linked, &transport->bap_transport_linked, bap_transport_linked) {
405
406
if (m == NULL)
407
return -ENOMEM;
408
409
- ret = dbus_connection_send_with_reply(monitor->conn, m, &transport->acquire_call, -1);
410
- dbus_message_unref(m);
411
-
412
- if (!ret || transport->acquire_call == NULL)
413
- return -EIO;
414
-
415
- ret = dbus_pending_call_set_notify(transport->acquire_call, transport_acquire_reply, transport, NULL);
416
- if (!ret)
417
+ transport->acquire_call = send_with_reply(monitor->conn, m, transport_acquire_reply, transport);
418
+ if (!transport->acquire_call)
419
return -EIO;
420
421
return 0;
422
423
static int do_transport_release(struct spa_bt_transport *transport)
424
{
425
struct spa_bt_monitor *monitor = transport->monitor;
426
- DBusMessage *m;
427
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
428
struct spa_bt_transport *t_linked;
429
bool is_idle = (transport->state == SPA_BT_TRANSPORT_STATE_IDLE);
430
- DBusMessage *r;
431
- DBusError err;
432
bool linked = false;
433
434
spa_log_debug(monitor->log, "transport %p: Release %s",
435
436
if (m == NULL)
437
return -ENOMEM;
438
439
- dbus_error_init(&err);
440
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
441
r = dbus_connection_send_with_reply_and_block(monitor->conn, m, -1, &err);
442
- dbus_message_unref(m);
443
-
444
if (r == NULL) {
445
if (is_idle) {
446
/* XXX: The fd always needs to be closed. However, Release()
447
448
spa_log_error(monitor->log, "Failed to release transport %s: %s",
449
transport->path, err.message);
450
}
451
- dbus_error_free(&err);
452
} else {
453
spa_log_info(monitor->log, "Transport %s released", transport->path);
454
- dbus_message_unref(r);
455
}
456
457
return 0;
458
459
const struct media_codec *codec;
460
uint8_t configA2DP_MAX_CAPS_SIZE;
461
enum spa_bt_media_direction direction;
462
- char *local_endpoint = NULL;
463
+ spa_autofree char *local_endpoint = NULL;
464
int res, config_size;
465
- dbus_bool_t dbus_ret;
466
- DBusMessage *m;
467
+ spa_autoptr(DBusMessage) m = NULL;
468
DBusMessageIter iter, d;
469
int i;
470
bool sink;
471
472
if (ep == NULL || ep->capabilities == NULL || ep->uuid == NULL) {
473
spa_log_debug(sw->device->monitor->log, "media codec switch %p: endpoint %s not valid, try next",
474
sw, *sw->path_iter);
475
- goto next;
476
+ return false;
477
}
478
479
/* Setup and check compatible configuration */
480
if (ep->codec != codec->codec_id) {
481
spa_log_debug(sw->device->monitor->log, "media codec switch %p: different codec, try next", sw);
482
- goto next;
483
+ return false;
484
}
485
486
if (!(sw->profile & spa_bt_profile_from_uuid(ep->uuid))) {
487
spa_log_debug(sw->device->monitor->log, "media codec switch %p: wrong uuid (%s) for profile, try next",
488
sw, ep->uuid);
489
- goto next;
490
+ return false;
491
}
492
493
if ((sw->profile & SPA_BT_PROFILE_A2DP_SINK) || (sw->profile & SPA_BT_PROFILE_BAP_SINK) ) {
494
495
} else {
496
spa_log_debug(sw->device->monitor->log, "media codec switch %p: bad profile (%d), try next",
497
sw, sw->profile);
498
- goto next;
499
+ return false;
500
}
501
502
if (media_codec_to_endpoint(codec, direction, &local_endpoint) < 0) {
503
spa_log_debug(sw->device->monitor->log, "media codec switch %p: no endpoint for codec %s, try next",
504
sw, codec->name);
505
- goto next;
506
+ return false;
507
}
508
509
/* Each endpoint can be used by only one device at a time (on each adapter) */
510
511
if (spa_streq(t->endpoint_path, local_endpoint)) {
512
spa_log_debug(sw->device->monitor->log, "media codec switch %p: endpoint %s in use, try next",
513
sw, local_endpoint);
514
- goto next;
515
+ return false;
516
}
517
}
518
519
520
if (res < 0) {
521
spa_log_debug(sw->device->monitor->log, "media codec switch %p: incompatible capabilities (%d), try next",
522
sw, res);
523
- goto next;
524
+ return false;
525
}
526
config_size = res;
527
528
529
m = dbus_message_new_method_call(BLUEZ_SERVICE, ep->path, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SetConfiguration");
530
if (m == NULL) {
531
spa_log_debug(sw->device->monitor->log, "media codec switch %p: dbus allocation failure, try next", sw);
532
- goto next;
533
+ return false;
534
}
535
536
spa_bt_device_update_last_bluez_action_time(sw->device);
537
538
dbus_message_iter_close_container(&iter, &d);
539
540
spa_assert(sw->pending == NULL);
541
- dbus_ret = dbus_connection_send_with_reply(sw->device->monitor->conn, m, &sw->pending, -1);
542
-
543
- if (!dbus_ret || sw->pending == NULL) {
544
+ sw->pending = send_with_reply(sw->device->monitor->conn, m, media_codec_switch_reply, sw);
545
+ if (!sw->pending) {
546
spa_log_error(sw->device->monitor->log, "media codec switch %p: dbus call failure, try next", sw);
547
- dbus_message_unref(m);
548
- goto next;
549
- }
550
-
551
- dbus_ret = dbus_pending_call_set_notify(sw->pending, media_codec_switch_reply, sw, NULL);
552
- dbus_message_unref(m);
553
-
554
- if (!dbus_ret) {
555
- spa_log_error(sw->device->monitor->log, "media codec switch %p: dbus set notify failure", sw);
556
- goto next;
557
+ return false;
558
}
559
560
- free(local_endpoint);
561
return true;
562
-
563
-next:
564
- free(local_endpoint);
565
- return false;
566
}
567
568
static void media_codec_switch_process(struct spa_bt_media_codec_switch *sw)
569
570
{
571
struct spa_bt_media_codec_switch *sw = user_data;
572
struct spa_bt_device *device = sw->device;
573
- DBusMessage *r;
574
575
spa_assert(sw->pending == pending);
576
- r = steal_reply_and_unref(&sw->pending);
577
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&sw->pending);
578
579
spa_bt_device_update_last_bluez_action_time(device);
580
581
- if (!media_codec_switch_goto_active(sw)) {
582
- if (r != NULL)
583
- dbus_message_unref(r);
584
+ if (!media_codec_switch_goto_active(sw))
585
return;
586
- }
587
588
if (r == NULL) {
589
spa_log_error(sw->device->monitor->log,
590
591
spa_log_debug(sw->device->monitor->log,
592
"media codec switch %p: failed (%s), trying next",
593
sw, dbus_message_get_error_name(r));
594
- dbus_message_unref(r);
595
goto next;
596
}
597
598
- dbus_message_unref(r);
599
-
600
/* Success */
601
spa_log_info(sw->device->monitor->log, "media codec switch %p: success", sw);
602
spa_bt_device_emit_codec_switched(sw->device, 0);
603
604
struct spa_bt_monitor *monitor = userdata;
605
const char *transport_path, *endpoint;
606
DBusMessageIter it2;
607
- DBusMessage *r;
608
+ spa_autoptr(DBusMessage) r = NULL;
609
struct spa_bt_transport *transport;
610
const struct media_codec *codec;
611
int profile;
612
613
if (!dbus_connection_send(conn, r, NULL))
614
return DBUS_HANDLER_RESULT_NEED_MEMORY;
615
616
- dbus_message_unref(r);
617
-
618
return DBUS_HANDLER_RESULT_HANDLED;
619
}
620
621
static DBusHandlerResult endpoint_clear_configuration(DBusConnection *conn, DBusMessage *m, void *userdata)
622
{
623
struct spa_bt_monitor *monitor = userdata;
624
- DBusError err;
625
- DBusMessage *r;
626
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
627
+ spa_autoptr(DBusMessage) r = NULL;
628
const char *transport_path;
629
struct spa_bt_transport *transport;
630
631
- dbus_error_init(&err);
632
-
633
if (!dbus_message_get_args(m, &err,
634
DBUS_TYPE_OBJECT_PATH, &transport_path,
635
DBUS_TYPE_INVALID)) {
636
spa_log_warn(monitor->log, "Bad ClearConfiguration method call: %s",
637
err.message);
638
- dbus_error_free(&err);
639
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
640
}
641
642
643
if (!dbus_connection_send(conn, r, NULL))
644
return DBUS_HANDLER_RESULT_NEED_MEMORY;
645
646
- dbus_message_unref(r);
647
-
648
return DBUS_HANDLER_RESULT_HANDLED;
649
}
650
651
static DBusHandlerResult endpoint_release(DBusConnection *conn, DBusMessage *m, void *userdata)
652
{
653
- DBusMessage *r;
654
-
655
- r = dbus_message_new_error(m,
656
- BLUEZ_MEDIA_ENDPOINT_INTERFACE ".Error.NotImplemented",
657
- "Method not implemented");
658
- if (r == NULL)
659
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
660
- if (!dbus_connection_send(conn, r, NULL))
661
+ if (!reply_with_error(conn, m, BLUEZ_MEDIA_ENDPOINT_INTERFACE ".Error.NotImplemented", "Method not implemented"))
662
return DBUS_HANDLER_RESULT_NEED_MEMORY;
663
664
- dbus_message_unref(r);
665
-
666
return DBUS_HANDLER_RESULT_HANDLED;
667
}
668
669
670
{
671
struct spa_bt_monitor *monitor = userdata;
672
const char *path, *interface, *member;
673
- DBusMessage *r;
674
DBusHandlerResult res;
675
676
path = dbus_message_get_path(m);
677
678
679
if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
680
const char *xml = ENDPOINT_INTROSPECT_XML;
681
+ spa_autoptr(DBusMessage) r = NULL;
682
683
if ((r = dbus_message_new_method_return(m)) == NULL)
684
return DBUS_HANDLER_RESULT_NEED_MEMORY;
685
686
if (!dbus_connection_send(monitor->conn, r, NULL))
687
return DBUS_HANDLER_RESULT_NEED_MEMORY;
688
689
- dbus_message_unref(r);
690
res = DBUS_HANDLER_RESULT_HANDLED;
691
}
692
else if (dbus_message_is_method_call(m, BLUEZ_MEDIA_ENDPOINT_INTERFACE, "SetConfiguration"))
693
694
{
695
struct spa_bt_adapter *adapter = user_data;
696
struct spa_bt_monitor *monitor = adapter->monitor;
697
- DBusMessage *r;
698
699
- r = steal_reply_and_unref(&pending);
700
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
701
if (r == NULL)
702
return;
703
704
if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
705
spa_log_warn(monitor->log, "BlueZ D-Bus ObjectManager not available");
706
- goto finish;
707
+ return;
708
}
709
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
710
spa_log_error(monitor->log, "RegisterEndpoint() failed: %s",
711
dbus_message_get_error_name(r));
712
- goto finish;
713
+ return;
714
}
715
716
adapter->legacy_endpoints_registered = true;
717
-
718
-finish:
719
- dbus_message_unref(r);
720
}
721
722
static void append_basic_variant_dict_entry(DBusMessageIter *dict, const char* key, int variant_type_int, const char* variant_type_str, void* variant) {
723
724
{
725
struct spa_bt_monitor *monitor = adapter->monitor;
726
const char *path = adapter->path;
727
- char *object_path = NULL;
728
- DBusMessage *m;
729
+ spa_autofree char *object_path = NULL;
730
+ spa_autoptr(DBusMessage) m = NULL;
731
DBusMessageIter object_it, dict_it;
732
- DBusPendingCall *call;
733
uint8_t capsA2DP_MAX_CAPS_SIZE;
734
int ret, caps_size;
735
uint16_t codec_id = codec->codec_id;
736
737
738
ret = media_codec_to_endpoint(codec, direction, &object_path);
739
if (ret < 0)
740
- goto error;
741
+ return ret;
742
743
ret = caps_size = codec->fill_caps(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, caps);
744
if (ret < 0)
745
- goto error;
746
+ return ret;
747
748
m = dbus_message_new_method_call(BLUEZ_SERVICE,
749
path,
750
BLUEZ_MEDIA_INTERFACE,
751
"RegisterEndpoint");
752
- if (m == NULL) {
753
- ret = -EIO;
754
- goto error;
755
- }
756
+ if (m == NULL)
757
+ return -EIO;
758
759
dbus_message_iter_init_append(m, &object_it);
760
dbus_message_iter_append_basic(&object_it, DBUS_TYPE_OBJECT_PATH, &object_path);
761
762
763
dbus_message_iter_close_container(&object_it, &dict_it);
764
765
- dbus_connection_send_with_reply(monitor->conn, m, &call, -1);
766
- dbus_pending_call_set_notify(call, bluez_register_endpoint_legacy_reply, adapter, NULL);
767
- dbus_message_unref(m);
768
-
769
- free(object_path);
770
+ if (!send_with_reply(monitor->conn, m, bluez_register_endpoint_legacy_reply, adapter))
771
+ return -EIO;
772
773
return 0;
774
-
775
-error:
776
- free(object_path);
777
- return ret;
778
}
779
780
static int adapter_register_endpoints_legacy(struct spa_bt_adapter *a)
781
782
struct spa_bt_monitor *monitor = user_data;
783
const struct media_codec * const * const media_codecs = monitor->media_codecs;
784
const char *path, *interface, *member;
785
- char *endpoint;
786
- DBusMessage *r;
787
DBusMessageIter iter, array;
788
DBusHandlerResult res;
789
int i;
790
791
792
if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
793
const char *xml = OBJECT_MANAGER_INTROSPECT_XML;
794
+ spa_autoptr(DBusMessage) r = NULL;
795
796
if ((r = dbus_message_new_method_return(m)) == NULL)
797
return DBUS_HANDLER_RESULT_NEED_MEMORY;
798
799
if (!dbus_connection_send(monitor->conn, r, NULL))
800
return DBUS_HANDLER_RESULT_NEED_MEMORY;
801
802
- dbus_message_unref(r);
803
res = DBUS_HANDLER_RESULT_HANDLED;
804
}
805
else if (dbus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
806
+ spa_autoptr(DBusMessage) r = NULL;
807
+
808
if ((r = dbus_message_new_method_return(m)) == NULL)
809
return DBUS_HANDLER_RESULT_NEED_MEMORY;
810
811
812
if (caps_size < 0)
813
continue;
814
815
+ spa_autofree char *endpoint = NULL;
816
ret = media_codec_to_endpoint(codec, SPA_BT_MEDIA_SINK, &endpoint);
817
if (ret == 0) {
818
spa_log_info(monitor->log, "register media sink codec %s: %s", media_codecsi->name, endpoint);
819
append_media_object(&array, endpoint,
820
codec->bap ? SPA_BT_UUID_BAP_SINK : SPA_BT_UUID_A2DP_SINK,
821
codec_id, caps, caps_size);
822
- free(endpoint);
823
}
824
}
825
826
827
if (caps_size < 0)
828
continue;
829
830
+ spa_autofree char *endpoint = NULL;
831
ret = media_codec_to_endpoint(codec, SPA_BT_MEDIA_SOURCE, &endpoint);
832
if (ret == 0) {
833
spa_log_info(monitor->log, "register media source codec %s: %s", media_codecsi->name, endpoint);
834
append_media_object(&array, endpoint,
835
codec->bap ? SPA_BT_UUID_BAP_SOURCE : SPA_BT_UUID_A2DP_SOURCE,
836
codec_id, caps, caps_size);
837
- free(endpoint);
838
}
839
}
840
}
841
842
{
843
struct spa_bt_adapter *adapter = user_data;
844
struct spa_bt_monitor *monitor = adapter->monitor;
845
- DBusMessage *r;
846
bool fallback = true;
847
848
- r = steal_reply_and_unref(&pending);
849
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
850
if (r == NULL)
851
return;
852
853
854
adapter->a2dp_application_registered = true;
855
856
finish:
857
- dbus_message_unref(r);
858
-
859
if (fallback)
860
adapter_register_endpoints_legacy(adapter);
861
}
862
863
{
864
struct spa_bt_adapter *adapter = user_data;
865
struct spa_bt_monitor *monitor = adapter->monitor;
866
- DBusMessage *r;
867
868
- r = steal_reply_and_unref(&pending);
869
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&pending);
870
if (r == NULL)
871
return;
872
873
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
874
spa_log_error(monitor->log, "RegisterApplication() failed: %s",
875
dbus_message_get_error_name(r));
876
- goto finish;
877
+ return;
878
}
879
880
adapter->bap_application_registered = true;
881
-
882
-finish:
883
- dbus_message_unref(r);
884
}
885
886
static int register_media_endpoint(struct spa_bt_monitor *monitor,
887
888
if (!endpoint_should_be_registered(monitor, codec, direction))
889
return 0;
890
891
- char *object_path = NULL;
892
+ spa_autofree char *object_path = NULL;
893
int ret = media_codec_to_endpoint(codec, direction, &object_path);
894
if (ret < 0)
895
return ret;
896
897
if (!dbus_connection_register_object_path(monitor->conn,
898
object_path,
899
&vtable_endpoint, monitor))
900
- {
901
- ret = -EIO;
902
- }
903
+ return -EIO;
904
905
- free(object_path);
906
- return ret;
907
+ return 0;
908
}
909
910
static int register_media_application(struct spa_bt_monitor * monitor)
911
912
if (!endpoint_should_be_registered(monitor, codec, direction))
913
return;
914
915
- char *object_path = NULL;
916
+ spa_autofree char *object_path = NULL;
917
int ret = media_codec_to_endpoint(codec, direction, &object_path);
918
if (ret < 0)
919
return;
920
921
922
if (!dbus_connection_unregister_object_path(monitor->conn, object_path))
923
spa_log_warn(monitor->log, "failed to unregister %s\n", object_path);
924
-
925
- free(object_path);
926
}
927
928
static void unregister_media_application(struct spa_bt_monitor * monitor)
929
930
const char *object_manager_path = bap ? BAP_OBJECT_MANAGER_PATH : A2DP_OBJECT_MANAGER_PATH;
931
struct spa_bt_monitor *monitor = a->monitor;
932
const char *ep_type_name = (bap ? "LE Audio" : "A2DP");
933
- DBusMessage *m;
934
+ spa_autoptr(DBusMessage) m = NULL;
935
DBusMessageIter i, d;
936
- DBusPendingCall *call;
937
938
if (bap && a->bap_application_registered)
939
return 0;
940
941
dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, "{sv}", &d);
942
dbus_message_iter_close_container(&i, &d);
943
944
- dbus_connection_send_with_reply(monitor->conn, m, &call, -1);
945
- dbus_pending_call_set_notify(call,
946
- bap ? bluez_register_application_bap_reply : bluez_register_application_a2dp_reply,
947
- a, NULL);
948
- dbus_message_unref(m);
949
+ if (!send_with_reply(monitor->conn, m, bap ? bluez_register_application_bap_reply : bluez_register_application_a2dp_reply, a))
950
+ return -EIO;
951
952
return 0;
953
}
954
955
static void get_managed_objects_reply(DBusPendingCall *pending, void *user_data)
956
{
957
struct spa_bt_monitor *monitor = user_data;
958
- DBusMessage *r;
959
DBusMessageIter it6;
960
961
spa_assert(monitor->get_managed_objects_call == pending);
962
- r = steal_reply_and_unref(&monitor->get_managed_objects_call);
963
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&monitor->get_managed_objects_call);
964
if (r == NULL)
965
return;
966
967
if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
968
spa_log_warn(monitor->log, "BlueZ D-Bus ObjectManager not available");
969
- goto finish;
970
+ return;
971
}
972
973
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
974
spa_log_error(monitor->log, "GetManagedObjects() failed: %s",
975
dbus_message_get_error_name(r));
976
- goto finish;
977
+ return;
978
}
979
980
if (!dbus_message_iter_init(r, &it0) ||
981
!spa_streq(dbus_message_get_signature(r), "a{oa{sa{sv}}}")) {
982
spa_log_error(monitor->log, "Invalid reply signature for GetManagedObjects()");
983
- goto finish;
984
+ return;
985
}
986
987
dbus_message_iter_recurse(&it0, &it1);
988
989
reselect_backend(monitor, false);
990
991
monitor->objects_listed = true;
992
-
993
-finish:
994
- dbus_message_unref(r);
995
- return;
996
}
997
998
static void get_managed_objects(struct spa_bt_monitor *monitor)
999
1000
if (monitor->objects_listed || monitor->get_managed_objects_call)
1001
return;
1002
1003
- DBusMessage *m;
1004
- DBusPendingCall *call;
1005
+ spa_autoptr(DBusMessage) m = NULL;
1006
1007
m = dbus_message_new_method_call(BLUEZ_SERVICE,
1008
"/",
1009
1010
1011
dbus_message_set_auto_start(m, false);
1012
1013
- dbus_connection_send_with_reply(monitor->conn, m, &call, -1);
1014
- dbus_pending_call_set_notify(call, get_managed_objects_reply, monitor, NULL);
1015
- dbus_message_unref(m);
1016
-
1017
- monitor->get_managed_objects_call = call;
1018
+ monitor->get_managed_objects_call = send_with_reply(monitor->conn, m, get_managed_objects_reply, monitor);
1019
}
1020
1021
static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *user_data)
1022
{
1023
struct spa_bt_monitor *monitor = user_data;
1024
- DBusError err;
1025
-
1026
- dbus_error_init(&err);
1027
1028
if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
1029
const char *name, *old_owner, *new_owner;
1030
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
1031
1032
spa_log_debug(monitor->log, "Name owner changed %s", dbus_message_get_path(m));
1033
1034
1035
DBUS_TYPE_STRING, &new_owner,
1036
DBUS_TYPE_INVALID)) {
1037
spa_log_error(monitor->log, "Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message);
1038
- goto fail;
1039
+ goto finish;
1040
}
1041
1042
if (spa_streq(name, BLUEZ_SERVICE)) {
1043
1044
}
1045
}
1046
1047
-fail:
1048
- dbus_error_free(&err);
1049
finish:
1050
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1051
}
1052
1053
static void add_filters(struct spa_bt_monitor *this)
1054
{
1055
- DBusError err;
1056
-
1057
if (this->filters_added)
1058
return;
1059
1060
- dbus_error_init(&err);
1061
-
1062
if (!dbus_connection_add_filter(this->conn, filter_cb, this, NULL)) {
1063
spa_log_error(this->log, "failed to add filter function");
1064
- goto fail;
1065
+ return;
1066
}
1067
1068
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
1069
+
1070
dbus_bus_add_match(this->conn,
1071
"type='signal',sender='org.freedesktop.DBus',"
1072
"interface='org.freedesktop.DBus',member='NameOwnerChanged',"
1073
1074
"arg0='" BLUEZ_MEDIA_TRANSPORT_INTERFACE "'", &err);
1075
1076
this->filters_added = true;
1077
-
1078
- return;
1079
-
1080
-fail:
1081
- dbus_error_free(&err);
1082
}
1083
1084
static int
1085
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/dbus-helpers.h -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/dbus-helpers.h
Changed
53
1
2
#ifndef SPA_BLUEZ5_DBUS_HELPERS_H
3
#define SPA_BLUEZ5_DBUS_HELPERS_H
4
5
+#include <stdbool.h>
6
+
7
#include <dbus/dbus.h>
8
9
#include <spa/utils/cleanup.h>
10
11
return reply;
12
}
13
14
+SPA_DEFINE_AUTOPTR_CLEANUP(DBusMessage, DBusMessage, {
15
+ spa_clear_ptr(*thing, dbus_message_unref);
16
+})
17
+
18
+static inline bool reply_with_error(DBusConnection *conn,
19
+ DBusMessage *reply_to,
20
+ const char *error_name, const char *error_message)
21
+{
22
+ spa_autoptr(DBusMessage) reply = dbus_message_new_error(reply_to, error_name, error_message);
23
+
24
+ return reply && dbus_connection_send(conn, reply, NULL);
25
+}
26
+
27
+static inline DBusPendingCall *send_with_reply(DBusConnection *conn,
28
+ DBusMessage *m,
29
+ DBusPendingCallNotifyFunction callback, void *user_data)
30
+{
31
+ DBusPendingCall *pending_call;
32
+
33
+ if (!dbus_connection_send_with_reply(conn, m, &pending_call, DBUS_TIMEOUT_USE_DEFAULT))
34
+ return NULL;
35
+
36
+ if (!pending_call)
37
+ return NULL;
38
+
39
+ if (!dbus_pending_call_set_notify(pending_call, callback, user_data, NULL)) {
40
+ dbus_pending_call_cancel(pending_call);
41
+ dbus_pending_call_unref(pending_call);
42
+ return NULL;
43
+ }
44
+
45
+ return pending_call;
46
+}
47
+
48
+SPA_DEFINE_AUTO_CLEANUP(DBusError, DBusError, {
49
+ dbus_error_free(thing);
50
+})
51
+
52
#endif /* SPA_BLUEZ5_DBUS_HELPERS_H */
53
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/hci.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/hci.c
Changed
48
1
2
#include <bluetooth/hci.h>
3
#include <bluetooth/hci_lib.h>
4
5
+#include <spa/utils/cleanup.h>
6
+
7
int spa_bt_adapter_has_msbc(struct spa_bt_adapter *adapter)
8
{
9
- int hci_id, res;
10
- int sock = -1;
11
+ int hci_id;
12
+ spa_autoclose int sock = -1;
13
uint8_t features8, max_page = 0;
14
struct sockaddr_hci a;
15
const char *str;
16
17
18
sock = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
19
if (sock < 0)
20
- goto error;
21
+ return -errno;
22
23
memset(&a, 0, sizeof(a));
24
a.hci_family = AF_BLUETOOTH;
25
a.hci_dev = hci_id;
26
if (bind(sock, (struct sockaddr *) &a, sizeof(a)) < 0)
27
- goto error;
28
+ return -errno;
29
30
if (hci_read_local_ext_features(sock, 0, &max_page, features, 1000) < 0)
31
- goto error;
32
-
33
- close(sock);
34
+ return -errno;
35
36
adapter->msbc_probed = true;
37
adapter->has_msbc = ((features2 & LMP_TRSP_SCO) && (features3 & LMP_ESCO)) ? 1 : 0;
38
return adapter->has_msbc;
39
-
40
-error:
41
- res = -errno;
42
- if (sock >= 0)
43
- close(sock);
44
- return res;
45
}
46
47
#endif
48
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/media-codecs.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/media-codecs.c
Changed
30
1
2
*/
3
4
#include <spa/utils/string.h>
5
+#include <spa/utils/cleanup.h>
6
7
#include "media-codecs.h"
8
9
10
uint32_t cap, int preferred_value)
11
{
12
size_t i;
13
- int *scores, res;
14
+ spa_autofree int *scores = NULL;
15
+ int res;
16
unsigned int max_priority;
17
18
if (n == 0)
19
20
}
21
22
if (scoresres < 0)
23
- res = -EINVAL;
24
+ return -EINVAL;
25
26
- free(scores);
27
return res;
28
}
29
30
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/modemmanager.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/modemmanager.c
Changed
385
1
2
void *user_data;
3
};
4
5
-static bool mm_dbus_connection_send_with_reply(struct impl *this, DBusMessage *m, DBusPendingCall **pending_return,
6
- DBusPendingCallNotifyFunction function, void *user_data)
7
-{
8
- spa_assert(*pending_return == NULL);
9
-
10
- DBusPendingCall *pending_call;
11
- bool ret = dbus_connection_send_with_reply(this->conn, m, &pending_call, -1);
12
- if (!ret) {
13
- spa_log_debug(this->log, "dbus call failure");
14
- goto out;
15
- }
16
-
17
- spa_assert(pending_call);
18
-
19
- ret = dbus_pending_call_set_notify(pending_call, function, user_data, NULL);
20
- if (!ret) {
21
- spa_log_debug(this->log, "dbus set notify failure");
22
- cancel_and_unref(&pending_call);
23
- goto out;
24
- }
25
-
26
- *pending_return = pending_call;
27
-
28
-out:
29
- dbus_message_unref(m);
30
-
31
- return ret;
32
-}
33
-
34
static int mm_state_to_clcc(struct impl *this, MMCallState state)
35
{
36
switch (state) {
37
38
{
39
struct call *call = user_data;
40
struct impl *this = call->this;
41
- DBusMessage *r;
42
DBusMessageIter arg_i, element_i;
43
MMCallDirection direction;
44
MMCallState state;
45
46
spa_assert(call->pending == pending);
47
- r = steal_reply_and_unref(&call->pending);
48
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&call->pending);
49
if (r == NULL)
50
return;
51
52
if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) {
53
spa_log_warn(this->log, "ModemManager D-Bus Call not available");
54
- goto finish;
55
+ return;
56
}
57
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
58
spa_log_error(this->log, "GetAll() failed: %s", dbus_message_get_error_name(r));
59
- goto finish;
60
+ return;
61
}
62
63
if (!dbus_message_iter_init(r, &arg_i) || !spa_streq(dbus_message_get_signature(r), "a{sv}")) {
64
spa_log_error(this->log, "Invalid arguments in GetAll() reply");
65
- goto finish;
66
+ return;
67
}
68
69
spa_log_debug(this->log, "Call path: %s", call->path);
70
71
72
dbus_message_iter_next(&element_i);
73
}
74
-
75
-finish:
76
- dbus_message_unref(r);
77
}
78
79
static DBusHandlerResult mm_parse_voice_properties(struct impl *this, DBusMessageIter *props_i)
80
81
static void mm_get_managed_objects_reply(DBusPendingCall *pending, void *user_data)
82
{
83
struct impl *this = user_data;
84
- DBusMessage *r;
85
DBusMessageIter i, array_i;
86
87
spa_assert(this->pending == pending);
88
- r = steal_reply_and_unref(&this->pending);
89
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&this->pending);
90
if (r == NULL)
91
return;
92
93
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
94
spa_log_error(this->log, "Failed to get a list of endpoints from ModemManager: %s",
95
dbus_message_get_error_name(r));
96
- goto finish;
97
+ return;
98
}
99
100
if (!dbus_message_iter_init(r, &i) || !spa_streq(dbus_message_get_signature(r), "a{oa{sa{sv}}}")) {
101
spa_log_error(this->log, "Invalid arguments in GetManagedObjects() reply");
102
- goto finish;
103
+ return;
104
}
105
106
dbus_message_iter_recurse(&i, &array_i);
107
108
mm_parse_interfaces(this, &dict_i);
109
dbus_message_iter_next(&array_i);
110
}
111
-
112
-finish:
113
- dbus_message_unref(r);
114
}
115
116
static void call_free(struct call *call)
117
118
static DBusHandlerResult mm_filter_cb(DBusConnection *bus, DBusMessage *m, void *user_data)
119
{
120
struct impl *this = user_data;
121
- DBusError err;
122
-
123
- dbus_error_init(&err);
124
125
if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
126
const char *name, *old_owner, *new_owner;
127
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
128
129
spa_log_debug(this->log, "Name owner changed %s", dbus_message_get_path(m));
130
131
132
const char *path;
133
struct call *call_object;
134
const char *mm_call_interface = MM_DBUS_INTERFACE_CALL;
135
+ spa_autoptr(DBusMessage) m = NULL;
136
137
if (!spa_streq(this->modem.path, dbus_message_get_path(m)))
138
goto finish;
139
140
if (m == NULL)
141
goto finish;
142
dbus_message_append_args(m, DBUS_TYPE_STRING, &mm_call_interface, DBUS_TYPE_INVALID);
143
- if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_properties_reply, call_object)) {
144
+
145
+ call_object->pending = send_with_reply(this->conn, m, mm_get_call_properties_reply, call_object);
146
+ if (!call_object->pending) {
147
spa_log_error(this->log, "dbus call failure");
148
goto finish;
149
}
150
151
152
static int add_filters(struct impl *this)
153
{
154
- DBusError err;
155
-
156
if (this->filters_added)
157
return 0;
158
159
- dbus_error_init(&err);
160
-
161
if (!dbus_connection_add_filter(this->conn, mm_filter_cb, this, NULL)) {
162
spa_log_error(this->log, "failed to add filter function");
163
- goto fail;
164
+ return -EIO;
165
}
166
167
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
168
+
169
dbus_bus_add_match(this->conn,
170
"type='signal',sender='org.freedesktop.DBus',"
171
"interface='org.freedesktop.DBus',member='NameOwnerChanged'," "arg0='" MM_DBUS_SERVICE "'", &err);
172
173
this->filters_added = true;
174
175
return 0;
176
-
177
-fail:
178
- dbus_error_free(&err);
179
- return -EIO;
180
}
181
182
bool mm_is_available(void *modemmanager)
183
184
struct impl *this = dbus_cmd_data->this;
185
struct call *call = dbus_cmd_data->call;
186
void *user_data = dbus_cmd_data->user_data;
187
- DBusMessage *r;
188
189
free(data);
190
191
spa_assert(call->pending == pending);
192
- r = steal_reply_and_unref(&call->pending);
193
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&call->pending);
194
if (r == NULL)
195
return;
196
197
198
struct dbus_cmd_data *dbus_cmd_data = data;
199
struct impl *this = dbus_cmd_data->this;
200
void *user_data = dbus_cmd_data->user_data;
201
- DBusMessage *r;
202
203
free(data);
204
205
spa_assert(this->voice_pending == pending);
206
- r = steal_reply_and_unref(&this->voice_pending);
207
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&this->voice_pending);
208
if (r == NULL)
209
return;
210
211
212
{
213
struct impl *this = modemmanager;
214
struct call *call_object, *call_tmp;
215
- struct dbus_cmd_data *data;
216
- DBusMessage *m;
217
+ spa_autofree struct dbus_cmd_data *data = NULL;
218
+ spa_autoptr(DBusMessage) m = NULL;
219
220
call_object = NULL;
221
spa_list_for_each(call_tmp, &this->call_list, link) {
222
223
*error = CMEE_AG_FAILURE;
224
return false;
225
}
226
- if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_simple_reply, data)) {
227
+
228
+ call_object->pending = send_with_reply(this->conn, m, mm_get_call_simple_reply, data);
229
+ if (!call_object->pending) {
230
spa_log_error(this->log, "dbus call failure");
231
if (error)
232
*error = CMEE_AG_FAILURE;
233
return false;
234
}
235
236
- return true;
237
+ return spa_steal_ptr(data), true;
238
}
239
240
bool mm_hangup_call(void *modemmanager, void *user_data, enum cmee_error *error)
241
{
242
struct impl *this = modemmanager;
243
struct call *call_object, *call_tmp;
244
- struct dbus_cmd_data *data;
245
- DBusMessage *m;
246
+ spa_autofree struct dbus_cmd_data *data= NULL;
247
+ spa_autoptr(DBusMessage) m = NULL;
248
249
call_object = NULL;
250
spa_list_for_each(call_tmp, &this->call_list, link) {
251
252
*error = CMEE_AG_FAILURE;
253
return false;
254
}
255
- if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_simple_reply, data)) {
256
+
257
+ call_object->pending = send_with_reply(this->conn, m, mm_get_call_simple_reply, data);
258
+ if (!call_object->pending) {
259
spa_log_error(this->log, "dbus call failure");
260
if (error)
261
*error = CMEE_AG_FAILURE;
262
return false;
263
}
264
265
- return true;
266
+ return spa_steal_ptr(data), true;
267
}
268
269
static void append_basic_variant_dict_entry(DBusMessageIter *dict, const char* key, int variant_type_int, const char* variant_type_str, void* variant) {
270
271
bool mm_do_call(void *modemmanager, const char* number, void *user_data, enum cmee_error *error)
272
{
273
struct impl *this = modemmanager;
274
- struct dbus_cmd_data *data;
275
- DBusMessage *m;
276
+ spa_autofree struct dbus_cmd_data *data = NULL;
277
+ spa_autoptr(DBusMessage) m = NULL;
278
DBusMessageIter iter, dict;
279
280
for (size_t i = 0; numberi; i++) {
281
282
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
283
append_basic_variant_dict_entry(&dict, "number", DBUS_TYPE_STRING, "s", &number);
284
dbus_message_iter_close_container(&iter, &dict);
285
- if (!mm_dbus_connection_send_with_reply(this, m, &this->voice_pending, mm_get_call_create_reply, data)) {
286
+
287
+ this->voice_pending = send_with_reply(this->conn, m, mm_get_call_create_reply, data);
288
+ if (!this->voice_pending) {
289
spa_log_error(this->log, "dbus call failure");
290
if (error)
291
*error = CMEE_AG_FAILURE;
292
return false;
293
}
294
295
- return true;
296
+ return spa_steal_ptr(data), true;
297
}
298
299
bool mm_send_dtmf(void *modemmanager, const char *dtmf, void *user_data, enum cmee_error *error)
300
{
301
struct impl *this = modemmanager;
302
struct call *call_object, *call_tmp;
303
- struct dbus_cmd_data *data;
304
- DBusMessage *m;
305
+ spa_autofree struct dbus_cmd_data *data = NULL;
306
+ spa_autoptr(DBusMessage) m = NULL;
307
308
call_object = NULL;
309
spa_list_for_each(call_tmp, &this->call_list, link) {
310
311
return false;
312
}
313
dbus_message_append_args(m, DBUS_TYPE_STRING, &dtmf, DBUS_TYPE_INVALID);
314
- if (!mm_dbus_connection_send_with_reply(this, m, &call_object->pending, mm_get_call_simple_reply, data)) {
315
+
316
+ call_object->pending = send_with_reply(this->conn, m, mm_get_call_simple_reply, data);
317
+ if (!call_object->pending) {
318
spa_log_error(this->log, "dbus call failure");
319
if (error)
320
*error = CMEE_AG_FAILURE;
321
return false;
322
}
323
324
- return true;
325
+ return spa_steal_ptr(data), true;
326
}
327
328
const char *mm_get_incoming_call_number(void *modemmanager)
329
330
void *mm_register(struct spa_log *log, void *dbus_connection, const struct spa_dict *info,
331
const struct mm_ops *ops, void *user_data)
332
{
333
- struct impl *this;
334
const char *modem_device_str = NULL;
335
bool modem_device_found = false;
336
337
338
return NULL;
339
}
340
341
- this = calloc(1, sizeof(struct impl));
342
+ spa_autofree struct impl *this = calloc(1, sizeof(*this));
343
if (this == NULL)
344
return NULL;
345
346
347
this->allowed_modem_device = strdup(modem_device_str);
348
spa_list_init(&this->call_list);
349
350
- if (add_filters(this) < 0) {
351
- goto fail;
352
- }
353
+ if (add_filters(this) < 0)
354
+ return NULL;
355
356
- DBusMessage *m = dbus_message_new_method_call(MM_DBUS_SERVICE, "/org/freedesktop/ModemManager1",
357
- DBUS_INTERFACE_OBJECTMANAGER, "GetManagedObjects");
358
+ spa_autoptr(DBusMessage) m = dbus_message_new_method_call(MM_DBUS_SERVICE,
359
+ "/org/freedesktop/ModemManager1",
360
+ DBUS_INTERFACE_OBJECTMANAGER,
361
+ "GetManagedObjects");
362
if (m == NULL)
363
- goto fail;
364
+ return NULL;
365
366
dbus_message_set_auto_start(m, false);
367
368
- if (!mm_dbus_connection_send_with_reply(this, m, &this->pending, mm_get_managed_objects_reply, this)) {
369
+ this->pending = send_with_reply(this->conn, m, mm_get_managed_objects_reply, this);
370
+ if (!this->pending) {
371
spa_log_error(this->log, "dbus call failure");
372
- goto fail;
373
+ return NULL;
374
}
375
376
- return this;
377
-
378
-fail:
379
- free(this);
380
- return NULL;
381
+ return spa_steal_ptr(this);
382
}
383
384
void mm_unregister(void *data)
385
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/player.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/player.c
Changed
145
1
2
#include <spa/utils/string.h>
3
4
#include "defs.h"
5
+#include "dbus-helpers.h"
6
#include "player.h"
7
8
#define PLAYER_OBJECT_PATH_BASE "/media_player"
9
10
static DBusMessage *introspect(struct impl *impl, DBusMessage *m)
11
{
12
const char *xml = PLAYER_INTROSPECT_XML;
13
- DBusMessage *r;
14
+ spa_autoptr(DBusMessage) r = NULL;
15
if ((r = dbus_message_new_method_return(m)) == NULL)
16
return NULL;
17
if (!dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID))
18
return NULL;
19
- return r;
20
+ return spa_steal_ptr(r);
21
}
22
23
static DBusHandlerResult player_handler(DBusConnection *c, DBusMessage *m, void *userdata)
24
{
25
struct impl *impl = userdata;
26
- DBusMessage *r;
27
+ spa_autoptr(DBusMessage) r = NULL;
28
29
if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect")) {
30
r = introspect(impl, m);
31
32
33
if (r == NULL)
34
return DBUS_HANDLER_RESULT_NEED_MEMORY;
35
- if (!dbus_connection_send(impl->conn, r, NULL)) {
36
- dbus_message_unref(r);
37
+ if (!dbus_connection_send(impl->conn, r, NULL))
38
return DBUS_HANDLER_RESULT_NEED_MEMORY;
39
- }
40
- dbus_message_unref(r);
41
return DBUS_HANDLER_RESULT_HANDLED;
42
}
43
44
static int send_update_signal(struct impl *impl)
45
{
46
- DBusMessage *m;
47
+ spa_autoptr(DBusMessage) m = NULL;
48
const char *iface = PLAYER_INTERFACE;
49
DBusMessageIter i, a;
50
- int res = 0;
51
52
m = dbus_message_new_signal(impl->path, DBUS_INTERFACE_PROPERTIES, "PropertiesChanged");
53
if (m == NULL)
54
55
dbus_message_iter_close_container(&i, &a);
56
57
if (!dbus_connection_send(impl->conn, m, NULL))
58
- res = -EIO;
59
-
60
- dbus_message_unref(m);
61
+ return -EIO;
62
63
- return res;
64
+ return 0;
65
}
66
67
static void update_properties(struct impl *impl, bool send_signal)
68
69
{
70
struct impl *impl = SPA_CONTAINER_OF(player, struct impl, this);
71
72
- DBusError err;
73
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
74
DBusMessageIter i;
75
- DBusMessage *m, *r;
76
- int res = 0;
77
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
78
79
spa_log_debug(impl->log, "RegisterPlayer() for dummy AVRCP player %s for %s",
80
impl->path, adapter_path);
81
82
dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, &impl->path);
83
append_properties(impl, &i);
84
85
- dbus_error_init(&err);
86
r = dbus_connection_send_with_reply_and_block(impl->conn, m, -1, &err);
87
- dbus_message_unref(m);
88
-
89
if (r == NULL) {
90
spa_log_error(impl->log, "RegisterPlayer() failed (%s)", err.message);
91
- dbus_error_free(&err);
92
return -EIO;
93
}
94
95
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
96
spa_log_error(impl->log, "RegisterPlayer() failed");
97
- res = -EIO;
98
+ return -EIO;
99
}
100
101
- dbus_message_unref(r);
102
-
103
- return res;
104
+ return 0;
105
}
106
107
int spa_bt_player_unregister(struct spa_bt_player *player, const char *adapter_path)
108
{
109
struct impl *impl = SPA_CONTAINER_OF(player, struct impl, this);
110
111
- DBusError err;
112
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
113
DBusMessageIter i;
114
- DBusMessage *m, *r;
115
- int res = 0;
116
+ spa_autoptr(DBusMessage) m = NULL, r = NULL;
117
118
spa_log_debug(impl->log, "UnregisterPlayer() for dummy AVRCP player %s for %s",
119
impl->path, adapter_path);
120
121
dbus_message_iter_init_append(m, &i);
122
dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, &impl->path);
123
124
- dbus_error_init(&err);
125
r = dbus_connection_send_with_reply_and_block(impl->conn, m, -1, &err);
126
- dbus_message_unref(m);
127
-
128
if (r == NULL) {
129
spa_log_error(impl->log, "UnregisterPlayer() failed (%s)", err.message);
130
- dbus_error_free(&err);
131
return -EIO;
132
}
133
134
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
135
spa_log_error(impl->log, "UnregisterPlayer() failed");
136
- res = -EIO;
137
+ return -EIO;
138
}
139
140
- dbus_message_unref(r);
141
-
142
- return res;
143
+ return 0;
144
}
145
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/quirks.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/quirks.c
Changed
41
1
2
#include <spa/support/plugin.h>
3
#include <spa/monitor/device.h>
4
#include <spa/monitor/utils.h>
5
+#include <spa/utils/cleanup.h>
6
#include <spa/utils/hook.h>
7
#include <spa/utils/type.h>
8
#include <spa/utils/keys.h>
9
10
{
11
char *data;
12
struct stat sbuf;
13
- int fd = -1;
14
+ spa_autoclose int fd = -1;
15
16
spa_log_debug(this->log, "loading %s", path);
17
18
if ((fd = open(path, O_CLOEXEC | O_RDONLY)) < 0)
19
- goto fail;
20
+ return -errno;
21
if (fstat(fd, &sbuf) < 0)
22
- goto fail;
23
+ return -errno;
24
if ((data = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
25
- goto fail;
26
- close(fd);
27
+ return -errno;
28
29
load_quirks(this, data, sbuf.st_size);
30
munmap(data, sbuf.st_size);
31
32
return 0;
33
-
34
-fail:
35
- if (fd >= 0)
36
- close(fd);
37
- return -errno;
38
}
39
40
struct spa_bt_quirks *spa_bt_quirks_create(const struct spa_dict *info, struct spa_log *log)
41
pipewire-0.3.76.tar.gz/spa/plugins/bluez5/upower.c -> pipewire-0.3.77.tar.gz/spa/plugins/bluez5/upower.c
Changed
110
1
2
static void upower_get_percentage_properties_reply(DBusPendingCall *pending, void *user_data)
3
{
4
struct impl *backend = user_data;
5
- DBusMessage *r;
6
DBusMessageIter i, variant_i;
7
8
spa_assert(backend->pending_get_call == pending);
9
- r = steal_reply_and_unref(&backend->pending_get_call);
10
+ spa_autoptr(DBusMessage) r = steal_reply_and_unref(&backend->pending_get_call);
11
if (r == NULL)
12
return;
13
14
if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) {
15
spa_log_error(backend->log, "Failed to get percentage from UPower: %s",
16
dbus_message_get_error_name(r));
17
- goto finish;
18
+ return;
19
}
20
21
if (!dbus_message_iter_init(r, &i) || !spa_streq(dbus_message_get_signature(r), "v")) {
22
spa_log_error(backend->log, "Invalid arguments in Get() reply");
23
- goto finish;
24
+ return;
25
}
26
27
dbus_message_iter_recurse(&i, &variant_i);
28
upower_parse_percentage(backend, &variant_i);
29
-
30
-finish:
31
- dbus_message_unref(r);
32
}
33
34
static int update_battery_percentage(struct impl *this)
35
{
36
cancel_and_unref(&this->pending_get_call);
37
38
- DBusMessage *m = dbus_message_new_method_call(UPOWER_SERVICE,
39
- UPOWER_DISPLAY_DEVICE_OBJECT,
40
- DBUS_INTERFACE_PROPERTIES,
41
- "Get");
42
+ spa_autoptr(DBusMessage) m = dbus_message_new_method_call(UPOWER_SERVICE,
43
+ UPOWER_DISPLAY_DEVICE_OBJECT,
44
+ DBUS_INTERFACE_PROPERTIES,
45
+ "Get");
46
if (!m)
47
return -ENOMEM;
48
49
50
DBUS_TYPE_INVALID);
51
dbus_message_set_auto_start(m, false);
52
53
- dbus_connection_send_with_reply(this->conn, m, &this->pending_get_call, -1);
54
- dbus_pending_call_set_notify(this->pending_get_call, upower_get_percentage_properties_reply, this, NULL);
55
-
56
- dbus_message_unref(m);
57
+ this->pending_get_call = send_with_reply(this->conn, m, upower_get_percentage_properties_reply, this);
58
+ if (!this->pending_get_call)
59
+ return -EIO;
60
61
return 0;
62
}
63
64
static DBusHandlerResult upower_filter_cb(DBusConnection *bus, DBusMessage *m, void *user_data)
65
{
66
struct impl *this = user_data;
67
- DBusError err;
68
-
69
- dbus_error_init(&err);
70
71
if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) {
72
const char *name, *old_owner, *new_owner;
73
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
74
75
spa_log_debug(this->log, "Name owner changed %s", dbus_message_get_path(m));
76
77
78
79
static int add_filters(struct impl *this)
80
{
81
- DBusError err;
82
-
83
if (this->filters_added)
84
return 0;
85
86
- dbus_error_init(&err);
87
-
88
if (!dbus_connection_add_filter(this->conn, upower_filter_cb, this, NULL)) {
89
spa_log_error(this->log, "failed to add filter function");
90
- goto fail;
91
+ return -EIO;
92
}
93
94
+ spa_auto(DBusError) err = DBUS_ERROR_INIT;
95
+
96
dbus_bus_add_match(this->conn,
97
"type='signal',sender='org.freedesktop.DBus',"
98
"interface='org.freedesktop.DBus',member='NameOwnerChanged'," "arg0='" UPOWER_SERVICE "'", &err);
99
100
this->filters_added = true;
101
102
return 0;
103
-
104
-fail:
105
- dbus_error_free(&err);
106
- return -EIO;
107
}
108
109
void *upower_register(struct spa_log *log,
110
pipewire-0.3.76.tar.gz/spa/plugins/v4l2/v4l2-udev.c -> pipewire-0.3.77.tar.gz/spa/plugins/v4l2/v4l2-udev.c
Changed
595
1
2
#define ACTION_DISABLE 2
3
4
struct device {
5
+ struct impl *impl;
6
uint32_t id;
7
struct udev_device *dev;
8
+ struct spa_source notify;
9
unsigned int accessible:1;
10
unsigned int ignored:1;
11
unsigned int emitted:1;
12
13
uint32_t n_devices;
14
15
struct spa_source source;
16
- struct spa_source notify;
17
};
18
19
-static int impl_udev_open(struct impl *this)
20
+static int stop_inotify(struct device *dev);
21
+static int start_inotify(struct device *dev);
22
+
23
+static int impl_udev_open(struct impl *impl)
24
{
25
- if (this->udev == NULL) {
26
- this->udev = udev_new();
27
- if (this->udev == NULL)
28
+ if (impl->udev == NULL) {
29
+ impl->udev = udev_new();
30
+ if (impl->udev == NULL)
31
return -ENOMEM;
32
}
33
return 0;
34
}
35
36
-static int impl_udev_close(struct impl *this)
37
+static int impl_udev_close(struct impl *impl)
38
{
39
- if (this->udev != NULL)
40
- udev_unref(this->udev);
41
- this->udev = NULL;
42
+ if (impl->udev != NULL)
43
+ udev_unref(impl->udev);
44
+ impl->udev = NULL;
45
return 0;
46
}
47
48
-static struct device *add_device(struct impl *this, uint32_t id, struct udev_device *dev)
49
+static struct device *add_device(struct impl *impl, uint32_t id, struct udev_device *dev)
50
{
51
struct device *device;
52
53
- if (this->n_devices >= MAX_DEVICES)
54
+ if (impl->n_devices >= MAX_DEVICES)
55
return NULL;
56
- device = &this->devicesthis->n_devices++;
57
+ device = &impl->devicesimpl->n_devices++;
58
spa_zero(*device);
59
+ device->impl = impl;
60
+ device->notify.fd = -1;
61
device->id = id;
62
udev_device_ref(dev);
63
device->dev = dev;
64
+ start_inotify(device);
65
return device;
66
}
67
68
-static struct device *find_device(struct impl *this, uint32_t id)
69
+static struct device *find_device(struct impl *impl, uint32_t id)
70
{
71
uint32_t i;
72
- for (i = 0; i < this->n_devices; i++) {
73
- if (this->devicesi.id == id)
74
- return &this->devicesi;
75
+ for (i = 0; i < impl->n_devices; i++) {
76
+ if (impl->devicesi.id == id)
77
+ return &impl->devicesi;
78
}
79
return NULL;
80
}
81
82
-static void remove_device(struct impl *this, struct device *device)
83
+static void clear_device(struct device *device)
84
+{
85
+ stop_inotify(device);
86
+ if (device->dev)
87
+ udev_device_unref(device->dev);
88
+}
89
+
90
+static void remove_device(struct device *device)
91
{
92
- udev_device_unref(device->dev);
93
- *device = this->devices--this->n_devices;
94
+ struct impl *impl = device->impl;
95
+ clear_device(device);
96
+ *device = impl->devices--impl->n_devices;
97
}
98
99
-static void clear_devices(struct impl *this)
100
+static void clear_devices(struct impl *impl)
101
{
102
uint32_t i;
103
- for (i = 0; i < this->n_devices; i++)
104
- udev_device_unref(this->devicesi.dev);
105
- this->n_devices = 0;
106
+ for (i = 0; i < impl->n_devices; i++)
107
+ clear_device(&impl->devicesi);
108
+ impl->n_devices = 0;
109
}
110
111
-static uint32_t get_device_id(struct impl *this, struct udev_device *dev)
112
+static uint32_t get_device_id(struct impl *impl, struct udev_device *dev)
113
{
114
const char *str;
115
116
117
*d = 0;
118
}
119
120
-static int emit_object_info(struct impl *this, struct device *device)
121
+static int emit_object_info(struct device *device)
122
{
123
+ struct impl *impl = device->impl;
124
struct spa_device_object_info info;
125
uint32_t id = device->id;
126
struct udev_device *dev = device->dev;
127
128
itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_CAPABILITIES, str);
129
}
130
info.props = &SPA_DICT_INIT(items, n_items);
131
- spa_device_emit_object_info(&this->hooks, id, &info);
132
+ spa_device_emit_object_info(&impl->hooks, id, &info);
133
device->emitted = true;
134
135
return 1;
136
}
137
138
-static bool check_access(struct impl *this, struct device *device)
139
+static bool check_access(struct device *device)
140
{
141
char path128;
142
143
snprintf(path, sizeof(path), "/dev/video%u", device->id);
144
device->accessible = access(path, R_OK|W_OK) >= 0;
145
- spa_log_debug(this->log, "%s accessible:%u", path, device->accessible);
146
+ spa_log_debug(device->impl->log, "%s accessible:%u", path, device->accessible);
147
148
return device->accessible;
149
}
150
151
-static void process_device(struct impl *this, uint32_t action, struct udev_device *dev)
152
+static void process_device(struct impl *impl, uint32_t action, struct udev_device *dev)
153
{
154
uint32_t id;
155
struct device *device;
156
bool emitted;
157
158
- if ((id = get_device_id(this, dev)) == SPA_ID_INVALID)
159
+ if ((id = get_device_id(impl, dev)) == SPA_ID_INVALID)
160
return;
161
162
- device = find_device(this, id);
163
+ device = find_device(impl, id);
164
if (device && device->ignored)
165
return;
166
167
switch (action) {
168
case ACTION_ADD:
169
if (device == NULL)
170
- device = add_device(this, id, dev);
171
+ device = add_device(impl, id, dev);
172
if (device == NULL)
173
return;
174
- if (!check_access(this, device))
175
+ if (!check_access(device))
176
return;
177
- emit_object_info(this, device);
178
+ else
179
+ emit_object_info(device);
180
break;
181
182
case ACTION_REMOVE:
183
if (device == NULL)
184
return;
185
emitted = device->emitted;
186
- remove_device(this, device);
187
+ remove_device(device);
188
if (emitted)
189
- spa_device_emit_object_info(&this->hooks, id, NULL);
190
+ spa_device_emit_object_info(&impl->hooks, id, NULL);
191
break;
192
193
case ACTION_DISABLE:
194
195
return;
196
if (device->emitted) {
197
device->emitted = false;
198
- spa_device_emit_object_info(&this->hooks, id, NULL);
199
+ spa_device_emit_object_info(&impl->hooks, id, NULL);
200
}
201
break;
202
}
203
}
204
205
-static int stop_inotify(struct impl *this)
206
-{
207
- if (this->notify.fd == -1)
208
- return 0;
209
- spa_log_info(this->log, "stop inotify");
210
- spa_loop_remove_source(this->main_loop, &this->notify);
211
- close(this->notify.fd);
212
- this->notify.fd = -1;
213
- return 0;
214
-}
215
-
216
static void impl_on_notify_events(struct spa_source *source)
217
{
218
- bool deleted = false;
219
- struct impl *this = source->data;
220
+ struct device *dev = source->data;
221
+ struct impl *impl = dev->impl;
222
union {
223
unsigned char namesizeof(struct inotify_event) + NAME_MAX + 1;
224
struct inotify_event e; /* for appropriate alignment */
225
226
227
for (p = &buf; p < e;
228
p = SPA_PTROFF(p, sizeof(struct inotify_event) + event->len, void)) {
229
- unsigned int id;
230
- struct device *device;
231
232
event = (const struct inotify_event *) p;
233
234
if ((event->mask & IN_ATTRIB)) {
235
bool access;
236
- if (sscanf(event->name, "video%u", &id) != 1)
237
- continue;
238
- if ((device = find_device(this, id)) == NULL)
239
- continue;
240
- access = check_access(this, device);
241
- if (access && !device->emitted)
242
- process_device(this, ACTION_ADD, device->dev);
243
- else if (!access && device->emitted)
244
- process_device(this, ACTION_DISABLE, device->dev);
245
+ access = check_access(dev);
246
+ if (access && !dev->emitted)
247
+ process_device(impl, ACTION_ADD, dev->dev);
248
+ else if (!access && dev->emitted)
249
+ process_device(impl, ACTION_DISABLE, dev->dev);
250
}
251
- /* /dev/ might have been removed */
252
- if ((event->mask & (IN_DELETE_SELF | IN_MOVE_SELF)))
253
- deleted = true;
254
}
255
}
256
- if (deleted)
257
- stop_inotify(this);
258
}
259
260
-static int start_inotify(struct impl *this)
261
+static int start_inotify(struct device *dev)
262
{
263
+ struct impl *impl = dev->impl;
264
int res, notify_fd;
265
+ char name32;
266
267
- if (this->notify.fd != -1)
268
+ if (dev->notify.fd != -1)
269
return 0;
270
271
if ((notify_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK)) < 0)
272
return -errno;
273
274
- res = inotify_add_watch(notify_fd, "/dev",
275
- IN_ATTRIB | IN_CLOSE_WRITE | IN_DELETE_SELF | IN_MOVE_SELF);
276
+ snprintf(name, sizeof(name), "/dev/video%u", dev->id);
277
+
278
+ res = inotify_add_watch(notify_fd, name, IN_ATTRIB | IN_CLOSE_WRITE);
279
if (res < 0) {
280
res = -errno;
281
close(notify_fd);
282
283
if (res == -ENOENT) {
284
- spa_log_debug(this->log, "/dev/ does not exist yet");
285
+ spa_log_debug(impl->log, "%s does not exist yet", name);
286
return 0;
287
}
288
- spa_log_error(this->log, "inotify_add_watch() failed: %s", spa_strerror(res));
289
+ spa_log_error(impl->log, "inotify_add_watch() failed: %s", spa_strerror(res));
290
return res;
291
}
292
- spa_log_info(this->log, "start inotify");
293
- this->notify.func = impl_on_notify_events;
294
- this->notify.data = this;
295
- this->notify.fd = notify_fd;
296
- this->notify.mask = SPA_IO_IN | SPA_IO_ERR;
297
+ spa_log_info(impl->log, "start inotify for %s", name);
298
+ dev->notify.func = impl_on_notify_events;
299
+ dev->notify.data = dev;
300
+ dev->notify.fd = notify_fd;
301
+ dev->notify.mask = SPA_IO_IN | SPA_IO_ERR;
302
303
- spa_loop_add_source(this->main_loop, &this->notify);
304
+ spa_loop_add_source(impl->main_loop, &dev->notify);
305
306
return 0;
307
}
308
309
+static int stop_inotify(struct device *dev)
310
+{
311
+ struct impl *impl = dev->impl;
312
+ if (dev->notify.fd == -1)
313
+ return 0;
314
+ spa_log_info(impl->log, "stop inotify for /dev/video%u", dev->id);
315
+ spa_loop_remove_source(impl->main_loop, &dev->notify);
316
+ close(dev->notify.fd);
317
+ dev->notify.fd = -1;
318
+ return 0;
319
+}
320
+
321
static void impl_on_fd_events(struct spa_source *source)
322
{
323
- struct impl *this = source->data;
324
+ struct impl *impl = source->data;
325
struct udev_device *dev;
326
const char *action;
327
328
- dev = udev_monitor_receive_device(this->umonitor);
329
+ dev = udev_monitor_receive_device(impl->umonitor);
330
if (dev == NULL)
331
return;
332
333
if ((action = udev_device_get_action(dev)) == NULL)
334
action = "change";
335
336
- spa_log_debug(this->log, "action %s", action);
337
-
338
- start_inotify(this);
339
+ spa_log_debug(impl->log, "action %s", action);
340
341
if (spa_streq(action, "add") ||
342
spa_streq(action, "change")) {
343
- process_device(this, ACTION_ADD, dev);
344
+ process_device(impl, ACTION_ADD, dev);
345
} else if (spa_streq(action, "remove")) {
346
- process_device(this, ACTION_REMOVE, dev);
347
+ process_device(impl, ACTION_REMOVE, dev);
348
}
349
udev_device_unref(dev);
350
}
351
352
-static int start_monitor(struct impl *this)
353
+static int start_monitor(struct impl *impl)
354
{
355
- int res;
356
-
357
- if (this->umonitor != NULL)
358
+ if (impl->umonitor != NULL)
359
return 0;
360
361
- this->umonitor = udev_monitor_new_from_netlink(this->udev, "udev");
362
- if (this->umonitor == NULL)
363
+ impl->umonitor = udev_monitor_new_from_netlink(impl->udev, "udev");
364
+ if (impl->umonitor == NULL)
365
return -ENOMEM;
366
367
- udev_monitor_filter_add_match_subsystem_devtype(this->umonitor,
368
+ udev_monitor_filter_add_match_subsystem_devtype(impl->umonitor,
369
"video4linux", NULL);
370
- udev_monitor_enable_receiving(this->umonitor);
371
-
372
- this->source.func = impl_on_fd_events;
373
- this->source.data = this;
374
- this->source.fd = udev_monitor_get_fd(this->umonitor);
375
- this->source.mask = SPA_IO_IN | SPA_IO_ERR;
376
+ udev_monitor_enable_receiving(impl->umonitor);
377
378
- spa_log_debug(this->log, "monitor %p", this->umonitor);
379
- spa_loop_add_source(this->main_loop, &this->source);
380
+ impl->source.func = impl_on_fd_events;
381
+ impl->source.data = impl;
382
+ impl->source.fd = udev_monitor_get_fd(impl->umonitor);
383
+ impl->source.mask = SPA_IO_IN | SPA_IO_ERR;
384
385
- if ((res = start_inotify(this)) < 0)
386
- return res;
387
+ spa_log_debug(impl->log, "monitor %p", impl->umonitor);
388
+ spa_loop_add_source(impl->main_loop, &impl->source);
389
390
return 0;
391
}
392
393
-static int stop_monitor(struct impl *this)
394
+static int stop_monitor(struct impl *impl)
395
{
396
- if (this->umonitor == NULL)
397
+ if (impl->umonitor == NULL)
398
return 0;
399
400
- clear_devices (this);
401
-
402
- spa_loop_remove_source(this->main_loop, &this->source);
403
- udev_monitor_unref(this->umonitor);
404
- this->umonitor = NULL;
405
+ clear_devices(impl);
406
407
- stop_inotify(this);
408
+ spa_loop_remove_source(impl->main_loop, &impl->source);
409
+ udev_monitor_unref(impl->umonitor);
410
+ impl->umonitor = NULL;
411
412
return 0;
413
}
414
415
-static int enum_devices(struct impl *this)
416
+static int enum_devices(struct impl *impl)
417
{
418
struct udev_enumerate *enumerate;
419
struct udev_list_entry *devices;
420
421
- enumerate = udev_enumerate_new(this->udev);
422
+ enumerate = udev_enumerate_new(impl->udev);
423
if (enumerate == NULL)
424
return -ENOMEM;
425
426
427
devices = udev_list_entry_get_next(devices)) {
428
struct udev_device *dev;
429
430
- dev = udev_device_new_from_syspath(this->udev, udev_list_entry_get_name(devices));
431
+ dev = udev_device_new_from_syspath(impl->udev, udev_list_entry_get_name(devices));
432
if (dev == NULL)
433
continue;
434
435
- process_device(this, ACTION_ADD, dev);
436
+ process_device(impl, ACTION_ADD, dev);
437
438
udev_device_unref(dev);
439
}
440
441
{ SPA_KEY_API_UDEV_MATCH, "video4linux" },
442
};
443
444
-static void emit_device_info(struct impl *this, bool full)
445
+static void emit_device_info(struct impl *impl, bool full)
446
{
447
- uint64_t old = full ? this->info.change_mask : 0;
448
+ uint64_t old = full ? impl->info.change_mask : 0;
449
if (full)
450
- this->info.change_mask = this->info_all;
451
- if (this->info.change_mask) {
452
- this->info.props = &SPA_DICT_INIT_ARRAY(device_info_items);
453
- spa_device_emit_info(&this->hooks, &this->info);
454
- this->info.change_mask = old;
455
+ impl->info.change_mask = impl->info_all;
456
+ if (impl->info.change_mask) {
457
+ impl->info.props = &SPA_DICT_INIT_ARRAY(device_info_items);
458
+ spa_device_emit_info(&impl->hooks, &impl->info);
459
+ impl->info.change_mask = old;
460
}
461
}
462
463
static void impl_hook_removed(struct spa_hook *hook)
464
{
465
- struct impl *this = hook->priv;
466
- if (spa_hook_list_is_empty(&this->hooks)) {
467
- stop_monitor(this);
468
- impl_udev_close(this);
469
+ struct impl *impl = hook->priv;
470
+ if (spa_hook_list_is_empty(&impl->hooks)) {
471
+ stop_monitor(impl);
472
+ impl_udev_close(impl);
473
}
474
}
475
476
477
const struct spa_device_events *events, void *data)
478
{
479
int res;
480
- struct impl *this = object;
481
+ struct impl *impl = object;
482
struct spa_hook_list save;
483
484
- spa_return_val_if_fail(this != NULL, -EINVAL);
485
+ spa_return_val_if_fail(impl != NULL, -EINVAL);
486
spa_return_val_if_fail(events != NULL, -EINVAL);
487
488
- if ((res = impl_udev_open(this)) < 0)
489
+ if ((res = impl_udev_open(impl)) < 0)
490
return res;
491
492
- spa_hook_list_isolate(&this->hooks, &save, listener, events, data);
493
+ spa_hook_list_isolate(&impl->hooks, &save, listener, events, data);
494
495
- emit_device_info(this, true);
496
+ emit_device_info(impl, true);
497
498
- if ((res = enum_devices(this)) < 0)
499
+ if ((res = enum_devices(impl)) < 0)
500
return res;
501
502
- if ((res = start_monitor(this)) < 0)
503
+ if ((res = start_monitor(impl)) < 0)
504
return res;
505
506
- spa_hook_list_join(&this->hooks, &save);
507
+ spa_hook_list_join(&impl->hooks, &save);
508
509
listener->removed = impl_hook_removed;
510
- listener->priv = this;
511
+ listener->priv = impl;
512
513
return 0;
514
}
515
516
517
static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
518
{
519
- struct impl *this;
520
+ struct impl *impl;
521
522
spa_return_val_if_fail(handle != NULL, -EINVAL);
523
spa_return_val_if_fail(interface != NULL, -EINVAL);
524
525
- this = (struct impl *) handle;
526
+ impl = (struct impl *) handle;
527
528
if (spa_streq(type, SPA_TYPE_INTERFACE_Device))
529
- *interface = &this->device;
530
+ *interface = &impl->device;
531
else
532
return -ENOENT;
533
534
535
536
static int impl_clear(struct spa_handle *handle)
537
{
538
- struct impl *this = (struct impl *) handle;
539
- stop_monitor(this);
540
- impl_udev_close(this);
541
+ struct impl *impl = (struct impl *) handle;
542
+ stop_monitor(impl);
543
+ impl_udev_close(impl);
544
return 0;
545
}
546
547
548
const struct spa_support *support,
549
uint32_t n_support)
550
{
551
- struct impl *this;
552
+ struct impl *impl;
553
554
spa_return_val_if_fail(factory != NULL, -EINVAL);
555
spa_return_val_if_fail(handle != NULL, -EINVAL);
556
557
handle->get_interface = impl_get_interface;
558
handle->clear = impl_clear;
559
560
- this = (struct impl *) handle;
561
- this->notify.fd = -1;
562
-
563
- this->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
564
- this->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
565
+ impl = (struct impl *) handle;
566
+ impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
567
+ impl->main_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop);
568
569
- if (this->main_loop == NULL) {
570
- spa_log_error(this->log, "a main-loop is needed");
571
+ if (impl->main_loop == NULL) {
572
+ spa_log_error(impl->log, "a main-loop is needed");
573
return -EINVAL;
574
}
575
- spa_hook_list_init(&this->hooks);
576
+ spa_hook_list_init(&impl->hooks);
577
578
- this->device.iface = SPA_INTERFACE_INIT(
579
+ impl->device.iface = SPA_INTERFACE_INIT(
580
SPA_TYPE_INTERFACE_Device,
581
SPA_VERSION_DEVICE,
582
- &impl_device, this);
583
+ &impl_device, impl);
584
585
- this->info = SPA_DEVICE_INFO_INIT();
586
- this->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS |
587
+ impl->info = SPA_DEVICE_INFO_INIT();
588
+ impl->info_all = SPA_DEVICE_CHANGE_MASK_FLAGS |
589
SPA_DEVICE_CHANGE_MASK_PROPS;
590
- this->info.flags = 0;
591
+ impl->info.flags = 0;
592
593
return 0;
594
}
595
pipewire-0.3.76.tar.gz/src/modules/module-metadata/metadata.c -> pipewire-0.3.77.tar.gz/src/modules/module-metadata/metadata.c
Changed
9
1
2
impl->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Metadata,
4
PW_VERSION_METADATA,
5
+ PW_METADATA_PERM_MASK,
6
properties,
7
global_bind, impl);
8
if (impl->global == NULL) {
9
pipewire-0.3.76.tar.gz/src/modules/module-profiler.c -> pipewire-0.3.77.tar.gz/src/modules/module-profiler.c
Changed
45
1
2
3
#include <string.h>
4
#include <stdio.h>
5
+#include <stdalign.h>
6
#include <errno.h>
7
#include <sys/types.h>
8
#include <sys/stat.h>
9
10
struct spa_source *flush_event;
11
unsigned int listening:1;
12
13
+ alignas(max_align_t)
14
uint8_t flushFLUSH_BUFFER + sizeof(struct spa_pod_struct);
15
};
16
17
18
pw_log_trace("%p avail %d", impl, avail);
19
20
if (avail > 0) {
21
- spa_ringbuffer_read_data(&n->buffer, n->data, DATA_BUFFER,
22
- idx % DATA_BUFFER,
23
- SPA_PTROFF(p, sizeof(struct spa_pod_struct) + total, void),
24
- avail);
25
+ if (total + avail < FLUSH_BUFFER) {
26
+ spa_ringbuffer_read_data(&n->buffer, n->data, DATA_BUFFER,
27
+ idx % DATA_BUFFER,
28
+ SPA_PTROFF(p, sizeof(struct spa_pod_struct) + total, void),
29
+ avail);
30
+ total += avail;
31
+ }
32
spa_ringbuffer_read_update(&n->buffer, idx + avail);
33
- total += avail;
34
}
35
}
36
37
38
impl->global = pw_global_new(context,
39
PW_TYPE_INTERFACE_Profiler,
40
PW_VERSION_PROFILER,
41
+ PW_PROFILER_PERM_MASK,
42
pw_properties_copy(props),
43
global_bind, impl);
44
if (impl->global == NULL) {
45
pipewire-0.3.76.tar.gz/src/modules/module-protocol-pulse/collect.c -> pipewire-0.3.77.tar.gz/src/modules/module-protocol-pulse/collect.c
Changed
100
1
2
#include <spa/pod/builder.h>
3
#include <spa/pod/parser.h>
4
#include <spa/utils/string.h>
5
+
6
+#include <spa/param/audio/format-utils.h>
7
+
8
#include <pipewire/pipewire.h>
9
10
#include "collect.h"
11
12
return SPA_ID_INVALID;
13
}
14
15
-void collect_device_info(struct pw_manager_object *device, struct pw_manager_object *card,
16
+static void collect_device_info(struct pw_manager_object *device, struct pw_manager_object *card,
17
struct device_info *dev_info, bool monitor, struct defs *defs)
18
{
19
struct pw_manager_param *p;
20
21
dev_info->volume_info.volume.channels = dev_info->map.channels;
22
}
23
24
+static void update_device_info(struct pw_manager *manager, struct pw_manager_object *o,
25
+ enum pw_direction direction, bool monitor, struct defs *defs)
26
+{
27
+ const char *str;
28
+ const char *key = monitor ? "device.info.monitor" : "device.info";
29
+ struct pw_manager_object *card = NULL;
30
+ struct pw_node_info *info = o->info;
31
+ struct device_info *dev_info, di;
32
+
33
+ if (info == NULL)
34
+ return;
35
+
36
+ di = DEVICE_INFO_INIT(direction);
37
+ if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
38
+ di.card_id = (uint32_t)atoi(str);
39
+ if ((str = spa_dict_lookup(info->props, "card.profile.device")) != NULL)
40
+ di.device = (uint32_t)atoi(str);
41
+ if (di.card_id != SPA_ID_INVALID) {
42
+ struct selector sel = { .id = di.card_id, .type = pw_manager_object_is_card, };
43
+ card = select_object(manager, &sel);
44
+ }
45
+ collect_device_info(o, card, &di, monitor, defs);
46
+
47
+ dev_info = pw_manager_object_get_data(o, key);
48
+ if (dev_info) {
49
+ if (memcmp(dev_info, &di, sizeof(di)) != 0) {
50
+ if (monitor || direction == PW_DIRECTION_INPUT)
51
+ o->change_mask |= PW_MANAGER_OBJECT_FLAG_SOURCE;
52
+ else
53
+ o->change_mask |= PW_MANAGER_OBJECT_FLAG_SINK;
54
+ }
55
+ } else {
56
+ o->change_mask = ~0;
57
+ dev_info = pw_manager_object_add_data(o, key, sizeof(*dev_info));
58
+ }
59
+ if (dev_info != NULL)
60
+ *dev_info = di;
61
+}
62
+
63
+void get_device_info(struct pw_manager_object *o, struct device_info *info,
64
+ enum pw_direction direction, bool monitor)
65
+{
66
+ const char *key = monitor ? "device.info.monitor" : "device.info";
67
+ struct device_info *di;
68
+ di = pw_manager_object_get_data(o, key);
69
+ if (di != NULL)
70
+ *info = *di;
71
+ else
72
+ *info = DEVICE_INFO_INIT(direction);
73
+}
74
+
75
static bool array_contains(uint32_t *vals, uint32_t n_vals, uint32_t val)
76
{
77
uint32_t n;
78
79
80
return n_codecs;
81
}
82
+
83
+void update_object_info(struct pw_manager *manager, struct pw_manager_object *o,
84
+ struct defs *defs)
85
+{
86
+ if (pw_manager_object_is_sink(o)) {
87
+ update_device_info(manager, o, PW_DIRECTION_OUTPUT, false, defs);
88
+ update_device_info(manager, o, PW_DIRECTION_OUTPUT, true, defs);
89
+ }
90
+ if (pw_manager_object_is_source(o)) {
91
+ update_device_info(manager, o, PW_DIRECTION_INPUT, false, defs);
92
+ }
93
+ if (pw_manager_object_is_source_output(o)) {
94
+ update_device_info(manager, o, PW_DIRECTION_INPUT, false, defs);
95
+ }
96
+ if (pw_manager_object_is_sink_input(o)) {
97
+ update_device_info(manager, o, PW_DIRECTION_OUTPUT, false, defs);
98
+ }
99
+}
100
pipewire-0.3.76.tar.gz/src/modules/module-protocol-pulse/collect.h -> pipewire-0.3.77.tar.gz/src/modules/module-protocol-pulse/collect.h
Changed
38
1
2
struct pw_manager_object *select_object(struct pw_manager *m, struct selector *s);
3
uint32_t id_to_index(struct pw_manager *m, uint32_t id);
4
void select_best(struct selector *s, struct pw_manager_object *o);
5
+void update_object_info(struct pw_manager *manager, struct pw_manager_object *o,
6
+ struct defs *defs);
7
8
/* ========================================================================== */
9
10
11
unsigned int have_volume:1;
12
unsigned int have_iec958codecs:1;
13
14
+ uint32_t card_id;
15
uint32_t device;
16
uint32_t active_port;
17
const char *active_port_name;
18
+
19
};
20
21
#define DEVICE_INFO_INIT(_dir) \
22
23
.ss = SAMPLE_SPEC_INIT, \
24
.map = CHANNEL_MAP_INIT, \
25
.volume_info = VOLUME_INFO_INIT, \
26
+ .card_id = SPA_ID_INVALID, \
27
.device = SPA_ID_INVALID, \
28
.active_port = SPA_ID_INVALID, \
29
}
30
31
-void collect_device_info(struct pw_manager_object *device, struct pw_manager_object *card,
32
- struct device_info *dev_info, bool monitor, struct defs *defs);
33
+void get_device_info(struct pw_manager_object *device, struct device_info *info,
34
+ enum pw_direction direction, bool monitor);
35
36
/* ========================================================================== */
37
38
pipewire-0.3.76.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c -> pipewire-0.3.77.tar.gz/src/modules/module-protocol-pulse/extensions/ext-device-restore.c
Changed
42
1
2
static int do_extension_device_restore_save_formats(struct client *client,
3
uint32_t command, uint32_t tag, struct message *m)
4
{
5
- struct impl *impl = client->impl;
6
struct pw_manager *manager = client->manager;
7
struct selector sel;
8
struct pw_manager_object *o, *card = NULL;
9
struct pw_node_info *info;
10
int res;
11
- uint32_t type, sink_index, card_id = SPA_ID_INVALID;
12
+ uint32_t type, sink_index;
13
uint8_t i, n_formats;
14
uint32_t n_codecs = 0, codec, iec958codecs32;
15
struct device_info dev_info;
16
- const char *str;
17
18
if ((res = message_get(m,
19
TAG_U32, &type,
20
21
if (o == NULL || (info = o->info) == NULL || info->props == NULL)
22
return -ENOENT;
23
24
- dev_info = DEVICE_INFO_INIT(SPA_DIRECTION_INPUT);
25
+ get_device_info(o, &dev_info, SPA_DIRECTION_INPUT, false);
26
27
- if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
28
- card_id = (uint32_t)atoi(str);
29
- if ((str = spa_dict_lookup(info->props, "card.profile.device")) != NULL)
30
- dev_info.device = (uint32_t)atoi(str);
31
- if (card_id != SPA_ID_INVALID) {
32
- struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
33
+ if (dev_info.card_id != SPA_ID_INVALID) {
34
+ struct selector sel = { .id = dev_info.card_id, .type = pw_manager_object_is_card, };
35
card = select_object(manager, &sel);
36
}
37
- collect_device_info(o, card, &dev_info, false, &impl->defs);
38
-
39
if (card != NULL && dev_info.active_port != SPA_ID_INVALID) {
40
res = set_card_codecs(card, dev_info.active_port,
41
dev_info.device, n_codecs, iec958codecs);
42
pipewire-0.3.76.tar.gz/src/modules/module-protocol-pulse/manager.c -> pipewire-0.3.77.tar.gz/src/modules/module-protocol-pulse/manager.c
Changed
104
1
2
3
const struct object_info *info;
4
5
+ int changed;
6
struct spa_list pending_list;
7
8
struct spa_hook proxy_listener;
9
10
11
pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->this.id, info->change_mask);
12
13
- info = o->this.info = pw_client_info_merge(o->this.info, info, o->this.changed == 0);
14
+ info = o->this.info = pw_client_info_merge(o->this.info, info, o->changed == 0);
15
if (info == NULL)
16
return;
17
18
19
changed++;
20
21
if (changed) {
22
- o->this.changed += changed;
23
+ o->changed += changed;
24
core_sync(o->manager);
25
}
26
}
27
28
29
pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->this.id, info->change_mask);
30
31
- info = o->this.info = pw_module_info_merge(o->this.info, info, o->this.changed == 0);
32
+ info = o->this.info = pw_module_info_merge(o->this.info, info, o->changed == 0);
33
if (info == NULL)
34
return;
35
36
37
changed++;
38
39
if (changed) {
40
- o->this.changed += changed;
41
+ o->changed += changed;
42
core_sync(o->manager);
43
}
44
}
45
46
47
pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->this.id, info->change_mask);
48
49
- info = o->this.info = pw_device_info_merge(o->this.info, info, o->this.changed == 0);
50
+ info = o->this.info = pw_device_info_merge(o->this.info, info, o->changed == 0);
51
if (info == NULL)
52
return;
53
54
55
}
56
}
57
if (changed) {
58
- o->this.changed += changed;
59
+ o->changed += changed;
60
core_sync(o->manager);
61
}
62
}
63
64
return;
65
66
if ((dev = find_device(m, o->this.id, device)) != NULL) {
67
- dev->this.changed++;
68
+ dev->changed++;
69
core_sync(o->manager);
70
}
71
}
72
73
74
pw_log_debug("object %p: id:%d change-mask:%08"PRIx64, o, o->this.id, info->change_mask);
75
76
- info = o->this.info = pw_node_info_merge(o->this.info, info, o->this.changed == 0);
77
+ info = o->this.info = pw_node_info_merge(o->this.info, info, o->changed == 0);
78
if (info == NULL)
79
return;
80
81
82
}
83
}
84
if (changed) {
85
- o->this.changed += changed;
86
+ o->changed += changed;
87
core_sync(o->manager);
88
}
89
}
90
91
if (o->this.creating) {
92
o->this.creating = false;
93
manager_emit_added(m, &o->this);
94
- o->this.changed = 0;
95
- } else if (o->this.changed > 0) {
96
+ o->changed = 0;
97
+ } else if (o->changed > 0) {
98
manager_emit_updated(m, &o->this);
99
- o->this.changed = 0;
100
+ o->changed = 0;
101
}
102
}
103
}
104
pipewire-0.3.76.tar.gz/src/modules/module-protocol-pulse/manager.h -> pipewire-0.3.77.tar.gz/src/modules/module-protocol-pulse/manager.h
Changed
16
1
2
int (*message_handler)(struct pw_manager *m, struct pw_manager_object *o,
3
const char *message, const char *params, char **response);
4
5
- int changed;
6
void *info;
7
struct spa_param_info *params;
8
uint32_t n_params;
9
10
+#define PW_MANAGER_OBJECT_FLAG_SOURCE (1<<0)
11
+#define PW_MANAGER_OBJECT_FLAG_SINK (1<<1)
12
+ uint64_t change_mask; /* object specific params change mask */
13
struct spa_list param_list;
14
unsigned int creating:1;
15
unsigned int removing:1;
16
pipewire-0.3.76.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c -> pipewire-0.3.77.tar.gz/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c
Changed
45
1
2
static void fill_service_data(struct module_zeroconf_publish_data *d, struct service *s,
3
struct pw_manager_object *o)
4
{
5
- struct impl *impl = d->module->impl;
6
bool is_sink = pw_manager_object_is_sink(o);
7
bool is_source = pw_manager_object_is_source(o);
8
struct pw_node_info *info = o->info;
9
- const char *name, *desc, *str;
10
- uint32_t card_id = SPA_ID_INVALID;
11
+ const char *name, *desc;
12
struct pw_manager *manager = d->manager;
13
struct pw_manager_object *card = NULL;
14
struct card_info card_info = CARD_INFO_INIT;
15
- struct device_info dev_info = is_sink ?
16
- DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT) : DEVICE_INFO_INIT(PW_DIRECTION_INPUT);
17
+ struct device_info dev_info;
18
uint32_t flags = 0;
19
20
if (info == NULL || info->props == NULL)
21
22
if (name == NULL)
23
name = "unknown";
24
25
- if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
26
- card_id = (uint32_t)atoi(str);
27
- if ((str = spa_dict_lookup(info->props, "card.profile.device")) != NULL)
28
- dev_info.device = (uint32_t)atoi(str);
29
- if (card_id != SPA_ID_INVALID) {
30
- struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
31
+ get_device_info(o, &dev_info, is_sink ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT, false);
32
+
33
+ if (dev_info.card_id != SPA_ID_INVALID) {
34
+ struct selector sel = { .id = dev_info.card_id, .type = pw_manager_object_is_card, };
35
card = select_object(manager, &sel);
36
}
37
if (card)
38
collect_card_info(card, &card_info);
39
40
- collect_device_info(o, card, &dev_info, false, &impl->defs);
41
-
42
if (!pw_manager_object_is_virtual(o)) {
43
if (is_sink)
44
flags |= SINK_HARDWARE;
45
pipewire-0.3.76.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.77.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
391
1
2
{
3
uint32_t event = 0, mask = 0, res_index = o->index;
4
5
- if (pw_manager_object_is_sink(o)) {
6
+ pw_log_debug("index:%d id:%d %08lx type:%u", o->index, o->id, o->change_mask, type);
7
+
8
+ if (pw_manager_object_is_sink(o) && o->change_mask & PW_MANAGER_OBJECT_FLAG_SINK) {
9
client_queue_subscribe_event(client,
10
SUBSCRIPTION_MASK_SINK,
11
SUBSCRIPTION_EVENT_SINK | type,
12
res_index);
13
}
14
- if (pw_manager_object_is_source_or_monitor(o)) {
15
+ if (pw_manager_object_is_source_or_monitor(o) && o->change_mask & PW_MANAGER_OBJECT_FLAG_SOURCE) {
16
mask = SUBSCRIPTION_MASK_SOURCE;
17
event = SUBSCRIPTION_EVENT_SOURCE;
18
}
19
20
{
21
struct client *client = data;
22
struct pw_manager *manager = client->manager;
23
+ struct impl *impl = client->impl;
24
const char *str;
25
26
register_object_message_handlers(o);
27
28
}
29
}
30
31
+ update_object_info(manager, o, &impl->defs);
32
+
33
send_object_event(client, o, SUBSCRIPTION_EVENT_NEW);
34
35
+ o->change_mask = 0;
36
+
37
/* Adding sinks etc. may also change defaults */
38
send_default_change_subscribe_event(client, pw_manager_object_is_sink(o), pw_manager_object_is_source_or_monitor(o));
39
}
40
41
static void manager_updated(void *data, struct pw_manager_object *o)
42
{
43
struct client *client = data;
44
+ struct pw_manager *manager = client->manager;
45
+ struct impl *impl = client->impl;
46
+
47
+ update_object_info(manager, o, &impl->defs);
48
49
send_object_event(client, o, SUBSCRIPTION_EVENT_CHANGE);
50
51
+ o->change_mask = 0;
52
+
53
set_temporary_move_target(client, o, SPA_ID_INVALID);
54
55
send_latency_offset_subscribe_event(client, o);
56
57
spa_zero(fix_ss);
58
spa_zero(fix_map);
59
if ((fix_format || fix_rate || fix_channels) && o != NULL) {
60
- struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT);
61
- collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs);
62
+ struct device_info dev_info;
63
+ get_device_info(o, &dev_info, PW_DIRECTION_OUTPUT, is_monitor);
64
fix_ss.format = fix_format ? dev_info.ss.format : 0;
65
fix_ss.rate = fix_rate ? dev_info.ss.rate : 0;
66
fix_ss.channels = fix_channels ? dev_info.ss.channels : 0;
67
68
spa_zero(fix_ss);
69
spa_zero(fix_map);
70
if ((fix_format || fix_rate || fix_channels) && o != NULL) {
71
- struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT);
72
- collect_device_info(o, NULL, &dev_info, is_monitor, &impl->defs);
73
+ struct device_info dev_info;
74
+ get_device_info(o, &dev_info, PW_DIRECTION_INPUT, is_monitor);
75
fix_ss.format = fix_format ? dev_info.ss.format : 0;
76
fix_ss.rate = fix_rate ? dev_info.ss.rate : 0;
77
fix_ss.channels = fix_channels ? dev_info.ss.channels : 0;
78
79
uint32_t index, const char *name, bool sink, bool *is_monitor)
80
{
81
struct selector sel;
82
- bool monitor = false, find_default = false;
83
+ bool monitor = false, find_default = false, allow_monitor = false;
84
struct pw_manager_object *o;
85
86
if (name != NULL) {
87
88
sink = true;
89
find_default = true;
90
monitor = true;
91
+ allow_monitor = true;
92
} else if (spa_streq(name, DEFAULT_SOURCE)) {
93
if (sink)
94
return NULL;
95
find_default = true;
96
+ allow_monitor = true;
97
} else if (spa_streq(name, DEFAULT_SINK)) {
98
if (!sink)
99
return NULL;
100
101
102
if (name != NULL) {
103
if (spa_strendswith(name, ".monitor")) {
104
- name = strndupa(name, strlen(name)-8);
105
- monitor = true;
106
+ if (!sink) {
107
+ name = strndupa(name, strlen(name)-8);
108
+ allow_monitor = true;
109
+ }
110
}
111
} else if (index == SPA_ID_INVALID)
112
return NULL;
113
114
115
o = select_object(client->manager, &sel);
116
if (o != NULL) {
117
- if (!sink && pw_manager_object_is_monitor(o))
118
- monitor = true;
119
+ if (!sink) {
120
+ if (pw_manager_object_is_monitor(o)) {
121
+ if (!allow_monitor)
122
+ return NULL;
123
+ monitor = true;
124
+ }
125
+ else if (!pw_manager_object_is_source(o))
126
+ return NULL;
127
+ } else {
128
+ if (!pw_manager_object_is_sink(o))
129
+ return NULL;
130
+ }
131
}
132
if (is_monitor)
133
*is_monitor = monitor;
134
135
136
static int do_set_volume(struct client *client, uint32_t command, uint32_t tag, struct message *m)
137
{
138
- struct impl *impl = client->impl;
139
struct pw_manager *manager = client->manager;
140
struct pw_node_info *info;
141
- uint32_t index, card_id = SPA_ID_INVALID;
142
- const char *name, *str;
143
+ uint32_t index;
144
+ const char *name;
145
struct volume volume;
146
struct pw_manager_object *o, *card = NULL;
147
int res;
148
149
if (o == NULL || (info = o->info) == NULL || info->props == NULL)
150
return -ENOENT;
151
152
- dev_info = DEVICE_INFO_INIT(direction);
153
-
154
- if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
155
- card_id = (uint32_t)atoi(str);
156
- if ((str = spa_dict_lookup(info->props, "card.profile.device")) != NULL)
157
- dev_info.device = (uint32_t)atoi(str);
158
- if (card_id != SPA_ID_INVALID) {
159
- struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
160
- card = select_object(manager, &sel);
161
- }
162
- collect_device_info(o, card, &dev_info, is_monitor, &impl->defs);
163
+ get_device_info(o, &dev_info, direction, is_monitor);
164
165
if (dev_info.have_volume &&
166
volume_compare(&dev_info.volume_info.volume, &volume) == 0)
167
goto done;
168
169
+ if (dev_info.card_id != SPA_ID_INVALID) {
170
+ struct selector sel = { .id = dev_info.card_id, .type = pw_manager_object_is_card, };
171
+ card = select_object(manager, &sel);
172
+ }
173
if (card != NULL && !is_monitor && dev_info.active_port != SPA_ID_INVALID)
174
res = set_card_volume_mute_delay(card, dev_info.active_port,
175
dev_info.device, &volume, NULL, NULL);
176
177
178
static int do_set_mute(struct client *client, uint32_t command, uint32_t tag, struct message *m)
179
{
180
- struct impl *impl = client->impl;
181
struct pw_manager *manager = client->manager;
182
struct pw_node_info *info;
183
- uint32_t index, card_id = SPA_ID_INVALID;
184
- const char *name, *str;
185
+ uint32_t index;
186
+ const char *name;
187
bool mute;
188
struct pw_manager_object *o, *card = NULL;
189
int res;
190
191
if (o == NULL || (info = o->info) == NULL || info->props == NULL)
192
return -ENOENT;
193
194
- dev_info = DEVICE_INFO_INIT(direction);
195
-
196
- if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
197
- card_id = (uint32_t)atoi(str);
198
- if ((str = spa_dict_lookup(info->props, "card.profile.device")) != NULL)
199
- dev_info.device = (uint32_t)atoi(str);
200
- if (card_id != SPA_ID_INVALID) {
201
- struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
202
- card = select_object(manager, &sel);
203
- }
204
- collect_device_info(o, card, &dev_info, is_monitor, &impl->defs);
205
+ get_device_info(o, &dev_info, direction, is_monitor);
206
207
if (dev_info.have_volume &&
208
dev_info.volume_info.mute == mute)
209
goto done;
210
211
+ if (dev_info.card_id != SPA_ID_INVALID) {
212
+ struct selector sel = { .id = dev_info.card_id, .type = pw_manager_object_is_card, };
213
+ card = select_object(manager, &sel);
214
+ }
215
+
216
if (card != NULL && !is_monitor && dev_info.active_port != SPA_ID_INVALID)
217
res = set_card_volume_mute_delay(card, dev_info.active_port,
218
dev_info.device, NULL, &mute, NULL);
219
220
static bool validate_device_info(struct device_info *dev_info)
221
{
222
return sample_spec_valid(&dev_info->ss) &&
223
- channel_map_valid(&dev_info->map) &&
224
- volume_valid(&dev_info->volume_info.volume);
225
+ channel_map_valid(&dev_info->map) &&
226
+ volume_valid(&dev_info->volume_info.volume);
227
}
228
229
static int fill_sink_info(struct client *client, struct message *m,
230
struct pw_manager_object *o)
231
{
232
- struct impl *impl = client->impl;
233
struct pw_node_info *info = o->info;
234
struct pw_manager *manager = client->manager;
235
const char *name, *desc, *str;
236
char *monitor_name = NULL;
237
uint32_t module_id = SPA_ID_INVALID;
238
- uint32_t card_id = SPA_ID_INVALID;
239
struct pw_manager_object *card = NULL;
240
uint32_t flags;
241
struct card_info card_info = CARD_INFO_INIT;
242
- struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT);
243
+ struct device_info dev_info;
244
size_t size;
245
246
if (!pw_manager_object_is_sink(o) || info == NULL || info->props == NULL)
247
248
if (module_id == SPA_ID_INVALID &&
249
(str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL)
250
module_id = (uint32_t)atoi(str);
251
- if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
252
- card_id = (uint32_t)atoi(str);
253
- if ((str = spa_dict_lookup(info->props, "card.profile.device")) != NULL)
254
- dev_info.device = (uint32_t)atoi(str);
255
- if (card_id != SPA_ID_INVALID) {
256
- struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
257
- card = select_object(manager, &sel);
258
- }
259
- if (card)
260
- collect_card_info(card, &card_info);
261
-
262
- collect_device_info(o, card, &dev_info, false, &impl->defs);
263
264
+ get_device_info(o, &dev_info, PW_DIRECTION_OUTPUT, false);
265
if (!validate_device_info(&dev_info)) {
266
pw_log_warn("%d: sink not ready: sample:%d map:%d volume:%d",
267
o->id, sample_spec_valid(&dev_info.ss),
268
269
return -ENOENT;
270
}
271
272
+
273
+ if (dev_info.card_id != SPA_ID_INVALID) {
274
+ struct selector sel = { .id = dev_info.card_id, .type = pw_manager_object_is_card, };
275
+ card = select_object(manager, &sel);
276
+ }
277
+ if (card)
278
+ collect_card_info(card, &card_info);
279
+
280
flags = SINK_LATENCY | SINK_DYNAMIC_LATENCY | SINK_DECIBEL_VOLUME;
281
if (!pw_manager_object_is_virtual(o))
282
flags |= SINK_HARDWARE;
283
284
static int fill_source_info(struct client *client, struct message *m,
285
struct pw_manager_object *o)
286
{
287
- struct impl *impl = client->impl;
288
struct pw_node_info *info = o->info;
289
struct pw_manager *manager = client->manager;
290
bool is_monitor;
291
292
char *monitor_name = NULL;
293
char *monitor_desc = NULL;
294
uint32_t module_id = SPA_ID_INVALID;
295
- uint32_t card_id = SPA_ID_INVALID;
296
struct pw_manager_object *card = NULL;
297
uint32_t flags;
298
struct card_info card_info = CARD_INFO_INIT;
299
- struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT);
300
+ struct device_info dev_info;
301
size_t size;
302
303
is_monitor = pw_manager_object_is_monitor(o);
304
305
if (module_id == SPA_ID_INVALID &&
306
(str = spa_dict_lookup(info->props, "pulse.module.id")) != NULL)
307
module_id = (uint32_t)atoi(str);
308
- if ((str = spa_dict_lookup(info->props, PW_KEY_DEVICE_ID)) != NULL)
309
- card_id = (uint32_t)atoi(str);
310
- if ((str = spa_dict_lookup(info->props, "card.profile.device")) != NULL)
311
- dev_info.device = (uint32_t)atoi(str);
312
-
313
- if (card_id != SPA_ID_INVALID) {
314
- struct selector sel = { .id = card_id, .type = pw_manager_object_is_card, };
315
- card = select_object(manager, &sel);
316
- }
317
- if (card)
318
- collect_card_info(card, &card_info);
319
-
320
- collect_device_info(o, card, &dev_info, is_monitor, &impl->defs);
321
322
+ get_device_info(o, &dev_info, PW_DIRECTION_INPUT, is_monitor);
323
if (!validate_device_info(&dev_info)) {
324
pw_log_warn("%d: source not ready: sample:%d map:%d volume:%d",
325
o->id, sample_spec_valid(&dev_info.ss),
326
327
}
328
329
flags = SOURCE_LATENCY | SOURCE_DYNAMIC_LATENCY | SOURCE_DECIBEL_VOLUME;
330
+
331
+ if (dev_info.card_id != SPA_ID_INVALID) {
332
+ struct selector sel = { .id = dev_info.card_id, .type = pw_manager_object_is_card, };
333
+ card = select_object(manager, &sel);
334
+ }
335
+ if (card)
336
+ collect_card_info(card, &card_info);
337
+
338
if (!pw_manager_object_is_virtual(o))
339
flags |= SOURCE_HARDWARE;
340
if (pw_manager_object_is_network(o))
341
342
static int fill_sink_input_info(struct client *client, struct message *m,
343
struct pw_manager_object *o)
344
{
345
- struct impl *impl = client->impl;
346
struct pw_node_info *info = o->info;
347
struct pw_manager *manager = client->manager;
348
const char *str;
349
uint32_t module_id = SPA_ID_INVALID, client_id = SPA_ID_INVALID;
350
uint32_t peer_index;
351
- struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_OUTPUT);
352
+ struct device_info dev_info;
353
354
if (!pw_manager_object_is_sink_input(o) || info == NULL || info->props == NULL)
355
return -ENOENT;
356
357
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
358
client_id = (uint32_t)atoi(str);
359
360
- collect_device_info(o, NULL, &dev_info, false, &impl->defs);
361
-
362
+ get_device_info(o, &dev_info, PW_DIRECTION_OUTPUT, false);
363
if (!validate_device_info(&dev_info))
364
return -ENOENT;
365
366
367
static int fill_source_output_info(struct client *client, struct message *m,
368
struct pw_manager_object *o)
369
{
370
- struct impl *impl = client->impl;
371
struct pw_node_info *info = o->info;
372
struct pw_manager *manager = client->manager;
373
const char *str;
374
uint32_t module_id = SPA_ID_INVALID, client_id = SPA_ID_INVALID;
375
uint32_t peer_index;
376
- struct device_info dev_info = DEVICE_INFO_INIT(PW_DIRECTION_INPUT);
377
+ struct device_info dev_info;
378
379
if (!pw_manager_object_is_source_output(o) || info == NULL || info->props == NULL)
380
return -ENOENT;
381
382
(str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID)) != NULL)
383
client_id = (uint32_t)atoi(str);
384
385
- collect_device_info(o, NULL, &dev_info, false, &impl->defs);
386
-
387
+ get_device_info(o, &dev_info, PW_DIRECTION_INPUT, false);
388
if (!validate_device_info(&dev_info))
389
return -ENOENT;
390
391
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint-stream.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint-stream.c
Changed
9
1
2
this->global = pw_global_new (context,
3
PW_TYPE_INTERFACE_EndpointStream,
4
PW_VERSION_ENDPOINT_STREAM,
5
+ PW_ENDPOINT_STREAM_PERM_MASK,
6
properties, endpoint_stream_bind, this);
7
if (!this->global)
8
goto no_mem;
9
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/client-endpoint/endpoint.c
Changed
9
1
2
this->global = pw_global_new (context,
3
PW_TYPE_INTERFACE_Endpoint,
4
PW_VERSION_ENDPOINT,
5
+ PW_ENDPOINT_PERM_MASK,
6
NULL, endpoint_bind, this);
7
if (!this->global)
8
goto no_mem;
9
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/client-session/endpoint-link.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/client-session/endpoint-link.c
Changed
9
1
2
this->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_EndpointLink,
4
PW_VERSION_ENDPOINT_LINK,
5
+ PW_ENDPOINT_LINK_PERM_MASK,
6
properties, endpoint_link_bind, this);
7
if (!this->global)
8
goto no_mem;
9
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/client-session/session.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/client-session/session.c
Changed
9
1
2
this->global = pw_global_new (context,
3
PW_TYPE_INTERFACE_Session,
4
PW_VERSION_SESSION,
5
+ PW_SESSION_PERM_MASK,
6
NULL, session_bind, this);
7
if (!this->global)
8
goto no_mem;
9
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/endpoint-link.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/endpoint-link.c
Changed
9
1
2
impl->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_EndpointLink,
4
PW_VERSION_ENDPOINT_LINK,
5
+ PW_ENDPOINT_LINK_PERM_MASK,
6
properties,
7
global_bind, impl);
8
if (impl->global == NULL) {
9
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/endpoint-stream.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/endpoint-stream.c
Changed
9
1
2
impl->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_EndpointStream,
4
PW_VERSION_ENDPOINT_STREAM,
5
+ PW_ENDPOINT_STREAM_PERM_MASK,
6
properties,
7
global_bind, impl);
8
if (impl->global == NULL) {
9
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/endpoint.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/endpoint.c
Changed
9
1
2
impl->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Endpoint,
4
PW_VERSION_ENDPOINT,
5
+ PW_ENDPOINT_PERM_MASK,
6
properties,
7
global_bind, impl);
8
if (impl->global == NULL) {
9
pipewire-0.3.76.tar.gz/src/modules/module-session-manager/session.c -> pipewire-0.3.77.tar.gz/src/modules/module-session-manager/session.c
Changed
9
1
2
impl->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Session,
4
PW_VERSION_SESSION,
5
+ PW_SESSION_PERM_MASK,
6
properties,
7
global_bind, impl);
8
if (impl->global == NULL) {
9
pipewire-0.3.76.tar.gz/src/modules/module-vban/audio.c -> pipewire-0.3.77.tar.gz/src/modules/module-vban/audio.c
Changed
12
1
2
3
timestamp += tosend;
4
avail -= tosend;
5
- impl->header.n_frames++;
6
+ header.n_frames++;
7
}
8
+ impl->header.n_frames = header.n_frames;
9
spa_ringbuffer_read_update(&impl->ring, timestamp);
10
}
11
12
pipewire-0.3.77.tar.gz/src/modules/module-vban/midi.c
Added
329
1
2
+/* PipeWire */
3
+/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans <wim.taymans@gmail.com> */
4
+/* SPDX-License-Identifier: MIT */
5
+
6
+static void vban_midi_process_playback(void *data)
7
+{
8
+ struct impl *impl = data;
9
+ struct pw_buffer *buf;
10
+ struct spa_data *d;
11
+ uint32_t timestamp, duration, maxsize, read;
12
+ struct spa_pod_builder b;
13
+ struct spa_pod_frame f1;
14
+ void *ptr;
15
+ struct spa_pod *pod;
16
+ struct spa_pod_control *c;
17
+
18
+ if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) {
19
+ pw_log_debug("Out of stream buffers: %m");
20
+ return;
21
+ }
22
+ d = buf->buffer->datas;
23
+
24
+ maxsize = d0.maxsize;
25
+
26
+ /* we always use the graph position to select events */
27
+ if (impl->io_position) {
28
+ duration = impl->io_position->clock.duration;
29
+ timestamp = impl->io_position->clock.position;
30
+ } else {
31
+ duration = 8192;
32
+ timestamp = 0;
33
+ }
34
+
35
+ /* we copy events into the buffer as they are available. */
36
+ spa_pod_builder_init(&b, d0.data, maxsize);
37
+ spa_pod_builder_push_sequence(&b, &f0, 0);
38
+
39
+ while (true) {
40
+ int32_t avail = spa_ringbuffer_get_read_index(&impl->ring, &read);
41
+ if (avail <= 0)
42
+ break;
43
+
44
+ ptr = SPA_PTROFF(impl->buffer, read & BUFFER_MASK2, void);
45
+
46
+ if ((pod = spa_pod_from_data(ptr, avail, 0, avail)) == NULL)
47
+ goto done;
48
+ if (!spa_pod_is_sequence(pod))
49
+ goto done;
50
+
51
+ /* the ringbuffer contains series of sequences, one for each
52
+ * received packet */
53
+ SPA_POD_SEQUENCE_FOREACH((struct spa_pod_sequence*)pod, c) {
54
+#if 0
55
+ /* try to render with given delay */
56
+ uint32_t target = c->offset + impl->target_buffer;
57
+ target = (uint64_t)target * rate / impl->rate;
58
+#else
59
+ uint32_t target = timestamp;
60
+#endif
61
+ if (timestamp != 0) {
62
+ /* skip old packets */
63
+ if (target < timestamp)
64
+ continue;
65
+ /* event for next cycle */
66
+ if (target >= timestamp + duration)
67
+ goto complete;
68
+ } else {
69
+ timestamp = target;
70
+ }
71
+ spa_pod_builder_control(&b, target - timestamp, SPA_CONTROL_Midi);
72
+ spa_pod_builder_bytes(&b,
73
+ SPA_POD_BODY(&c->value),
74
+ SPA_POD_BODY_SIZE(&c->value));
75
+ }
76
+ /* we completed a sequence (one RTP packet), advance ringbuffer
77
+ * and go to the next packet */
78
+ read += SPA_PTRDIFF(c, ptr);
79
+ spa_ringbuffer_read_update(&impl->ring, read);
80
+ }
81
+complete:
82
+ spa_pod_builder_pop(&b, &f0);
83
+
84
+ if (b.state.offset > maxsize) {
85
+ pw_log_warn("overflow buffer %u %u", b.state.offset, maxsize);
86
+ b.state.offset = 0;
87
+ }
88
+ d0.chunk->size = b.state.offset;
89
+ d0.chunk->stride = 1;
90
+ d0.chunk->offset = 0;
91
+done:
92
+ pw_stream_queue_buffer(impl->stream, buf);
93
+}
94
+
95
+static int parse_varlen(uint8_t *p, uint32_t avail, uint32_t *result)
96
+{
97
+ uint32_t value = 0, offs = 0;
98
+ while (offs < avail) {
99
+ uint8_t b = poffs++;
100
+ value = (value << 7) | (b & 0x7f);
101
+ if ((b & 0x80) == 0)
102
+ break;
103
+ }
104
+ *result = value;
105
+ return offs;
106
+}
107
+
108
+static int get_midi_size(uint8_t *p, uint32_t avail)
109
+{
110
+ int size;
111
+ uint32_t offs = 0, value;
112
+
113
+ switch (poffs++) {
114
+ case 0xc0 ... 0xdf:
115
+ size = 2;
116
+ break;
117
+ case 0x80 ... 0xbf:
118
+ case 0xe0 ... 0xef:
119
+ size = 3;
120
+ break;
121
+ case 0xff:
122
+ case 0xf0:
123
+ case 0xf7:
124
+ size = parse_varlen(&poffs, avail - offs, &value);
125
+ size += value + 1;
126
+ break;
127
+ default:
128
+ return -EINVAL;
129
+ }
130
+ return size;
131
+}
132
+
133
+static int vban_midi_receive_midi(struct impl *impl, uint8_t *packet,
134
+ uint32_t payload_offset, uint32_t plen)
135
+{
136
+ uint32_t write;
137
+ int32_t filled;
138
+ struct spa_pod_builder b;
139
+ struct spa_pod_frame f1;
140
+ void *ptr;
141
+ uint32_t offs = payload_offset;
142
+ uint32_t timestamp = 0;
143
+
144
+ /* no sync, resync */
145
+ if (!impl->have_sync) {
146
+ pw_log_info("sync to timestamp:%u", timestamp);
147
+ impl->have_sync = true;
148
+ impl->ring.readindex = impl->ring.writeindex;
149
+ }
150
+
151
+ filled = spa_ringbuffer_get_write_index(&impl->ring, &write);
152
+ if (filled > (int32_t)BUFFER_SIZE2) {
153
+ pw_log_warn("overflow");
154
+ return -ENOSPC;
155
+ }
156
+
157
+ ptr = SPA_PTROFF(impl->buffer, write & BUFFER_MASK2, void);
158
+
159
+ /* each packet is written as a sequence of events. The offset is
160
+ * the receive timestamp */
161
+ spa_pod_builder_init(&b, ptr, BUFFER_SIZE2 - filled);
162
+ spa_pod_builder_push_sequence(&b, &f0, 0);
163
+
164
+ while (offs < plen) {
165
+ int size;
166
+
167
+ spa_pod_builder_control(&b, timestamp, SPA_CONTROL_Midi);
168
+
169
+ size = get_midi_size(&packetoffs, plen - offs);
170
+
171
+ if (size <= 0 || offs + size > plen) {
172
+ pw_log_warn("invalid size (%08x) %d (%u %u)",
173
+ packetoffs, size, offs, plen);
174
+ break;
175
+ }
176
+
177
+ spa_pod_builder_bytes(&b, &packetoffs, size);
178
+
179
+ offs += size;
180
+ }
181
+ spa_pod_builder_pop(&b, &f0);
182
+
183
+ write += b.state.offset;
184
+ spa_ringbuffer_write_update(&impl->ring, write);
185
+
186
+ return 0;
187
+}
188
+
189
+static int vban_midi_receive(struct impl *impl, uint8_t *buffer, ssize_t len)
190
+{
191
+ struct vban_header *hdr;
192
+ ssize_t hlen;
193
+ uint32_t n_frames;
194
+
195
+ if (len < VBAN_HEADER_SIZE)
196
+ goto short_packet;
197
+
198
+ hdr = (struct vban_header*)buffer;
199
+ if (strncmp(hdr->vban, "VBAN", 3))
200
+ goto invalid_version;
201
+
202
+ hlen = VBAN_HEADER_SIZE;
203
+
204
+ n_frames = hdr->n_frames;
205
+ if (impl->have_sync && impl->n_frames != n_frames) {
206
+ pw_log_info("unexpected frame (%d != %d)",
207
+ n_frames, impl->n_frames);
208
+ impl->have_sync = false;
209
+ }
210
+ impl->n_frames = n_frames + 1;
211
+
212
+ impl->receiving = true;
213
+
214
+ return vban_midi_receive_midi(impl, buffer, hlen, len);
215
+
216
+short_packet:
217
+ pw_log_warn("short packet received");
218
+ return -EINVAL;
219
+invalid_version:
220
+ pw_log_warn("invalid RTP version");
221
+ spa_debug_mem(0, buffer, len);
222
+ return -EPROTO;
223
+}
224
+
225
+static void vban_midi_flush_packets(struct impl *impl,
226
+ struct spa_pod_sequence *sequence, uint32_t timestamp, uint32_t rate)
227
+{
228
+ struct spa_pod_control *c;
229
+ struct vban_header header;
230
+ struct iovec iov2;
231
+ uint32_t len;
232
+
233
+ header = impl->header;
234
+
235
+ iov0.iov_base = &header;
236
+ iov0.iov_len = sizeof(header);
237
+ iov1.iov_base = impl->buffer;
238
+ iov1.iov_len = 0;
239
+
240
+ len = 0;
241
+
242
+ SPA_POD_SEQUENCE_FOREACH(sequence, c) {
243
+ void *ev;
244
+ uint32_t size;
245
+
246
+ if (c->type != SPA_CONTROL_Midi)
247
+ continue;
248
+
249
+ ev = SPA_POD_BODY(&c->value),
250
+ size = SPA_POD_BODY_SIZE(&c->value);
251
+ if (len == 0) {
252
+ /* start new packet */
253
+ header.n_frames++;
254
+ } else if (len + size > impl->mtu) {
255
+ /* flush packet when we have one and when it's too large */
256
+ iov1.iov_len = len;
257
+
258
+ pw_log_debug("sending %d", len);
259
+ vban_stream_emit_send_packet(impl, iov, 2);
260
+ len = 0;
261
+ }
262
+ memcpy(&impl->bufferlen, ev, size);
263
+ len += size;
264
+ }
265
+ if (len > 0) {
266
+ /* flush last packet */
267
+ iov1.iov_len = len;
268
+
269
+ pw_log_debug("sending %d", len);
270
+ vban_stream_emit_send_packet(impl, iov, 2);
271
+ }
272
+ impl->header.n_frames = header.n_frames;
273
+}
274
+
275
+static void vban_midi_process_capture(void *data)
276
+{
277
+ struct impl *impl = data;
278
+ struct pw_buffer *buf;
279
+ struct spa_data *d;
280
+ uint32_t offs, size, timestamp, rate;
281
+ struct spa_pod *pod;
282
+ void *ptr;
283
+
284
+ if ((buf = pw_stream_dequeue_buffer(impl->stream)) == NULL) {
285
+ pw_log_debug("Out of stream buffers: %m");
286
+ return;
287
+ }
288
+ d = buf->buffer->datas;
289
+
290
+ offs = SPA_MIN(d0.chunk->offset, d0.maxsize);
291
+ size = SPA_MIN(d0.chunk->size, d0.maxsize - offs);
292
+
293
+ if (SPA_LIKELY(impl->io_position)) {
294
+ rate = impl->io_position->clock.rate.denom;
295
+ timestamp = impl->io_position->clock.position * impl->rate / rate;
296
+ } else {
297
+ rate = 10000;
298
+ timestamp = 0;
299
+ }
300
+
301
+ ptr = SPA_PTROFF(d0.data, offs, void);
302
+
303
+ if ((pod = spa_pod_from_data(ptr, size, 0, size)) == NULL)
304
+ goto done;
305
+ if (!spa_pod_is_sequence(pod))
306
+ goto done;
307
+
308
+ if (!impl->have_sync) {
309
+ pw_log_info("sync to timestamp:%u n_frames:%u",
310
+ timestamp, impl->n_frames);
311
+ impl->have_sync = true;
312
+ }
313
+
314
+ vban_midi_flush_packets(impl, (struct spa_pod_sequence*)pod, timestamp, rate);
315
+
316
+done:
317
+ pw_stream_queue_buffer(impl->stream, buf);
318
+}
319
+
320
+static int vban_midi_init(struct impl *impl, enum spa_direction direction)
321
+{
322
+ if (direction == SPA_DIRECTION_INPUT)
323
+ impl->stream_events.process = vban_midi_process_capture;
324
+ else
325
+ impl->stream_events.process = vban_midi_process_playback;
326
+ impl->receive_vban = vban_midi_receive;
327
+ return 0;
328
+}
329
pipewire-0.3.76.tar.gz/src/modules/module-vban/stream.c -> pipewire-0.3.77.tar.gz/src/modules/module-vban/stream.c
Changed
71
1
2
};
3
4
#include "module-vban/audio.c"
5
-//#include "module-vban/midi.c"
6
+#include "module-vban/midi.c"
7
8
struct format_info {
9
uint32_t media_subtype;
10
11
{ SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_S32_LE, 4, VBAN_DATATYPE_INT32, },
12
{ SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_F32_LE, 4, VBAN_DATATYPE_FLOAT32, },
13
{ SPA_MEDIA_SUBTYPE_raw, SPA_AUDIO_FORMAT_F64_LE, 8, VBAN_DATATYPE_FLOAT64, },
14
- { SPA_MEDIA_SUBTYPE_control, 0, 1, },
15
+ { SPA_MEDIA_SUBTYPE_control, 0, 1, VBAN_SERIAL_MIDI | VBAN_DATATYPE_U8, },
16
};
17
18
static void stream_io_changed(void *data, uint32_t id, void *area, uint32_t size)
19
20
goto out;
21
}
22
memcpy(impl->header.vban, "VBAN", 4);
23
- if ((str = pw_properties_get(props, "sess.name")) == NULL)
24
- str = "Stream1";
25
- strcpy(impl->header.stream_name, str);
26
27
switch (impl->info.media_subtype) {
28
case SPA_MEDIA_SUBTYPE_raw:
29
30
}
31
impl->stride = impl->format_info->size * impl->stream_info.info.raw.channels;
32
impl->rate = impl->stream_info.info.raw.rate;
33
+
34
impl->header.format_SR = vban_sr_index(impl->rate);
35
if (impl->header.format_SR == VBAN_SR_MAXNUMBER) {
36
pw_log_error("unsupported audio rate:%u", impl->rate);
37
38
goto out;
39
}
40
impl->header.format_bit = impl->format_info->format_bit;
41
+ if ((str = pw_properties_get(props, "sess.name")) == NULL)
42
+ str = "Stream1";
43
+ strcpy(impl->header.stream_name, str);
44
break;
45
case SPA_MEDIA_SUBTYPE_control:
46
impl->stream_info = impl->info;
47
48
impl->rate = pw_properties_get_uint32(props, "midi.rate", 10000);
49
if (impl->rate == 0)
50
impl->rate = 10000;
51
+
52
+ impl->header.format_SR = (0x1 << 5) | 14; /* 115200 */
53
+ impl->header.format_nbs = 0;
54
+ impl->header.format_nbc = 0;
55
+ impl->header.format_bit = impl->format_info->format_bit;
56
+ if ((str = pw_properties_get(props, "sess.name")) == NULL)
57
+ str = "Midi1";
58
+ strcpy(impl->header.stream_name, str);
59
break;
60
default:
61
spa_assert_not_reached();
62
63
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
64
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application),
65
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
66
-// vban_midi_init(impl, direction);
67
+ vban_midi_init(impl, direction);
68
break;
69
default:
70
res = -EINVAL;
71
pipewire-0.3.76.tar.gz/src/modules/module-vban/vban.h -> pipewire-0.3.77.tar.gz/src/modules/module-vban/vban.h
Changed
12
1
2
#define VBAN_DATATYPE_12BITS 0x06
3
#define VBAN_DATATYPE_10BITS 0x07
4
5
+#define VBAN_SERIAL_GENERIC 0x00
6
+#define VBAN_SERIAL_MIDI 0x10
7
+#define VBAN_SERIAL_USER 0xf0
8
+
9
#ifdef __cplusplus
10
}
11
#endif
12
pipewire-0.3.76.tar.gz/src/modules/module-x11-bell.c -> pipewire-0.3.77.tar.gz/src/modules/module-x11-bell.c
Changed
28
1
2
PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
3
#define PW_LOG_TOPIC_DEFAULT mod_topic
4
5
+/* libcanberra is not thread safe when doing ca_context_create()
6
+ * and so we need a global lock */
7
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
8
+
9
struct impl {
10
struct pw_context *context;
11
struct pw_thread_loop *thread_loop;
12
13
ca_context *ca;
14
int res;
15
16
+ pthread_mutex_lock(&lock);
17
if (impl->properties)
18
sample = pw_properties_get(impl->properties, "sample.name");
19
if (sample == NULL)
20
21
exit_destroy:
22
ca_context_destroy(ca);
23
exit:
24
+ pthread_mutex_unlock(&lock);
25
return res;
26
}
27
28
pipewire-0.3.76.tar.gz/src/pipewire/client.h -> pipewire-0.3.77.tar.gz/src/pipewire/client.h
Changed
45
1
2
*/
3
#define PW_TYPE_INTERFACE_Client PW_TYPE_INFO_INTERFACE_BASE "Client"
4
5
+#define PW_CLIENT_PERM_MASK PW_PERM_RWXM
6
+
7
#define PW_VERSION_CLIENT 3
8
struct pw_client;
9
10
11
* \param id the global id to report the error on
12
* \param res an errno style error code
13
* \param message an error string
14
+ *
15
+ * This requires W and X permissions on the client.
16
*/
17
int (*error) (void *object, uint32_t id, int res, const char *message);
18
/**
19
* Update client properties
20
*
21
* \param props new properties
22
+ *
23
+ * This requires W and X permissions on the client.
24
*/
25
int (*update_properties) (void *object, const struct spa_dict *props);
26
27
28
*
29
* \param index the first index to query, 0 for first
30
* \param num the maximum number of items to get
31
+ *
32
+ * This requires W and X permissions on the client.
33
*/
34
int (*get_permissions) (void *object, uint32_t index, uint32_t num);
35
/**
36
37
*
38
* \param n_permissions number of permissions
39
* \param permissions array of permissions
40
+ *
41
+ * This requires W and X permissions on the client.
42
*/
43
int (*update_permissions) (void *object, uint32_t n_permissions,
44
const struct pw_permission *permissions);
45
pipewire-0.3.76.tar.gz/src/pipewire/conf.c -> pipewire-0.3.77.tar.gz/src/pipewire/conf.c
Changed
38
1
2
return res == 0 ? data.count : res;
3
}
4
5
+static bool valid_conf_name(const char *str)
6
+{
7
+ return spa_streq(str, "null") || spa_strendswith(str, ".conf");
8
+}
9
+
10
static int try_load_conf(const char *conf_prefix, const char *conf_name,
11
struct pw_properties *conf)
12
{
13
14
conf_name = pw_properties_get(props, PW_KEY_CONFIG_NAME);
15
if (conf_name == NULL)
16
conf_name = "client.conf";
17
+ else if (!valid_conf_name(conf_name)) {
18
+ pw_log_error("%s '%s' does not end with .conf",
19
+ PW_KEY_CONFIG_NAME, conf_name);
20
+ return -EINVAL;
21
+ }
22
if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) {
23
pw_log_error("can't load config %s: %s",
24
conf_name, spa_strerror(res));
25
26
struct pw_properties *override;
27
const char *path, *name;
28
29
+ if (!valid_conf_name(conf_name)) {
30
+ pw_log_error("%s '%s' does not end with .conf",
31
+ PW_KEY_CONFIG_OVERRIDE_NAME, conf_name);
32
+ return -EINVAL;
33
+ }
34
+
35
override = pw_properties_new(NULL, NULL);
36
if (override == NULL) {
37
res = -errno;
38
pipewire-0.3.76.tar.gz/src/pipewire/core.h -> pipewire-0.3.77.tar.gz/src/pipewire/core.h
Changed
87
1
2
#define PW_TYPE_INTERFACE_Core PW_TYPE_INFO_INTERFACE_BASE "Core"
3
#define PW_TYPE_INTERFACE_Registry PW_TYPE_INFO_INTERFACE_BASE "Registry"
4
5
+#define PW_CORE_PERM_MASK PW_PERM_R|PW_PERM_X|PW_PERM_M
6
+
7
#define PW_VERSION_CORE 4
8
struct pw_core;
9
#define PW_VERSION_REGISTRY 3
10
11
* Start a conversation with the server. This will send
12
* the core info and will destroy all resources for the client
13
* (except the core and client resource).
14
+ *
15
+ * This requires X permissions on the core.
16
*/
17
int (*hello) (void *object, uint32_t version);
18
/**
19
20
* methods and the resulting events have been handled.
21
*
22
* \param seq the seq number passed to the done event
23
+ *
24
+ * This requires X permissions on the core.
25
*/
26
int (*sync) (void *object, uint32_t id, int seq);
27
/**
28
29
* Reply to the server ping event with the same seq.
30
*
31
* \param seq the seq number received in the ping event
32
+ *
33
+ * This requires X permissions on the core.
34
*/
35
int (*pong) (void *object, uint32_t id, int seq);
36
/**
37
38
* This method is usually also emitted on the resource object with
39
* \a id.
40
*
41
- * \param id object where the error occurred
42
+ * \param id resource id where the error occurred
43
* \param res error code
44
* \param message error description
45
+ *
46
+ * This requires X permissions on the core.
47
*/
48
int (*error) (void *object, uint32_t id, int seq, int res, const char *message);
49
/**
50
51
* the global objects available from the PipeWire server
52
* \param version the client version
53
* \param user_data_size extra size
54
+ *
55
+ * This requires X permissions on the core.
56
*/
57
struct pw_registry * (*get_registry) (void *object, uint32_t version,
58
size_t user_data_size);
59
60
* \param version the version of the interface
61
* \param props extra properties
62
* \param user_data_size extra size
63
+ *
64
+ * This requires X permissions on the core.
65
*/
66
void * (*create_object) (void *object,
67
const char *factory_name,
68
69
* Destroy the server resource for the given proxy.
70
*
71
* \param obj the proxy to destroy
72
+ *
73
+ * This requires X permissions on the core.
74
*/
75
int (*destroy) (void *object, void *proxy);
76
};
77
78
*
79
* Try to destroy the global object.
80
*
81
- * \param id the global id to destroy
82
+ * \param id the global id to destroy. The client needs X permissions
83
+ * on the global.
84
*/
85
int (*destroy) (void *object, uint32_t id);
86
};
87
pipewire-0.3.76.tar.gz/src/pipewire/device.h -> pipewire-0.3.77.tar.gz/src/pipewire/device.h
Changed
37
1
2
3
#define PW_TYPE_INTERFACE_Device PW_TYPE_INFO_INTERFACE_BASE "Device"
4
5
+#define PW_DEVICE_PERM_MASK PW_PERM_RWXM
6
+
7
#define PW_VERSION_DEVICE 3
8
struct pw_device;
9
10
11
*
12
* \param ids an array of param ids
13
* \param n_ids the number of ids in \a ids
14
+ *
15
+ * This requires X permissions on the device.
16
*/
17
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
18
19
20
* \param start the start index or 0 for the first param
21
* \param num the maximum number of params to retrieve
22
* \param filter a param filter or NULL
23
+ *
24
+ * This requires X permissions on the device.
25
*/
26
int (*enum_params) (void *object, int seq, uint32_t id, uint32_t start, uint32_t num,
27
const struct spa_pod *filter);
28
29
* \param id the parameter id to set
30
* \param flags extra parameter flags
31
* \param param the parameter to set
32
+ *
33
+ * This requires W and X permissions on the device.
34
*/
35
int (*set_param) (void *object, uint32_t id, uint32_t flags,
36
const struct spa_pod *param);
37
pipewire-0.3.76.tar.gz/src/pipewire/extensions/metadata.h -> pipewire-0.3.77.tar.gz/src/pipewire/extensions/metadata.h
Changed
52
1
2
*/
3
#define PW_TYPE_INTERFACE_Metadata PW_TYPE_INFO_INTERFACE_BASE "Metadata"
4
5
+#define PW_METADATA_PERM_MASK PW_PERM_RWX
6
+
7
#define PW_VERSION_METADATA 3
8
struct pw_metadata;
9
10
11
#define PW_METADATA_EVENT_PROPERTY 0
12
#define PW_METADATA_EVENT_NUM 1
13
14
+
15
/** \ref pw_metadata events */
16
struct pw_metadata_events {
17
#define PW_VERSION_METADATA_EVENTS 0
18
19
const struct pw_metadata_events *events,
20
void *data);
21
22
+ /**
23
+ * Set a metadata property
24
+ *
25
+ * Automatically emit property events for the subject and key
26
+ * when they are changed.
27
+ *
28
+ * \param subject the id of the global to associate the metadata
29
+ * with.
30
+ * \param key the key of the metadata, NULL clears all metadata for
31
+ * the subject.
32
+ * \param type the type of the metadata, this can be blank
33
+ * \param value the metadata value. NULL clears the metadata.
34
+ *
35
+ * This requires X and W permissions on the metadata. It also
36
+ * requires M permissions on the subject global.
37
+ */
38
int (*set_property) (void *object,
39
uint32_t subject,
40
const char *key,
41
const char *type,
42
const char *value);
43
44
+ /**
45
+ * Clear all metadata
46
+ *
47
+ * This requires X and W permissions on the metadata.
48
+ */
49
int (*clear) (void *object);
50
};
51
52
pipewire-0.3.76.tar.gz/src/pipewire/extensions/profiler.h -> pipewire-0.3.77.tar.gz/src/pipewire/extensions/profiler.h
Changed
10
1
2
3
#define PW_EXTENSION_MODULE_PROFILER PIPEWIRE_MODULE_PREFIX "module-profiler"
4
5
+#define PW_PROFILER_PERM_MASK PW_PERM_R
6
+
7
#define PW_PROFILER_EVENT_PROFILE 0
8
#define PW_PROFILER_EVENT_NUM 1
9
10
pipewire-0.3.76.tar.gz/src/pipewire/extensions/session-manager/interfaces.h -> pipewire-0.3.77.tar.gz/src/pipewire/extensions/session-manager/interfaces.h
Changed
150
1
2
*/
3
4
#define PW_TYPE_INTERFACE_Session PW_TYPE_INFO_INTERFACE_BASE "Session"
5
+#define PW_SESSION_PERM_MASK PW_PERM_RWX
6
#define PW_VERSION_SESSION 0
7
struct pw_session;
8
9
#define PW_TYPE_INTERFACE_Endpoint PW_TYPE_INFO_INTERFACE_BASE "Endpoint"
10
+#define PW_ENDPOINT_PERM_MASK PW_PERM_RWX
11
#define PW_VERSION_ENDPOINT 0
12
struct pw_endpoint;
13
14
#define PW_TYPE_INTERFACE_EndpointStream PW_TYPE_INFO_INTERFACE_BASE "EndpointStream"
15
+#define PW_ENDPOINT_STREAM_PERM_MASK PW_PERM_RWX
16
#define PW_VERSION_ENDPOINT_STREAM 0
17
struct pw_endpoint_stream;
18
19
#define PW_TYPE_INTERFACE_EndpointLink PW_TYPE_INFO_INTERFACE_BASE "EndpointLink"
20
+#define PW_ENDPOINT_LINK_PERM_MASK PW_PERM_RWX
21
#define PW_VERSION_ENDPOINT_LINK 0
22
struct pw_endpoint_link;
23
24
25
*
26
* \param ids an array of param ids
27
* \param n_ids the number of ids in \a ids
28
+ *
29
+ * This requires X permissions.
30
*/
31
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
32
33
34
* \param start the start index or 0 for the first param
35
* \param num the maximum number of params to retrieve
36
* \param filter a param filter or NULL
37
+ *
38
+ * This requires X permissions.
39
*/
40
int (*enum_params) (void *object, int seq,
41
uint32_t id, uint32_t start, uint32_t num,
42
43
* \param id the parameter id to set
44
* \param flags extra parameter flags
45
* \param param the parameter to set
46
+ *
47
+ * This requires X and W permissions.
48
*/
49
int (*set_param) (void *object, uint32_t id, uint32_t flags,
50
const struct spa_pod *param);
51
52
*
53
* \param ids an array of param ids
54
* \param n_ids the number of ids in \a ids
55
+ *
56
+ * This requires X permissions.
57
*/
58
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
59
60
61
* \param start the start index or 0 for the first param
62
* \param num the maximum number of params to retrieve
63
* \param filter a param filter or NULL
64
+ *
65
+ * This requires X permissions.
66
*/
67
int (*enum_params) (void *object, int seq,
68
uint32_t id, uint32_t start, uint32_t num,
69
70
* \param id the parameter id to set
71
* \param flags extra parameter flags
72
* \param param the parameter to set
73
+ *
74
+ * This requires X and W permissions.
75
*/
76
int (*set_param) (void *object, uint32_t id, uint32_t flags,
77
const struct spa_pod *param);
78
79
+ /**
80
+ * Create a link
81
+ *
82
+ * This requires X permissions.
83
+ */
84
int (*create_link) (void *object, const struct spa_dict *props);
85
};
86
87
88
*
89
* \param ids an array of param ids
90
* \param n_ids the number of ids in \a ids
91
+ *
92
+ * This requires X permissions.
93
*/
94
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
95
96
97
* \param start the start index or 0 for the first param
98
* \param num the maximum number of params to retrieve
99
* \param filter a param filter or NULL
100
+ *
101
+ * This requires X permissions.
102
*/
103
int (*enum_params) (void *object, int seq,
104
uint32_t id, uint32_t start, uint32_t num,
105
106
* \param id the parameter id to set
107
* \param flags extra parameter flags
108
* \param param the parameter to set
109
+ *
110
+ * This requires X and W permissions.
111
*/
112
int (*set_param) (void *object, uint32_t id, uint32_t flags,
113
const struct spa_pod *param);
114
115
*
116
* \param ids an array of param ids
117
* \param n_ids the number of ids in \a ids
118
+ *
119
+ * This requires X permissions.
120
*/
121
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
122
123
124
* \param start the start index or 0 for the first param
125
* \param num the maximum number of params to retrieve
126
* \param filter a param filter or NULL
127
+ *
128
+ * This requires X permissions.
129
*/
130
int (*enum_params) (void *object, int seq,
131
uint32_t id, uint32_t start, uint32_t num,
132
133
* \param id the parameter id to set
134
* \param flags extra parameter flags
135
* \param param the parameter to set
136
+ *
137
+ * This requires X and W permissions.
138
*/
139
int (*set_param) (void *object, uint32_t id, uint32_t flags,
140
const struct spa_pod *param);
141
142
+ /**
143
+ * Request a state on the link.
144
+ *
145
+ * This requires X and W permissions.
146
+ */
147
int (*request_state) (void *object, enum pw_endpoint_link_state state);
148
};
149
150
pipewire-0.3.76.tar.gz/src/pipewire/factory.h -> pipewire-0.3.77.tar.gz/src/pipewire/factory.h
Changed
10
1
2
*/
3
#define PW_TYPE_INTERFACE_Factory PW_TYPE_INFO_INTERFACE_BASE "Factory"
4
5
+#define PW_FACTORY_PERM_MASK PW_PERM_R|PW_PERM_M
6
+
7
#define PW_VERSION_FACTORY 3
8
struct pw_factory;
9
10
pipewire-0.3.76.tar.gz/src/pipewire/global.c -> pipewire-0.3.77.tar.gz/src/pipewire/global.c
Changed
32
1
2
SPA_EXPORT
3
uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_impl_client *client)
4
{
5
- if (client->permission_func == NULL)
6
- return PW_PERM_ALL;
7
-
8
- return client->permission_func(global, client, client->permission_data);
9
+ uint32_t permissions = global->permission_mask;
10
+ if (client->permission_func != NULL)
11
+ permissions &= client->permission_func(global, client, client->permission_data);
12
+ return permissions;
13
}
14
15
/** Create a new global
16
17
pw_global_new(struct pw_context *context,
18
const char *type,
19
uint32_t version,
20
+ uint32_t permission_mask,
21
struct pw_properties *properties,
22
pw_global_bind_func_t func,
23
void *object)
24
25
this->context = context;
26
this->type = type;
27
this->version = version;
28
+ this->permission_mask = permission_mask;
29
this->func = func;
30
this->object = object;
31
this->properties = properties;
32
pipewire-0.3.76.tar.gz/src/pipewire/global.h -> pipewire-0.3.77.tar.gz/src/pipewire/global.h
Changed
9
1
2
pw_global_new(struct pw_context *context, /**< the context */
3
const char *type, /**< the interface type of the global */
4
uint32_t version, /**< the interface version of the global */
5
+ uint32_t permission_mask, /**< mask of valid permissions */
6
struct pw_properties *properties, /**< extra properties */
7
pw_global_bind_func_t func, /**< function to bind */
8
void *object /**< global object */);
9
pipewire-0.3.76.tar.gz/src/pipewire/impl-client.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-client.c
Changed
9
1
2
client->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Client,
4
PW_VERSION_CLIENT,
5
+ PW_CLIENT_PERM_MASK,
6
properties,
7
global_bind,
8
client);
9
pipewire-0.3.76.tar.gz/src/pipewire/impl-core.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-core.c
Changed
9
1
2
core->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Core,
4
PW_VERSION_CORE,
5
+ PW_CORE_PERM_MASK,
6
properties,
7
global_bind,
8
core);
9
pipewire-0.3.76.tar.gz/src/pipewire/impl-device.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-device.c
Changed
9
1
2
device->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Device,
4
PW_VERSION_DEVICE,
5
+ PW_DEVICE_PERM_MASK,
6
properties,
7
global_bind,
8
device);
9
pipewire-0.3.76.tar.gz/src/pipewire/impl-factory.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-factory.c
Changed
9
1
2
factory->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Factory,
4
PW_VERSION_FACTORY,
5
+ PW_FACTORY_PERM_MASK,
6
properties,
7
global_bind,
8
factory);
9
pipewire-0.3.76.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-link.c
Changed
73
1
2
}
3
4
static int check_owner_permissions(struct pw_context *context,
5
- struct pw_impl_node *node, uint32_t id, uint32_t permissions)
6
+ struct pw_impl_node *node, struct pw_global *other, uint32_t permissions)
7
{
8
const char *str;
9
struct pw_impl_client *client;
10
11
/* not the right object, something wrong */
12
return -EIO;
13
14
- if ((global = pw_context_find_global(context, id)) == NULL)
15
- /* current client can't see node id */
16
- return -errno;
17
-
18
- perms = pw_global_get_permissions(global, client);
19
+ perms = pw_global_get_permissions(other, client);
20
if ((perms & permissions) != permissions)
21
/* owner client can't see other node */
22
return -EPERM;
23
24
struct pw_properties *properties)
25
{
26
int res;
27
+ uint32_t in_perms, out_perms;
28
+ struct pw_global *in_global, *out_global;
29
+
30
+ if ((in_global = input->node->global) == NULL)
31
+ return -ENOENT;
32
+ if ((out_global = output->node->global) == NULL)
33
+ return -ENOENT;
34
+
35
+ in_perms = out_perms = PW_PERM_R | PW_PERM_L;
36
+ if (context->current_client != NULL) {
37
+ in_perms = pw_global_get_permissions(in_global, context->current_client);
38
+ out_perms = pw_global_get_permissions(out_global, context->current_client);
39
+ }
40
+ /* current client can't see input node or output node */
41
+ if (!PW_PERM_IS_R(in_perms) || !PW_PERM_IS_R(out_perms))
42
+ return -ENOENT;
43
+
44
if ((res = check_owner_permissions(context, output->node,
45
- input->node->info.id, PW_PERM_R)) < 0)
46
- return res;
47
+ in_global, PW_PERM_R)) < 0) {
48
+ /* output node owner can't see input node, check if the current
49
+ * client has universal link permissions for the output node */
50
+ if (!PW_PERM_IS_L(out_perms))
51
+ return res;
52
+ }
53
if ((res = check_owner_permissions(context, input->node,
54
- output->node->info.id, PW_PERM_R)) < 0)
55
- return res;
56
+ out_global, PW_PERM_R)) < 0) {
57
+ /* input node owner can't see output node, check if the current
58
+ * client has universal link permissions for the input node */
59
+ if (!PW_PERM_IS_L(in_perms))
60
+ return res;
61
+ }
62
return 0;
63
}
64
65
66
link->global = pw_global_new(context,
67
PW_TYPE_INTERFACE_Link,
68
PW_VERSION_LINK,
69
+ PW_LINK_PERM_MASK,
70
properties,
71
global_bind,
72
link);
73
pipewire-0.3.76.tar.gz/src/pipewire/impl-metadata.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-metadata.c
Changed
9
1
2
metadata->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Metadata,
4
PW_VERSION_METADATA,
5
+ PW_METADATA_PERM_MASK,
6
properties,
7
global_bind,
8
metadata);
9
pipewire-0.3.76.tar.gz/src/pipewire/impl-module.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-module.c
Changed
9
1
2
this->global = pw_global_new(context,
3
PW_TYPE_INTERFACE_Module,
4
PW_VERSION_MODULE,
5
+ PW_MODULE_PERM_MASK,
6
NULL,
7
global_bind,
8
this);
9
pipewire-0.3.76.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-node.c
Changed
17
1
2
PW_KEY_MODULE_ID,
3
PW_KEY_FACTORY_ID,
4
PW_KEY_CLIENT_ID,
5
+ PW_KEY_CLIENT_API,
6
PW_KEY_DEVICE_ID,
7
PW_KEY_PRIORITY_SESSION,
8
PW_KEY_PRIORITY_DRIVER,
9
10
this->global = pw_global_new(context,
11
PW_TYPE_INTERFACE_Node,
12
PW_VERSION_NODE,
13
+ PW_NODE_PERM_MASK,
14
properties,
15
global_bind,
16
this);
17
pipewire-0.3.76.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.77.tar.gz/src/pipewire/impl-port.c
Changed
9
1
2
port->global = pw_global_new(node->context,
3
PW_TYPE_INTERFACE_Port,
4
PW_VERSION_PORT,
5
+ PW_PORT_PERM_MASK,
6
properties,
7
global_bind,
8
port);
9
pipewire-0.3.76.tar.gz/src/pipewire/link.h -> pipewire-0.3.77.tar.gz/src/pipewire/link.h
Changed
10
1
2
3
#define PW_TYPE_INTERFACE_Link PW_TYPE_INFO_INTERFACE_BASE "Link"
4
5
+#define PW_LINK_PERM_MASK PW_PERM_R | PW_PERM_X
6
+
7
#define PW_VERSION_LINK 3
8
struct pw_link;
9
10
pipewire-0.3.76.tar.gz/src/pipewire/module.h -> pipewire-0.3.77.tar.gz/src/pipewire/module.h
Changed
10
1
2
*/
3
#define PW_TYPE_INTERFACE_Module PW_TYPE_INFO_INTERFACE_BASE "Module"
4
5
+#define PW_MODULE_PERM_MASK PW_PERM_R|PW_PERM_M
6
+
7
#define PW_VERSION_MODULE 3
8
struct pw_module;
9
10
pipewire-0.3.76.tar.gz/src/pipewire/node.h -> pipewire-0.3.77.tar.gz/src/pipewire/node.h
Changed
46
1
2
*/
3
#define PW_TYPE_INTERFACE_Node PW_TYPE_INFO_INTERFACE_BASE "Node"
4
5
+#define PW_NODE_PERM_MASK PW_PERM_RWXML
6
+
7
#define PW_VERSION_NODE 3
8
struct pw_node;
9
10
11
*
12
* \param ids an array of param ids
13
* \param n_ids the number of ids in \a ids
14
+ *
15
+ * This requires X permissions on the node.
16
*/
17
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
18
19
20
* \param start the start index or 0 for the first param
21
* \param num the maximum number of params to retrieve
22
* \param filter a param filter or NULL
23
+ *
24
+ * This requires X permissions on the node.
25
*/
26
int (*enum_params) (void *object, int seq, uint32_t id,
27
uint32_t start, uint32_t num,
28
29
* \param id the parameter id to set
30
* \param flags extra parameter flags
31
* \param param the parameter to set
32
+ *
33
+ * This requires X and W permissions on the node.
34
*/
35
int (*set_param) (void *object, uint32_t id, uint32_t flags,
36
const struct spa_pod *param);
37
38
* Send a command to the node
39
*
40
* \param command the command to send
41
+ *
42
+ * This requires X and W permissions on the node.
43
*/
44
int (*send_command) (void *object, const struct spa_command *command);
45
};
46
pipewire-0.3.76.tar.gz/src/pipewire/permission.h -> pipewire-0.3.77.tar.gz/src/pipewire/permission.h
Changed
38
1
2
#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be
3
* present in order to call methods that modify the object. */
4
#define PW_PERM_M 0010 /**< metadata can be set on object, Since 0.3.9 */
5
+#define PW_PERM_L 0020 /**< a link can be made between a node that doesn't have
6
+ * permission to see the other node, Since 0.3.77 */
7
8
-#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X)
9
+#define PW_PERM_RW (PW_PERM_R|PW_PERM_W)
10
+#define PW_PERM_RWX (PW_PERM_RW|PW_PERM_X)
11
#define PW_PERM_RWXM (PW_PERM_RWX|PW_PERM_M)
12
+#define PW_PERM_RWXML (PW_PERM_RWXM|PW_PERM_L)
13
14
#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R)
15
#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W)
16
#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X)
17
#define PW_PERM_IS_M(p) (((p)&PW_PERM_M) == PW_PERM_M)
18
+#define PW_PERM_IS_L(p) (((p)&PW_PERM_L) == PW_PERM_L)
19
20
#define PW_PERM_ALL PW_PERM_RWXM
21
#define PW_PERM_INVALID (uint32_t)(0xffffffff)
22
23
24
#define PW_PERMISSION_INIT(id,p) ((struct pw_permission){ (id), (p) })
25
26
-#define PW_PERMISSION_FORMAT "%c%c%c%c"
27
+#define PW_PERMISSION_FORMAT "%c%c%c%c%c"
28
#define PW_PERMISSION_ARGS(permission) \
29
(permission) & PW_PERM_R ? 'r' : '-', \
30
(permission) & PW_PERM_W ? 'w' : '-', \
31
(permission) & PW_PERM_X ? 'x' : '-', \
32
- (permission) & PW_PERM_M ? 'm' : '-'
33
+ (permission) & PW_PERM_M ? 'm' : '-', \
34
+ (permission) & PW_PERM_L ? 'l' : '-'
35
36
/**
37
* \}
38
pipewire-0.3.76.tar.gz/src/pipewire/port.h -> pipewire-0.3.77.tar.gz/src/pipewire/port.h
Changed
28
1
2
3
#define PW_TYPE_INTERFACE_Port PW_TYPE_INFO_INTERFACE_BASE "Port"
4
5
+#define PW_PORT_PERM_MASK PW_PERM_R|PW_PERM_X|PW_PERM_M
6
+
7
#define PW_VERSION_PORT 3
8
struct pw_port;
9
10
11
*
12
* \param ids an array of param ids
13
* \param n_ids the number of ids in \a ids
14
+ *
15
+ * This requires X permissions on the port.
16
*/
17
int (*subscribe_params) (void *object, uint32_t *ids, uint32_t n_ids);
18
19
20
* \param start the start index or 0 for the first param
21
* \param num the maximum number of params to retrieve
22
* \param filter a param filter or NULL
23
+ *
24
+ * This requires X permissions on the port.
25
*/
26
int (*enum_params) (void *object, int seq,
27
uint32_t id, uint32_t start, uint32_t num,
28
pipewire-0.3.76.tar.gz/src/pipewire/private.h -> pipewire-0.3.77.tar.gz/src/pipewire/private.h
Changed
9
1
2
3
const char *type; /**< type of interface */
4
uint32_t version; /**< version of interface */
5
+ uint32_t permission_mask; /**< possible permissions */
6
7
pw_global_bind_func_t func; /**< bind function */
8
void *object; /**< object associated with the interface */
9
pipewire-0.3.76.tar.gz/src/tools/pw-dump.c -> pipewire-0.3.77.tar.gz/src/tools/pw-dump.c
Changed
9
1
2
{ "w", PW_PERM_W },
3
{ "x", PW_PERM_X },
4
{ "m", PW_PERM_M },
5
+ { "l", PW_PERM_L },
6
{ NULL, },
7
};
8
9
Refresh
No build results available
Refresh
No rpmlint results available
Login required, please
login
or
signup
in order to comment
Request History
zaitor created request over 1 year ago
New upstream release
zaitor accepted request over 1 year ago
Xin