2a258604d71ed402fcc85ea396ed416c3a399e00
[profile/ivi/pulseaudio.git] / 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 "queue.h"
30 #include "core-subscribe.h"
31 #include "xmalloc.h"
32 #include "log.h"
33
34 /* The subscription subsystem may be used to be notified whenever an
35  * entity (sink, source, ...) is created or deleted. Modules may
36  * register a callback function that is called whenever an event
37  * matching a subscription mask happens. The execution of the callback
38  * function is postponed to the next main loop iteration, i.e. is not
39  * called from within the stack frame the entity was created in. */
40
41 struct pa_subscription {
42     pa_core *core;
43     int dead;
44     void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata);
45     void *userdata;
46     pa_subscription_mask_t mask;
47
48     pa_subscription *prev, *next;
49 };
50
51 struct pa_subscription_event {
52     pa_subscription_event_type_t type;
53     uint32_t index;
54 };
55
56 static void sched_event(pa_core *c);
57
58 /* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */
59 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) {
60     pa_subscription *s;
61     assert(c);
62
63     s = pa_xmalloc(sizeof(pa_subscription));
64     s->core = c;
65     s->dead = 0;
66     s->callback = callback;
67     s->userdata = userdata;
68     s->mask = m;
69
70     if ((s->next = c->subscriptions))
71         s->next->prev = s;
72     s->prev = NULL;
73     c->subscriptions = s;
74     return s;
75 }
76
77 /* Free a subscription object, effectively marking it for deletion */
78 void pa_subscription_free(pa_subscription*s) {
79     assert(s && !s->dead);
80     s->dead = 1;
81     sched_event(s->core);
82 }
83
84 static void free_item(pa_subscription *s) {
85     assert(s && s->core);
86
87     if (s->prev)
88         s->prev->next = s->next;
89     else
90         s->core->subscriptions = s->next;
91             
92     if (s->next)
93         s->next->prev = s->prev;
94     
95     pa_xfree(s);
96 }
97
98 /* Free all subscription objects */
99 void pa_subscription_free_all(pa_core *c) {
100     pa_subscription_event *e;
101     assert(c);
102     
103     while (c->subscriptions)
104         free_item(c->subscriptions);
105
106     if (c->subscription_event_queue) {
107         while ((e = pa_queue_pop(c->subscription_event_queue)))
108             pa_xfree(e);
109         
110         pa_queue_free(c->subscription_event_queue, NULL, NULL);
111         c->subscription_event_queue = NULL;
112     }
113
114     if (c->subscription_defer_event) {
115         c->mainloop->defer_free(c->subscription_defer_event);
116         c->subscription_defer_event = NULL;
117     }
118 }
119
120 /*static void dump_event(pa_subscription_event*e) {
121     switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
122         case PA_SUBSCRIPTION_EVENT_SINK:
123             pa_log(__FILE__": SINK_EVENT");
124             break;
125         case PA_SUBSCRIPTION_EVENT_SOURCE:
126             pa_log(__FILE__": SOURCE_EVENT");
127             break;
128         case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
129             pa_log(__FILE__": SINK_INPUT_EVENT");
130             break;
131         case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
132             pa_log(__FILE__": SOURCE_OUTPUT_EVENT");
133             break;
134         case PA_SUBSCRIPTION_EVENT_MODULE:
135             pa_log(__FILE__": MODULE_EVENT");
136             break;
137         case PA_SUBSCRIPTION_EVENT_CLIENT:
138             pa_log(__FILE__": CLIENT_EVENT");
139             break;
140         default:
141             pa_log(__FILE__": OTHER");
142             break;
143     }
144
145     switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
146         case PA_SUBSCRIPTION_EVENT_NEW:
147             pa_log(__FILE__":  NEW");
148             break;
149         case PA_SUBSCRIPTION_EVENT_CHANGE:
150             pa_log(__FILE__":  CHANGE");
151             break;
152         case PA_SUBSCRIPTION_EVENT_REMOVE:
153             pa_log(__FILE__":  REMOVE");
154             break;
155         default:
156             pa_log(__FILE__":  OTHER");
157             break;
158     }
159
160     pa_log(__FILE__":  %u\n", e->index);
161 }*/
162
163 /* Deferred callback for dispatching subscirption events */
164 static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) {
165     pa_core *c = userdata;
166     pa_subscription *s;
167     assert(c && c->subscription_defer_event == de && c->mainloop == m);
168
169     c->mainloop->defer_enable(c->subscription_defer_event, 0);
170
171
172     /* Dispatch queued events */
173     
174     if (c->subscription_event_queue) {
175         pa_subscription_event *e;
176         
177         while ((e = pa_queue_pop(c->subscription_event_queue))) {
178
179             for (s = c->subscriptions; s; s = s->next) {
180
181                 if (!s->dead && pa_subscription_match_flags(s->mask, e->type))
182                     s->callback(c, e->type, e->index, s->userdata);
183             }
184             
185             pa_xfree(e);
186         }
187     }
188
189     /* Remove dead subscriptions */
190     
191     s = c->subscriptions;
192     while (s) {
193         pa_subscription *n = s->next;
194         if (s->dead)
195             free_item(s);
196         s = n;
197     }
198 }
199
200 /* Schedule an mainloop event so that a pending subscription event is dispatched */
201 static void sched_event(pa_core *c) {
202     assert(c);
203
204     if (!c->subscription_defer_event) {
205         c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c);
206         assert(c->subscription_defer_event);
207     }
208         
209     c->mainloop->defer_enable(c->subscription_defer_event, 1);
210 }
211
212 /* Append a new subscription event to the subscription event queue and schedule a main loop event */
213 void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) {
214     pa_subscription_event *e;
215     assert(c);
216
217     e = pa_xmalloc(sizeof(pa_subscription_event));
218     e->type = t;
219     e->index = index;
220
221     if (!c->subscription_event_queue) {
222         c->subscription_event_queue = pa_queue_new();
223         assert(c->subscription_event_queue);
224     }
225     
226     pa_queue_push(c->subscription_event_queue, e);
227     sched_event(c);
228 }
229
230