~diwic/ubuntu/lucid/pulseaudio/bugfixes

« back to all changes in this revision

Viewing changes to src/modules/reserve-monitor.c

  • Committer: Bazaar Package Importer
  • Author(s): Sjoerd Simons
  • Date: 2009-07-28 14:00:27 UTC
  • mfrom: (1.5.1 upstream)
  • mto: (1.4.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 65.
  • Revision ID: james.westby@ubuntu.com-20090728140027-wts8ya37tyrh4ww5
Tags: upstream-0.9.16~test2~20090726git59659e1db
ImportĀ upstreamĀ versionĀ 0.9.16~test2~20090726git59659e1db

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
42
        DBusConnection *connection;
 
43
 
 
44
        unsigned busy:1;
 
45
        unsigned filtering:1;
 
46
        unsigned matching:1;
 
47
 
 
48
        rm_change_cb_t change_cb;
 
49
        void *userdata;
 
50
};
 
51
 
 
52
#define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
 
53
 
 
54
static DBusHandlerResult filter_handler(
 
55
        DBusConnection *c,
 
56
        DBusMessage *s,
 
57
        void *userdata) {
 
58
 
 
59
        DBusMessage *reply;
 
60
        rm_monitor *m;
 
61
        DBusError error;
 
62
 
 
63
        dbus_error_init(&error);
 
64
 
 
65
        m = userdata;
 
66
        assert(m->ref >= 1);
 
67
 
 
68
        if (dbus_message_is_signal(s, "org.freedesktop.DBus", "NameOwnerChanged")) {
 
69
                const char *name, *old, *new;
 
70
 
 
71
                if (!dbus_message_get_args(
 
72
                            s,
 
73
                            &error,
 
74
                            DBUS_TYPE_STRING, &name,
 
75
                            DBUS_TYPE_STRING, &old,
 
76
                            DBUS_TYPE_STRING, &new,
 
77
                            DBUS_TYPE_INVALID))
 
78
                        goto invalid;
 
79
 
 
80
                if (strcmp(name, m->service_name) == 0) {
 
81
                        m->busy = !!(new && *new);
 
82
 
 
83
                        /* If we ourselves own the device, then don't consider this 'busy' */
 
84
                        if (m->busy) {
 
85
                                const char *un;
 
86
 
 
87
                                if ((un = dbus_bus_get_unique_name(c)))
 
88
                                        if (strcmp(new, un) == 0)
 
89
                                                m->busy = FALSE;
 
90
                        }
 
91
 
 
92
                        if (m->change_cb) {
 
93
                                m->ref++;
 
94
                                m->change_cb(m);
 
95
                                rm_release(m);
 
96
                        }
 
97
                }
 
98
        }
 
99
 
 
100
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
101
 
 
102
invalid:
 
103
        if (!(reply = dbus_message_new_error(
 
104
                      s,
 
105
                      DBUS_ERROR_INVALID_ARGS,
 
106
                      "Invalid arguments")))
 
107
                goto oom;
 
108
 
 
109
        if (!dbus_connection_send(c, reply, NULL))
 
110
                goto oom;
 
111
 
 
112
        dbus_message_unref(reply);
 
113
 
 
114
        dbus_error_free(&error);
 
115
 
 
116
        return DBUS_HANDLER_RESULT_HANDLED;
 
117
 
 
118
oom:
 
119
        if (reply)
 
120
                dbus_message_unref(reply);
 
121
 
 
122
        dbus_error_free(&error);
 
123
 
 
124
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
125
}
 
