]> code.delx.au - pulseaudio/blob - polyp/subscribe.c
add subscription subsystem
[pulseaudio] / polyp / subscribe.c
1 #include <stdio.h>
2 #include <assert.h>
3
4 #include "queue.h"
5 #include "subscribe.h"
6 #include "xmalloc.h"
7
8 struct pa_subscription {
9 struct pa_core *core;
10 int dead;
11 void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
12 void *userdata;
13 enum pa_subscription_mask mask;
14
15 struct pa_subscription *prev, *next;
16 };
17
18 struct pa_subscription_event {
19 enum pa_subscription_event_type type;
20 uint32_t index;
21 };
22
23 static void sched_event(struct pa_core *c);
24
25 struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscription_mask m, void (*callback)(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
26 struct pa_subscription *s;
27 assert(c);
28
29 s = pa_xmalloc(sizeof(struct pa_subscription));
30 s->core = c;
31 s->dead = 0;
32 s->callback = callback;
33 s->userdata = userdata;
34 s->mask = m;
35
36 if ((s->next = c->subscriptions))
37 s->next->prev = s;
38 s->prev = NULL;
39 c->subscriptions = s;
40 return NULL;
41 }
42
43 void pa_subscription_free(struct pa_subscription*s) {
44 assert(s && !s->dead);
45 s->dead = 1;
46 sched_event(s->core);
47 }
48
49 static void free_item(struct pa_subscription *s) {
50 assert(s && s->core);
51
52 if (s->prev)
53 s->prev->next = s->next;
54 else
55 s->core->subscriptions = s->next;
56
57 if (s->next)
58 s->next->prev = s->prev;
59
60 pa_xfree(s);
61 }
62
63 void pa_subscription_free_all(struct pa_core *c) {
64 struct pa_subscription_event *e;
65 assert(c);
66
67 while (c->subscriptions)
68 free_item(c->subscriptions);
69
70 if (c->subscription_event_queue) {
71 while ((e = pa_queue_pop(c->subscription_event_queue)))
72 pa_xfree(e);
73
74 pa_queue_free(c->subscription_event_queue, NULL, NULL);
75 c->subscription_event_queue = NULL;
76 }
77
78 if (c->subscription_defer_event) {
79 c->mainloop->defer_free(c->subscription_defer_event);
80 c->subscription_defer_event = NULL;
81 }
82 }
83
84 static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) {
85 struct pa_core *c = userdata;
86 struct pa_subscription *s;
87 assert(c && c->subscription_defer_event == e && c->mainloop == m);
88
89 c->mainloop->defer_enable(c->subscription_defer_event, 0);
90
91
92 /* Dispatch queued events */
93
94 if (c->subscription_event_queue) {
95 struct pa_subscription_event *e;
96
97 while ((e = pa_queue_pop(c->subscription_event_queue))) {
98 struct pa_subscription *s;
99
100 for (s = c->subscriptions; s; s = s->next) {
101 if (!s->dead && pa_subscription_match_flags(s->mask, e->type))
102 s->callback(c, e->type, e->index, s->userdata);
103 }
104
105 pa_xfree(e);
106 }
107 }
108
109 /* Remove dead subscriptions */
110
111 s = c->subscriptions;
112 while (s) {
113 struct pa_subscription *n = s->next;
114 if (s->dead)
115 free_item(s);
116 s = n;
117 }
118 }
119
120 static void sched_event(struct pa_core *c) {
121 assert(c);
122
123 if (!c->subscription_defer_event) {
124 c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c);
125 assert(c->subscription_defer_event);
126 }
127
128 c->mainloop->defer_enable(c->subscription_defer_event, 1);
129 }
130
131
132 void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index) {
133 struct pa_subscription_event *e;
134 assert(c);
135
136 e = pa_xmalloc(sizeof(struct pa_subscription_event));
137 e->type = t;
138 e->index = index;
139
140 if (!c->subscription_event_queue) {
141 c->subscription_event_queue = pa_queue_new();
142 assert(c->subscription_event_queue);
143 }
144
145 pa_queue_push(c->subscription_event_queue, e);
146 sched_event(c);
147 }
148
149
150 int pa_subscription_match_flags(enum pa_subscription_mask m, enum pa_subscription_event_type t) {
151 return !!(m & (1 >> (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)));
152 }