source: roaraudio/libroarpulse/mainloop.c @ 3472:d2274d9b5795

Last change on this file since 3472:d2274d9b5795 was 3472:d2274d9b5795, checked in by phi, 14 years ago

get it to work with pacat!

File size: 8.7 KB
Line 
1//mainloop.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *  The code (may) include prototypes and comments (and maybe
6 *  other code fragements) from libpulse*. They are mostly copyrighted by:
7 *  Lennart Poettering <poettering@users.sourceforge.net> and
8 *  Pierre Ossman <drzeus@drzeus.cx>
9 *
10 *  This file is part of libroarpulse a part of RoarAudio,
11 *  a cross-platform sound system for both, home and professional use.
12 *  See README for details.
13 *
14 *  This file is free software; you can redistribute it and/or modify
15 *  it under the terms of the GNU General Public License version 3
16 *  as published by the Free Software Foundation.
17 *
18 *  RoarAudio is distributed in the hope that it will be useful,
19 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *  GNU General Public License for more details.
22 *
23 *  You should have received a copy of the GNU General Public License
24 *  along with this software; see the file COPYING.  If not, write to
25 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 *  NOTE for everyone want's to change something and send patches:
28 *  read README and HACKING! There a addition information on
29 *  the license of this document you need to read before you send
30 *  any patches.
31 *
32 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
33 *  or libpulse*:
34 *  The libs libroaresd, libroararts and libroarpulse link this libroar
35 *  and are therefore GPL. Because of this it may be illigal to use
36 *  them with any software that uses libesd, libartsc or libpulse*.
37 */
38
39#include <libroarpulse/libroarpulse.h>
40#include <poll.h>
41
42#define MAX_IO_EVENTS    8
43
44struct pa_io_event {
45 int used;
46 pa_mainloop_api *api;
47 int fd;
48 pa_io_event_flags_t events;
49 pa_io_event_cb_t cb;
50 void *userdata;
51 pa_io_event_destroy_cb_t destroy;
52};
53
54struct pa_mainloop {
55 pa_mainloop_api api;
56 pa_poll_func    poll_func;
57 void          * poll_userdata;
58 int             poll_timeout;
59 int             quit;
60 int             quitval;
61 pa_io_event     io_event[MAX_IO_EVENTS];
62 struct pollfd   pollfd[MAX_IO_EVENTS];
63 nfds_t          pollfds;
64};
65
66// IO EVENTS:
67static void _roar_pa_io_enable(pa_io_event* e, pa_io_event_flags_t events);
68
69/** Create a new IO event source object */
70static pa_io_event* _roar_pa_io_new(pa_mainloop_api*a, int fd,
71                                    pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) {
72 pa_mainloop * mainloop = a->userdata;
73 pa_io_event * ret = NULL;
74 int i;
75
76 for (i = 0; i < MAX_IO_EVENTS; i++) {
77  if ( mainloop->io_event[i].used == 0 ) {
78   ret = &(mainloop->io_event[i]);
79  }
80 }
81
82 if ( ret == NULL )
83  return NULL;
84
85 ret->used = 1;
86
87 ret->api      = a;
88 ret->fd       = fd;
89 ret->cb       = cb;
90 ret->userdata = userdata;
91
92 // Callbacks:
93 ret->destroy  = NULL;
94
95 _roar_pa_io_enable(ret, events);
96
97 return ret;
98}
99/** Enable or disable IO events on this object */
100static void _roar_pa_io_enable(pa_io_event* e, pa_io_event_flags_t events) {
101 if ( e == NULL )
102  return;
103
104 e->events = events;
105}
106
107/** Free a IO event source object */
108static void _roar_pa_io_free(pa_io_event* e) {
109 if ( e == NULL )
110  return;
111
112 if ( e->destroy != NULL )
113  e->destroy(e->api, e, e->userdata);
114
115 e->used = 0;
116}
117/** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */
118static void _roar_pa_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t cb) {
119 if ( e == NULL )
120  return;
121
122 e->destroy = cb;
123}
124
125
126
127// API:
128
129/** Allocate a new main loop object */
130pa_mainloop *pa_mainloop_new(void) {
131 pa_mainloop * m = roar_mm_malloc(sizeof(pa_mainloop));
132
133 ROAR_DBG("pa_mainloop_new() = ?");
134
135 if ( m == NULL )
136  return NULL;
137
138 memset(m, 0, sizeof(pa_mainloop));
139
140 m->api.userdata       = m;
141 m->api.io_new         = _roar_pa_io_new;
142 m->api.io_enable      = _roar_pa_io_enable;
143 m->api.io_free        = _roar_pa_io_free;
144 m->api.io_set_destroy = _roar_pa_io_set_destroy;
145
146 ROAR_DBG("pa_mainloop_new() = %p", m);
147 return m;
148}
149
150/** Free a main loop object */
151void pa_mainloop_free(pa_mainloop* m) {
152 ROAR_DBG("pa_mainloop_free(m=%p) = ?", m);
153
154 if ( m == NULL )
155  return;
156
157 roar_mm_free(m);
158
159 ROAR_DBG("pa_mainloop_free(m=%p) = (void)", m);
160}
161
162/** Prepare for a single iteration of the main loop. Returns a negative value
163on error or exit request. timeout specifies a maximum timeout for the subsequent
164poll, or -1 for blocking behaviour. .*/
165int pa_mainloop_prepare(pa_mainloop *m, int timeout) {
166 short events;
167 int i;
168
169 if ( m == NULL )
170  return -1;
171
172 if ( m->quit )
173  return -2;
174
175 m->pollfds = 0;
176
177 for (i = 0; i < MAX_IO_EVENTS; i++) {
178  if ( m->io_event[i].used ) {
179   events = 0;
180
181   if ( m->io_event[i].events & PA_IO_EVENT_INPUT )
182    events |= POLLIN;
183
184   if ( m->io_event[i].events & PA_IO_EVENT_OUTPUT )
185    events |= POLLOUT;
186
187   if ( m->io_event[i].events & PA_IO_EVENT_HANGUP )
188    events |= POLLHUP;
189
190   if ( m->io_event[i].events & PA_IO_EVENT_ERROR )
191    events |= POLLERR;
192
193   if ( events == 0 )
194    continue;
195
196   m->pollfd[m->pollfds].fd     = m->io_event[i].fd;
197   m->pollfd[m->pollfds].events = events;
198   m->pollfds++;
199  }
200 }
201
202 m->poll_timeout = timeout;
203
204 return 0;
205}
206
207/** Execute the previously prepared poll. Returns a negative value on error.*/
208int pa_mainloop_poll(pa_mainloop *m) {
209 int ret;
210
211 if ( m == NULL )
212  return -1;
213
214 if ( m->quit )
215  return -2;
216
217 if ( m->poll_func != NULL ) {
218  ret = m->poll_func(m->pollfd, m->pollfds, m->poll_timeout, m->poll_userdata);
219 } else {
220  ret = poll(m->pollfd, m->pollfds, m->poll_timeout);
221 }
222
223 return ret;
224}
225
226/** Dispatch timeout, io and deferred events from the previously executed poll. Returns
227a negative value on error. On success returns the number of source dispatched. */
228int pa_mainloop_dispatch(pa_mainloop *m) {
229 pa_io_event_flags_t events;
230 int count = 0;
231
232 int i, h;
233
234 if ( m == NULL )
235  return -1;
236
237 if ( m->quit )
238  return -2;
239
240 for (i = 0; i < m->pollfds; i++) {
241  if ( m->pollfd[i].revents != 0 ) {
242   for (h = 0; h < MAX_IO_EVENTS; h++) {
243    if ( m->io_event[h].fd == m->pollfd[i].fd ) {
244     events = PA_IO_EVENT_NULL;
245
246     if ( m->pollfd[i].revents & POLLIN )
247      events |= PA_IO_EVENT_INPUT;
248
249     if ( m->pollfd[i].revents & POLLOUT )
250      events |= PA_IO_EVENT_OUTPUT;
251
252     if ( m->pollfd[i].revents & POLLHUP )
253      events |= PA_IO_EVENT_HANGUP;
254
255     if ( m->pollfd[i].revents & POLLERR )
256      events |= PA_IO_EVENT_ERROR;
257
258     if ( m->io_event[h].cb != NULL )
259      m->io_event[h].cb(&(m->api), &(m->io_event[h]), m->pollfd[i].fd, events, m->io_event[h].userdata);
260
261     count++;
262    }
263   }
264  }
265 }
266
267 return count;
268}
269
270/** Return the return value as specified with the main loop's quit() routine. */
271int pa_mainloop_get_retval(pa_mainloop *m) {
272 if ( m == NULL )
273  return -1;
274
275 return m->quitval;
276}
277
278/** Run a single iteration of the main loop. This is a convenience function
279for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch().
280Returns a negative value on error or exit request. If block is nonzero,
281block for events if none are queued. Optionally return the return value as
282specified with the main loop's quit() routine in the integer variable retval points
283to. On success returns the number of sources dispatched in this iteration. */
284int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) {
285 int r;
286
287 ROAR_DBG("pa_mainloop_iterate(m=%p, block=%i, retval=%p) = ?", m, block, retval);
288
289 if ( m == NULL )
290  return -1;
291
292 r = pa_mainloop_prepare(m, block ? -1 : 0);
293
294 if ( r >= 0 )
295  r = pa_mainloop_poll(m);
296
297 if ( r > 0 )
298  r = pa_mainloop_dispatch(m);
299
300 if ( r == -2 && retval != NULL ) {
301  *retval = m->quitval;
302 }
303
304 ROAR_DBG("pa_mainloop_iterate(m=%p, block=%i, retval=%p) = %i", m, block, retval, r);
305 return r;
306}
307
308/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */
309int pa_mainloop_run(pa_mainloop *m, int *retval) {
310 int r = 1;
311
312 ROAR_DBG("pa_mainloop_run(m=%p, retval=%p) = ?", m, retval);
313
314 if ( m == NULL )
315  return -1;
316
317 while (!(m->quit) && r > 0) {
318  r = pa_mainloop_iterate(m, 1, retval);
319 }
320
321 ROAR_DBG("pa_mainloop_run(m=%p, retval=%p): r=%i", m, retval, r);
322
323 if ( r == -2 )
324  return 1;
325
326 if ( r < 0 )
327  return -1;
328
329 return 0;
330}
331
332/** Return the abstract main loop abstraction layer vtable for this main loop. */
333pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) {
334 if ( m == NULL )
335  return NULL;
336
337 return &(m->api);
338}
339
340/** Shutdown the main loop */
341void pa_mainloop_quit(pa_mainloop *m, int r) {
342 if ( m == NULL )
343  return;
344
345 m->quitval = r;
346 m->quit    = 1;
347}
348
349/** Interrupt a running poll (for threaded systems) */
350void pa_mainloop_wakeup(pa_mainloop *m);
351
352/** Change the poll() implementation */
353void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) {
354 if ( m == NULL )
355  return;
356
357 m->poll_func     = poll_func;
358 m->poll_userdata = userdata;
359}
360
361//ll
Note: See TracBrowser for help on using the repository browser.