remove global memblock statistic variables in favor of memblock_stat objects
[profile/ivi/pulseaudio-panda.git] / polyp / polyplib-context.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 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 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 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33
34 #include "polyplib-internal.h"
35 #include "polyplib-context.h"
36 #include "native-common.h"
37 #include "pdispatch.h"
38 #include "pstream.h"
39 #include "dynarray.h"
40 #include "socket-client.h"
41 #include "pstream-util.h"
42 #include "authkey.h"
43 #include "util.h"
44 #include "xmalloc.h"
45
46 static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
47     [PA_COMMAND_REQUEST] = { pa_command_request },
48     [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed },
49     [PA_COMMAND_RECORD_STREAM_KILLED] = { pa_command_stream_killed },
50     [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event },
51 };
52
53 struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
54     struct pa_context *c;
55     assert(mainloop && name);
56     
57     c = pa_xmalloc(sizeof(struct pa_context));
58     c->ref = 1;
59     c->name = pa_xstrdup(name);
60     c->mainloop = mainloop;
61     c->client = NULL;
62     c->pstream = NULL;
63     c->pdispatch = NULL;
64     c->playback_streams = pa_dynarray_new();
65     c->record_streams = pa_dynarray_new();
66     assert(c->playback_streams && c->record_streams);
67
68     PA_LLIST_HEAD_INIT(struct pa_stream, c->streams);
69     PA_LLIST_HEAD_INIT(struct pa_operation, c->operations);
70     
71     c->error = PA_ERROR_OK;
72     c->state = PA_CONTEXT_UNCONNECTED;
73     c->ctag = 0;
74
75     c->state_callback = NULL;
76     c->state_userdata = NULL;
77
78     c->subscribe_callback = NULL;
79     c->subscribe_userdata = NULL;
80
81     c->memblock_stat = pa_memblock_stat_new();
82     
83     pa_check_for_sigpipe();
84     return c;
85 }
86
87 static void context_free(struct pa_context *c) {
88     assert(c);
89
90     while (c->operations)
91         pa_operation_cancel(c->operations);
92
93     while (c->streams)
94         pa_stream_set_state(c->streams, PA_STREAM_TERMINATED);
95     
96     if (c->client)
97         pa_socket_client_unref(c->client);
98     if (c->pdispatch)
99         pa_pdispatch_unref(c->pdispatch);
100     if (c->pstream) {
101         pa_pstream_close(c->pstream);
102         pa_pstream_unref(c->pstream);
103     }
104     
105     if (c->record_streams)
106         pa_dynarray_free(c->record_streams, NULL, NULL);
107     if (c->playback_streams)
108         pa_dynarray_free(c->playback_streams, NULL, NULL);
109
110     pa_memblock_stat_unref(c->memblock_stat);
111     
112     pa_xfree(c->name);
113     pa_xfree(c);
114 }
115
116 struct pa_context* pa_context_ref(struct pa_context *c) {
117     assert(c && c->ref >= 1);
118     c->ref++;
119     return c;
120 }
121
122 void pa_context_unref(struct pa_context *c) {
123     assert(c && c->ref >= 1);
124
125     if ((--(c->ref)) == 0)
126         context_free(c);
127 }
128
129 void pa_context_set_state(struct pa_context *c, enum pa_context_state st) {
130     assert(c);
131     
132     if (c->state == st)
133         return;
134
135     pa_context_ref(c);
136
137     if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) {
138         struct pa_stream *s;
139         
140         s = c->streams ? pa_stream_ref(c->streams) : NULL;
141         while (s) {
142             struct pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
143             pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
144             pa_stream_unref(s);
145             s = n;
146         }
147
148         if (c->pdispatch)
149             pa_pdispatch_unref(c->pdispatch);
150         c->pdispatch = NULL;
151     
152         if (c->pstream) {
153             pa_pstream_close(c->pstream);
154             pa_pstream_unref(c->pstream);
155         }
156         c->pstream = NULL;
157     
158         if (c->client)
159             pa_socket_client_unref(c->client);
160         c->client = NULL;
161     }
162
163     c->state = st;
164     if (c->state_callback)
165         c->state_callback(c, c->state_userdata);
166
167     pa_context_unref(c);
168 }
169
170 void pa_context_fail(struct pa_context *c, int error) {
171     assert(c);
172     c->error = error;
173     pa_context_set_state(c, PA_CONTEXT_FAILED);
174 }
175
176 static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
177     struct pa_context *c = userdata;
178     assert(p && c);
179     pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED);
180 }
181
182 static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
183     struct pa_context *c = userdata;
184     assert(p && packet && c);
185
186     pa_context_ref(c);
187     
188     if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
189         fprintf(stderr, "polyp.c: invalid packet.\n");
190         pa_context_fail(c, PA_ERROR_PROTOCOL);
191     }
192
193     pa_context_unref(c);
194 }
195
196 static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
197     struct pa_context *c = userdata;
198     struct pa_stream *s;
199     assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
200
201     pa_context_ref(c);
202     
203     if ((s = pa_dynarray_get(c->record_streams, channel))) {
204         if (s->read_callback)
205             s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
206     }
207
208     pa_context_unref(c);
209 }
210
211 int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
212     assert(c && t);
213
214     if (command == PA_COMMAND_ERROR) {
215         if (pa_tagstruct_getu32(t, &c->error) < 0) {
216             pa_context_fail(c, PA_ERROR_PROTOCOL);
217             return -1;
218                 
219         }
220     } else if (command == PA_COMMAND_TIMEOUT)
221         c->error = PA_ERROR_TIMEOUT;
222     else {
223         pa_context_fail(c, PA_ERROR_PROTOCOL);
224         return -1;
225     }
226
227     return 0;
228 }
229
230 static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
231     struct pa_context *c = userdata;
232     assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME));
233
234     pa_context_ref(c);
235     
236     if (command != PA_COMMAND_REPLY) {
237         if (pa_context_handle_error(c, command, t) < 0)
238             pa_context_fail(c, PA_ERROR_PROTOCOL);
239
240         goto finish;
241     }
242
243     switch(c->state) {
244         case PA_CONTEXT_AUTHORIZING: {
245             struct pa_tagstruct *t;
246             t = pa_tagstruct_new(NULL, 0);
247             assert(t);
248             pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
249             pa_tagstruct_putu32(t, tag = c->ctag++);
250             pa_tagstruct_puts(t, c->name);
251             pa_pstream_send_tagstruct(c->pstream, t);
252             pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
253
254             pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
255             break;
256         }
257
258         case PA_CONTEXT_SETTING_NAME :
259             pa_context_set_state(c, PA_CONTEXT_READY);
260             break;
261             
262         default:
263             assert(0);
264     }
265
266 finish:
267     pa_context_unref(c);
268 }
269
270 static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
271     struct pa_context *c = userdata;
272     struct pa_tagstruct *t;
273     uint32_t tag;
274     assert(client && c && c->state == PA_CONTEXT_CONNECTING);
275
276     pa_context_ref(c);
277     
278     pa_socket_client_unref(client);
279     c->client = NULL;
280
281     if (!io) {
282         pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
283         goto finish;
284     }
285
286     assert(!c->pstream);
287     c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat);
288     assert(c->pstream);
289     
290     pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
291     pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
292     pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
293
294     assert(!c->pdispatch);
295     c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
296     assert(c->pdispatch);
297
298     t = pa_tagstruct_new(NULL, 0);
299     assert(t);
300     pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
301     pa_tagstruct_putu32(t, tag = c->ctag++);
302     pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
303     pa_pstream_send_tagstruct(c->pstream, t);
304     pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
305
306     pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
307
308 finish:
309     pa_context_unref(c);
310 }
311
312 static struct sockaddr *resolve_server(const char *server, size_t *len) {
313     struct sockaddr *sa;
314     struct addrinfo hints, *result = NULL;
315     char *port;
316     assert(server && len);
317
318     if ((port = strrchr(server, ':')))
319         port++;
320     if (!port)
321         port = DEFAULT_PORT;
322
323     memset(&hints, 0, sizeof(hints));
324     hints.ai_family = PF_UNSPEC;
325     hints.ai_socktype = SOCK_STREAM;
326     hints.ai_protocol = 0;
327
328     if (getaddrinfo(server, port, &hints, &result) != 0)
329         return NULL;
330     assert(result);
331     
332     sa = pa_xmalloc(*len = result->ai_addrlen);
333     memcpy(sa, result->ai_addr, *len);
334
335     freeaddrinfo(result);
336     
337     return sa;
338 }
339
340 int pa_context_connect(struct pa_context *c, const char *server) {
341     int r = -1;
342     assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
343
344     pa_context_ref(c);
345     
346     if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
347         pa_context_fail(c, PA_ERROR_AUTHKEY);
348         goto finish;
349     }
350
351     if (!server)
352         if (!(server = getenv(ENV_DEFAULT_SERVER)))
353             server = DEFAULT_SERVER;
354
355     assert(!c->client);
356     
357     if (*server == '/') {
358         if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
359             pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
360             goto finish;
361         }
362     } else {
363         struct sockaddr* sa;
364         size_t sa_len;
365
366         if (!(sa = resolve_server(server, &sa_len))) {
367             pa_context_fail(c, PA_ERROR_INVALIDSERVER);
368             goto finish;
369         }
370
371         c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
372         pa_xfree(sa);
373
374         if (!c->client) {
375             pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
376             goto finish;
377         }
378     }
379
380     pa_socket_client_set_callback(c->client, on_connection, c);
381     pa_context_set_state(c, PA_CONTEXT_CONNECTING);
382
383     r = 0;
384     
385 finish:
386     pa_context_unref(c);
387     
388     return r;
389 }
390
391 void pa_context_disconnect(struct pa_context *c) {
392     assert(c);
393     pa_context_set_state(c, PA_CONTEXT_TERMINATED);
394 }
395
396 enum pa_context_state pa_context_get_state(struct pa_context *c) {
397     assert(c && c->ref >= 1);
398     return c->state;
399 }
400
401 int pa_context_errno(struct pa_context *c) {
402     assert(c && c->ref >= 1);
403     return c->error;
404 }
405
406 void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
407     assert(c && c->ref >= 1);
408     c->state_callback = cb;
409     c->state_userdata = userdata;
410 }
411
412 int pa_context_is_pending(struct pa_context *c) {
413     assert(c && c->ref >= 1);
414
415     if (c->state != PA_CONTEXT_READY)
416         return 0;
417
418     assert(c->pstream && c->pdispatch);
419     return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
420 }
421
422 static void set_dispatch_callbacks(struct pa_operation *o);
423
424 static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
425     set_dispatch_callbacks(userdata);
426 }
427
428 static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
429     set_dispatch_callbacks(userdata);
430 }
431
432 static void set_dispatch_callbacks(struct pa_operation *o) {
433     int done = 1;
434     assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY);
435
436     pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
437     pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
438     
439     if (pa_pdispatch_is_pending(o->context->pdispatch)) {
440         pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
441         done = 0;
442     }
443
444     if (pa_pstream_is_pending(o->context->pstream)) {
445         pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
446         done = 0;
447     }
448
449     if (!done)
450         pa_operation_ref(o);
451     else {
452         if (o->callback) {
453             void (*cb)(struct pa_context *c, void *userdata);
454             cb = (void*) o->callback;
455             cb(o->context, o->userdata);
456         }
457         
458         pa_operation_done(o);
459     }   
460
461     pa_operation_unref(o);
462 }
463
464 struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) {
465     struct pa_operation *o;
466     assert(c && c->ref >= 1 && c->state == PA_CONTEXT_READY);
467
468     if (!pa_context_is_pending(c))
469         return NULL;
470
471     o = pa_operation_new(c, NULL);
472     assert(o);
473     o->callback = cb;
474     o->userdata = userdata;
475
476     set_dispatch_callbacks(pa_operation_ref(o));
477
478     return o;
479 }
480
481 void pa_context_exit_daemon(struct pa_context *c) {
482     struct pa_tagstruct *t;
483     assert(c && c->ref >= 1);
484     
485     t = pa_tagstruct_new(NULL, 0);
486     assert(t);
487     pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
488     pa_tagstruct_putu32(t, c->ctag++);
489     pa_pstream_send_tagstruct(c->pstream, t);
490 }
491
492 void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
493     struct pa_operation *o = userdata;
494     int success = 1;
495     assert(pd && o && o->context && o->ref >= 1);
496
497     if (command != PA_COMMAND_REPLY) {
498         if (pa_context_handle_error(o->context, command, t) < 0)
499             goto finish;
500
501         success = 0;
502     } else if (!pa_tagstruct_eof(t)) {
503         pa_context_fail(o->context, PA_ERROR_PROTOCOL);
504         goto finish;
505     }
506
507     if (o->callback) {
508         void (*cb)(struct pa_context *c, int success, void *userdata) = o->callback;
509         cb(o->context, success, o->userdata);
510     }
511
512 finish:
513     pa_operation_done(o);
514     pa_operation_unref(o);
515 }
516
517 struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata) {
518     struct pa_tagstruct *t;
519     struct pa_operation *o;
520     uint32_t tag;
521     assert(c && cb);
522
523     o = pa_operation_new(c, NULL);
524     o->callback = cb;
525     o->userdata = userdata;
526
527     t = pa_tagstruct_new(NULL, 0);
528     pa_tagstruct_putu32(t, command);
529     pa_tagstruct_putu32(t, tag = c->ctag++);
530     pa_pstream_send_tagstruct(c->pstream, t);
531     pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o);
532
533     return pa_operation_ref(o);
534 }