]> code.delx.au - pulseaudio/blob - src/polypcore/core-subscribe.c
unhide padsp
[pulseaudio] / src / polypcore / core-subscribe.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <assert.h>
28
29 #include <polyp/xmalloc.h>
30
31 #include <polypcore/queue.h>
32 #include <polypcore/log.h>
33
34 #include "core-subscribe.h"
35
36 /* The subscription subsystem may be used to be notified whenever an
37 * entity (sink, source, ...) is created or deleted. Modules may
38 * register a callback function that is called whenever an event
39 * matching a subscription mask happens. The execution of the callback
40 * function is postponed to the next main loop iteration, i.e. is not
41 * called from within the stack frame the entity was created in. */
42
43 struct pa_subscription {
44 pa_core *core;
45 int dead;
46 void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata);
47 void *userdata;
48 pa_subscription_mask_t mask;
49
50 pa_subscription *prev, *next;
51 };
52
53 struct pa_subscription_event {
54 pa_subscription_event_type_t type;
55 uint32_t index;
56 };
57
58 static void sched_event(pa_core *c);
59
60 /* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */
61 pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) {
62 pa_subscription *s;
63 assert(c);
64
65 s = pa_xmalloc(sizeof(pa_subscription));
66 s->core = c;
67 s->dead = 0;
68 s->callback = callback;
69 s->userdata = userdata;
70 s->mask = m;
71
72 if ((s->next = c->subscriptions))
73 s->next->prev = s;
74 s->prev = NULL;
75 c->subscriptions = s;
76 return s;
77 }
78
79 /* Free a subscription object, effectively marking it for deletion */
80 void pa_subscription_free(pa_subscription*s) {
81 assert(s && !s->dead);
82 s->dead = 1;
83 sched_event(s->core);
84 }
85
86 static void free_item(pa_subscription *s) {
87 assert(s && s->core);
88
89 if (s->prev)
90 s->prev->next = s->next;
91 else
92 s->core->subscriptions = s->next;
93
94 if (s->next)
95 s->next->prev = s->prev;
96
97 pa_xfree(s);
98 }
99
100 /* Free all subscription objects */
101 void pa_subscription_free_all(pa_core *c) {
102 pa_subscription_event *e;
103 assert(c);
104
105 while (c->subscriptions)
106 free_item(c->subscriptions);
107
108 if (c->subscription_event_queue) {
109 while ((e = pa_queue_pop(c->subscription_event_queue)))
110 pa_xfree(e);
111
112 pa_queue_free(c->subscription_event_queue, NULL, NULL);
113 c->subscription_event_queue = NULL;
114 }
115
116 if (c->subscription_defer_event) {
117 c->mainloop->defer_free(c->subscription_defer_event);
118 c->subscription_defer_event = NULL;
119 }
120 }
121
122 #if 0
123 static void dump_event(pa_subscription_event*e) {
124 switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
125 case PA_SUBSCRIPTION_EVENT_SINK:
126 pa_log(__FILE__": SINK_EVENT");
127 break;
128 case PA_SUBSCRIPTION_EVENT_SOURCE:
129 pa_log(__FILE__": SOURCE_EVENT");
130 break;
131 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
132 pa_log(__FILE__": SINK_INPUT_EVENT");
133 break;
134 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
135 pa_log(__FILE__": SOURCE_OUTPUT_EVENT");
136 break;
137 case PA_SUBSCRIPTION_EVENT_MODULE:
138 pa_log(__FILE__": MODULE_EVENT");
139 break;
140 case PA_SUBSCRIPTION_EVENT_CLIENT:
141 pa_log(__FILE__": CLIENT_EVENT");
142 break;
143 default:
144 pa_log(__FILE__": OTHER");
145 break;
146 }
147
148 switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
149 case PA_SUBSCRIPTION_EVENT_NEW:
150 pa_log(__FILE__": NEW");
151 break;
152 case PA_SUBSCRIPTION_EVENT_CHANGE:
153 pa_log(__FILE__": CHANGE");
154 break;
155 case PA_SUBSCRIPTION_EVENT_REMOVE:
156 pa_log(__FILE__": REMOVE");
157 break;
158 default:
159 pa_log(__FILE__": OTHER");
160 break;
161 }
162
163 pa_log(__FILE__": %u", e->index);
164 }
165 #endif
166
167 /* Deferred callback for dispatching subscirption events */
168 static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) {
169 pa_core *c = userdata;
170 pa_subscription *s;
171 assert(c && c->subscription_defer_event == de && c->mainloop == m);
172
173 c->mainloop->defer_enable(c->subscription_defer_event, 0);
174
175 /* Dispatch queued events */
176
177 if (c->subscription_event_queue) {
178 pa_subscription_event *e;
179
180 while ((e = pa_queue_pop(c->subscription_event_queue))) {
181
182 for (s = c->subscriptions; s; s = s->next) {
183
184 if (!s->dead && pa_subscription_match_flags(s->mask, e->type))
185 s->callback(c, e->type, e->index, s->userdata);
186 }
187
188 pa_xfree(e);
189 }
190 }
191
192 /* Remove dead subscriptions */
193
194 s = c->subscriptions;
195 while (s) {
196 pa_subscription *n = s->next;
197 if (s->dead)
198 free_item(s);
199 s = n;
200 }
201 }
202
203 /* Schedule an mainloop event so that a pending subscription event is dispatched */
204 static void sched_event(pa_core *c) {
205 assert(c);
206
207 if (!c->subscription_defer_event) {
208 c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c);
209 assert(c->subscription_defer_event);
210 }
211
212 c->mainloop->defer_enable(c->subscription_defer_event, 1);
213 }
214
215 /* Append a new subscription event to the subscription event queue and schedule a main loop event */
216 void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) {
217 pa_subscription_event *e;
218 assert(c);
219
220 e = pa_xmalloc(sizeof(pa_subscription_event));
221 e->type = t;
222 e->index = index;
223
224 if (!c->subscription_event_queue) {
225 c->subscription_event_queue = pa_queue_new();
226 assert(c->subscription_event_queue);
227 }
228
229 pa_queue_push(c->subscription_event_queue, e);
230 sched_event(c);
231 }
232
233