]> code.delx.au - pulseaudio/blob - src/modules/reserve-monitor.c
Fix up according to Coding Style
[pulseaudio] / src / modules / reserve-monitor.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: t -*-*/
2
3 /***
4 Copyright 2009 Lennart Poettering
5
6 Permission is hereby granted, free of charge, to any person
7 obtaining a copy of this software and associated documentation files
8 (the "Software"), to deal in the Software without restriction,
9 including without limitation the rights to use, copy, modify, merge,
10 publish, distribute, sublicense, and/or sell copies of the Software,
11 and to permit persons to whom the Software is furnished to do so,
12 subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 ***/
26
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <assert.h>
33
34 #include "reserve-monitor.h"
35
36 struct rm_monitor {
37 int ref;
38
39 char *device_name;
40 char *service_name;
41 char *match;
42
43 DBusConnection *connection;
44
45 unsigned busy:1;
46 unsigned filtering:1;
47 unsigned matching:1;
48
49 rm_change_cb_t change_cb;
50 void *userdata;
51 };
52
53 #define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
54
55 #define SERVICE_FILTER \
56 "type='signal'," \
57 "sender='" DBUS_SERVICE_DBUS "'," \
58 "interface='" DBUS_INTERFACE_DBUS "'," \
59 "member='NameOwnerChanged'," \
60 "arg0='%s'"
61
62 static DBusHandlerResult filter_handler(
63 DBusConnection *c,
64 DBusMessage *s,
65 void *userdata) {
66
67 rm_monitor *m;
68 DBusError error;
69
70 dbus_error_init(&error);
71
72 m = userdata;
73 assert(m->ref >= 1);
74
75 if (dbus_message_is_signal(s, "org.freedesktop.DBus", "NameOwnerChanged")) {
76 const char *name, *old, *new;
77
78 if (!dbus_message_get_args(
79 s,
80 &error,
81 DBUS_TYPE_STRING, &name,
82 DBUS_TYPE_STRING, &old,
83 DBUS_TYPE_STRING, &new,
84 DBUS_TYPE_INVALID))
85 goto invalid;
86
87 if (strcmp(name, m->service_name) == 0) {
88 m->busy = !!(new && *new);
89
90 /* If we ourselves own the device, then don't consider this 'busy' */
91 if (m->busy) {
92 const char *un;
93
94 if ((un = dbus_bus_get_unique_name(c)))
95 if (strcmp(new, un) == 0)
96 m->busy = FALSE;
97 }
98
99 if (m->change_cb) {
100 m->ref++;
101 m->change_cb(m);
102 rm_release(m);
103 }
104 }
105 }
106
107 invalid:
108 dbus_error_free(&error);
109
110 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
111 }
112
113 int rm_watch(
114 rm_monitor **_m,
115 DBusConnection *connection,
116 const char*device_name,
117 rm_change_cb_t change_cb,
118 DBusError *error) {
119
120 rm_monitor *m = NULL;
121 int r;
122 DBusError _error;
123
124 if (!error)
125 error = &_error;
126
127 dbus_error_init(error);
128
129 if (!_m)
130 return -EINVAL;
131
132 if (!connection)
133 return -EINVAL;
134
135 if (!device_name)
136 return -EINVAL;
137
138 if (!(m = calloc(sizeof(rm_monitor), 1)))
139 return -ENOMEM;
140
141 m->ref = 1;
142
143 if (!(m->device_name = strdup(device_name))) {
144 r = -ENOMEM;
145 goto fail;
146 }
147
148 m->connection = dbus_connection_ref(connection);
149 m->change_cb = change_cb;
150
151 if (!(m->service_name = malloc(sizeof(SERVICE_PREFIX) + strlen(device_name)))) {
152 r = -ENOMEM;
153 goto fail;
154 }
155 sprintf(m->service_name, SERVICE_PREFIX "%s", m->device_name);
156
157 if (!(dbus_connection_add_filter(m->connection, filter_handler, m, NULL))) {
158 r = -ENOMEM;
159 goto fail;
160 }
161
162 m->filtering = 1;
163
164 if (!(m->match = malloc(sizeof(SERVICE_FILTER) - 2 + strlen(m->service_name)))) {
165 r = -ENOMEM;
166 goto fail;
167 }
168
169 sprintf(m->match, SERVICE_FILTER, m->service_name);
170 dbus_bus_add_match(m->connection, m->match, error);
171
172 if (dbus_error_is_set(error)) {
173 r = -EIO;
174 goto fail;
175 }
176
177 m->matching = 1;
178
179 m->busy = dbus_bus_name_has_owner(m->connection, m->service_name, error);
180
181 if (dbus_error_is_set(error)) {
182 r = -EIO;
183 goto fail;
184 }
185
186 *_m = m;
187 return 0;
188
189 fail:
190 if (&_error == error)
191 dbus_error_free(&_error);
192
193 if (m)
194 rm_release(m);
195
196 return r;
197 }
198
199 void rm_release(rm_monitor *m) {
200 if (!m)
201 return;
202
203 assert(m->ref > 0);
204
205 if (--m->ref > 0)
206 return;
207
208 if (m->matching)
209 dbus_bus_remove_match(
210 m->connection,
211 m->match,
212 NULL);
213
214 if (m->filtering)
215 dbus_connection_remove_filter(
216 m->connection,
217 filter_handler,
218 m);
219
220 free(m->device_name);
221 free(m->service_name);
222 free(m->match);
223
224 if (m->connection)
225 dbus_connection_unref(m->connection);
226
227 free(m);
228 }
229
230 int rm_busy(rm_monitor *m) {
231 if (!m)
232 return -EINVAL;
233
234 assert(m->ref > 0);
235
236 return m->busy;
237 }
238
239 void rm_set_userdata(rm_monitor *m, void *userdata) {
240
241 if (!m)
242 return;
243
244 assert(m->ref > 0);
245 m->userdata = userdata;
246 }
247
248 void* rm_get_userdata(rm_monitor *m) {
249
250 if (!m)
251 return NULL;
252
253 assert(m->ref > 0);
254
255 return m->userdata;
256 }