126
 
 
127
int rm_watch(
 
128
        rm_monitor **_m,
 
129
        DBusConnection *connection,
 
130
        const char*device_name,
 
131
        rm_change_cb_t change_cb,
 
132
        DBusError *error)  {
 
133
 
 
134
        rm_monitor *m = NULL;
 
135
        int r;
 
136
        DBusError _error;
 
137
 
 
138
        if (!error)
 
139
                error = &_error;
 
140
 
 
141
        dbus_error_init(error);
 
142
 
 
143
        if (!_m)
 
144
                return -EINVAL;
 
145
 
 
146
        if (!connection)
 
147
                return -EINVAL;
 
148
 
 
149
        if (!device_name)
 
150
                return -EINVAL;
 
151
 
 
152
        if (!(m = calloc(sizeof(rm_monitor), 1)))
 
153
                return -ENOMEM;
 
154
 
 
155
        m->ref = 1;
 
156
 
 
157
        if (!(m->device_name = strdup(device_name))) {
 
158
                r = -ENOMEM;
 
159
                goto fail;
 
160
        }
 
161
 
 
162
        m->connection = dbus_connection_ref(connection);
 
163
        m->change_cb = change_cb;
 
164
 
 
165
        if (!(m->service_name = malloc(sizeof(SERVICE_PREFIX) + strlen(device_name)))) {
 
166
                r = -ENOMEM;
 
167
                goto fail;
 
168
        }
 
169
        sprintf(m->service_name, SERVICE_PREFIX "%s", m->device_name);
 
170
 
 
171
        if (!(dbus_connection_add_filter(m->connection, filter_handler, m, NULL))) {
 
172
                r = -ENOMEM;
 
173
                goto fail;
 
174
        }
 
175
 
 
176
        m->filtering = 1;
 
177
 
 
178
        dbus_bus_add_match(m->connection,
 
179
                           "type='signal',"
 
180
                           "sender='" DBUS_SERVICE_DBUS "',"
 
181
                           "interface='" DBUS_INTERFACE_DBUS "',"
 
182
                           "member='NameOwnerChanged'", error);
 
183
 
 
184
        if (dbus_error_is_set(error)) {
 
185
                r = -EIO;
 
186
                goto fail;
 
187
        }
 
188
 
 
189
        m->matching = 1;
 
190
 
 
191
        m->busy = dbus_bus_name_has_owner(m->connection, m->service_name, error);
 
192
 
 
193
        if (dbus_error_is_set(error)) {
 
194
                r = -EIO;
 
195
                goto fail;
 
196
        }
 
197
 
 
198
        *_m = m;
 
199
        return 0;
 
200
 
 
201
fail:
 
202
        if (&_error == error)
 
203
                dbus_error_free(&_error);
 
204
 
 
205
        if (m)
 
206
                rm_release(m);
 
207
 
 
208
        return r;
 
209
}
 
210
 
 
211
void rm_release(rm_monitor *m) {
 
212
        if (!m)
 
213
                return;
 
214
 
 
215
        assert(m->ref > 0);
 
216
 
 
217
        if (--m->ref > 0)
 
218
                return;
 
219
 
 
220
        if (m->matching)
 
221
                dbus_bus_remove_match(
 
222
                        m->connection,
 
223
                        "type='signal',"
 
224
                        "sender='" DBUS_SERVICE_DBUS "',"
 
225
                        "interface='" DBUS_INTERFACE_DBUS "',"
 
226
                        "member='NameOwnerChanged'", NULL);
 
227
 
 
228
        if (m->filtering)
 
229
                dbus_connection_remove_filter(
 
230
                        m->connection,
 
231
                        filter_handler,
 
232
                        m);
 
233
 
 
234
        free(m->device_name);
 
235
        free(m->service_name);
 
236
 
 
237
        if (m->connection)
 
238
                dbus_connection_unref(m->connection);
 
239
 
 
240
        free(m);
 
241
}
 
242
 
 
243
int rm_busy(rm_monitor *m) {
 
244
        if (!m)
 
245
                return -EINVAL;
 
246
 
 
247
        assert(m->ref > 0);
 
248
 
 
249
        return m->busy;
 
250
}
 
251
 
 
252
void rm_set_userdata(rm_monitor *m, void *userdata) {
 
253
 
 
254
        if (!m)
 
255
                return;
 
256
 
 
257
        assert(m->ref > 0);
 
258
        m->userdata = userdata;
 
259
}
 
260
 
 
261
void* rm_get_userdata(rm_monitor *m) {
 
262
 
 
263
        if (!m)
 
264
                return NULL;
 
265
 
 
266
        assert(m->ref > 0);
 
267
 
 
268
        return m->userdata;
 
269
}