]> code.delx.au - pulseaudio/blob - polyp/module-tunnel.c
improve sync clock change
[pulseaudio] / polyp / module-tunnel.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 <unistd.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <regex.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include "module.h"
36 #include "util.h"
37 #include "modargs.h"
38 #include "log.h"
39 #include "subscribe.h"
40 #include "xmalloc.h"
41 #include "sink-input.h"
42 #include "pdispatch.h"
43 #include "pstream.h"
44 #include "pstream-util.h"
45 #include "authkey.h"
46 #include "socket-client.h"
47 #include "socket-util.h"
48 #include "authkey-prop.h"
49
50 #ifdef TUNNEL_SINK
51 #include "module-tunnel-sink-symdef.h"
52 PA_MODULE_DESCRIPTION("Tunnel module for sinks")
53 PA_MODULE_USAGE("server=<address> sink=<remote sink name> cookie=<filename> format=<sample format> channels=<number of channels> rate=<sample rate> sink_name=<name for the local sink>")
54 #else
55 #include "module-tunnel-source-symdef.h"
56 PA_MODULE_DESCRIPTION("Tunnel module for sources")
57 PA_MODULE_USAGE("server=<address> source=<remote source name> cookie=<filename> format=<sample format> channels=<number of channels> rate=<sample rate> source_name=<name for the local source>")
58 #endif
59
60 PA_MODULE_AUTHOR("Lennart Poettering")
61 PA_MODULE_VERSION(PACKAGE_VERSION)
62
63 #define PA_TYPEID_TUNNEL PA_TYPEID_MAKE('T', 'U', 'N', 'L')
64
65 #define DEFAULT_SINK_NAME "tunnel"
66 #define DEFAULT_SOURCE_NAME "tunnel"
67
68 #define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8)
69 #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2)
70 #define DEFAULT_MINREQ 512
71 #define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ)
72 #define DEFAULT_FRAGSIZE 1024
73
74 #define DEFAULT_TIMEOUT 5
75
76 #define LATENCY_INTERVAL 10
77
78 static const char* const valid_modargs[] = {
79 "server",
80 "cookie",
81 "format",
82 "channels",
83 "rate",
84 #ifdef TUNNEL_SINK
85 "sink_name",
86 "sink",
87 #else
88 "source_name",
89 "source",
90 #endif
91 NULL,
92 };
93
94 static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
95
96 #ifdef TUNNEL_SINK
97 static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
98 #endif
99
100 static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
101 #ifdef TUNNEL_SINK
102 [PA_COMMAND_REQUEST] = { command_request },
103 #endif
104 [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_stream_killed },
105 [PA_COMMAND_RECORD_STREAM_KILLED] = { command_stream_killed },
106 };
107
108 struct userdata {
109 struct pa_socket_client *client;
110 struct pa_pstream *pstream;
111 struct pa_pdispatch *pdispatch;
112
113 char *server_name;
114 #ifdef TUNNEL_SINK
115 char *sink_name;
116 struct pa_sink *sink;
117 uint32_t requested_bytes;
118 #else
119 char *source_name;
120 struct pa_source *source;
121 #endif
122
123 struct pa_module *module;
124 struct pa_core *core;
125
126 uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
127
128 uint32_t ctag;
129 uint32_t device_index;
130 uint32_t channel;
131
132 pa_usec_t host_latency;
133
134 struct pa_time_event *time_event;
135
136 int auth_cookie_in_property;
137 };
138
139 static void close_stuff(struct userdata *u) {
140 assert(u);
141
142 if (u->pstream) {
143 pa_pstream_close(u->pstream);
144 pa_pstream_unref(u->pstream);
145 u->pstream = NULL;
146 }
147
148 if (u->pdispatch) {
149 pa_pdispatch_unref(u->pdispatch);
150 u->pdispatch = NULL;
151 }
152
153 if (u->client) {
154 pa_socket_client_unref(u->client);
155 u->client = NULL;
156 }
157
158 #ifdef TUNNEL_SINK
159 if (u->sink) {
160 pa_sink_disconnect(u->sink);
161 pa_sink_unref(u->sink);
162 u->sink = NULL;
163 }
164 #else
165 if (u->source) {
166 pa_source_disconnect(u->source);
167 pa_source_unref(u->source);
168 u->source = NULL;
169 }
170 #endif
171
172 if (u->time_event) {
173 u->core->mainloop->time_free(u->time_event);
174 u->time_event = NULL;
175 }
176 }
177
178 static void die(struct userdata *u) {
179 assert(u);
180 close_stuff(u);
181 pa_module_unload_request(u->module);
182 }
183
184 static void command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
185 struct userdata *u = userdata;
186 assert(pd && t && u && u->pdispatch == pd);
187
188 pa_log(__FILE__": stream killed\n");
189 die(u);
190 }
191
192 #ifdef TUNNEL_SINK
193 static void send_prebuf_request(struct userdata *u) {
194 struct pa_tagstruct *t;
195
196 t = pa_tagstruct_new(NULL, 0);
197 pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM);
198 pa_tagstruct_putu32(t, u->ctag++);
199 pa_tagstruct_putu32(t, u->channel);
200 pa_pstream_send_tagstruct(u->pstream, t);
201 }
202
203 static void send_bytes(struct userdata *u) {
204 assert(u);
205
206 if (!u->pstream)
207 return;
208
209 while (u->requested_bytes > 0) {
210 struct pa_memchunk chunk;
211 if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) {
212
213
214 if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF)
215 send_prebuf_request(u);
216
217 return;
218 }
219
220 pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk);
221 pa_memblock_unref(chunk.memblock);
222
223 if (chunk.length > u->requested_bytes)
224 u->requested_bytes = 0;
225 else
226 u->requested_bytes -= chunk.length;
227 }
228 }
229
230 static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
231 struct userdata *u = userdata;
232 uint32_t bytes, channel;
233 assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd);
234
235 if (pa_tagstruct_getu32(t, &channel) < 0 ||
236 pa_tagstruct_getu32(t, &bytes) < 0 ||
237 !pa_tagstruct_eof(t)) {
238 pa_log(__FILE__": invalid protocol reply\n");
239 die(u);
240 return;
241 }
242
243 if (channel != u->channel) {
244 pa_log(__FILE__": recieved data for invalid channel\n");
245 die(u);
246 return;
247 }
248
249 u->requested_bytes += bytes;
250 send_bytes(u);
251 }
252
253 #endif
254
255 static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
256 struct userdata *u = userdata;
257 pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec;
258 int playing;
259 uint32_t queue_length;
260 uint64_t counter;
261 struct timeval local, remote, now;
262 assert(pd && u);
263
264 if (command != PA_COMMAND_REPLY) {
265 if (command == PA_COMMAND_ERROR)
266 pa_log(__FILE__": failed to get latency.\n");
267 else
268 pa_log(__FILE__": protocol error.\n");
269 die(u);
270 return;
271 }
272
273 if (pa_tagstruct_get_usec(t, &buffer_usec) < 0 ||
274 pa_tagstruct_get_usec(t, &sink_usec) < 0 ||
275 pa_tagstruct_get_usec(t, &source_usec) < 0 ||
276 pa_tagstruct_get_boolean(t, &playing) < 0 ||
277 pa_tagstruct_getu32(t, &queue_length) < 0 ||
278 pa_tagstruct_get_timeval(t, &local) < 0 ||
279 pa_tagstruct_get_timeval(t, &remote) < 0 ||
280 pa_tagstruct_getu64(t, &counter) < 0 ||
281 !pa_tagstruct_eof(t)) {
282 pa_log(__FILE__": invalid reply.\n");
283 die(u);
284 return;
285 }
286
287 gettimeofday(&now, NULL);
288
289 if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
290 /* local and remote seem to have synchronized clocks */
291 #ifdef TUNNEL_SINK
292 transport_usec = pa_timeval_diff(&remote, &local);
293 #else
294 transport_usec = pa_timeval_diff(&now, &remote);
295 #endif
296 } else
297 transport_usec = pa_timeval_diff(&now, &local)/2;
298
299 #ifdef TUNNEL_SINK
300 u->host_latency = sink_usec + transport_usec;
301 #else
302 u->host_latency = source_usec + transport_usec;
303 if (u->host_latency > sink_usec)
304 u->host_latency -= sink_usec;
305 else
306 u->host_latency = 0;
307 #endif
308
309 /* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */
310 }
311
312 static void request_latency(struct userdata *u) {
313 struct pa_tagstruct *t;
314 struct timeval now;
315 uint32_t tag;
316 assert(u);
317
318 t = pa_tagstruct_new(NULL, 0);
319 #ifdef TUNNEL_SINK
320 pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
321 #else
322 pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY);
323 #endif
324 pa_tagstruct_putu32(t, tag = u->ctag++);
325 pa_tagstruct_putu32(t, u->channel);
326
327 gettimeofday(&now, NULL);
328 pa_tagstruct_put_timeval(t, &now);
329 pa_tagstruct_putu64(t, 0);
330
331 pa_pstream_send_tagstruct(u->pstream, t);
332 pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u);
333 }
334
335 static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
336 struct userdata *u = userdata;
337 assert(pd && u && u->pdispatch == pd);
338
339 if (command != PA_COMMAND_REPLY) {
340 if (command == PA_COMMAND_ERROR)
341 pa_log(__FILE__": failed to create stream.\n");
342 else
343 pa_log(__FILE__": protocol error.\n");
344 die(u);
345 return;
346 }
347
348 if (pa_tagstruct_getu32(t, &u->channel) < 0 ||
349 pa_tagstruct_getu32(t, &u->device_index) < 0 ||
350 #ifdef TUNNEL_SINK
351 pa_tagstruct_getu32(t, &u->requested_bytes) < 0 ||
352 #endif
353 !pa_tagstruct_eof(t)) {
354 pa_log(__FILE__": invalid reply.\n");
355 die(u);
356 return;
357 }
358
359 request_latency(u);
360 #ifdef TUNNEL_SINK
361 send_bytes(u);
362 #endif
363 }
364
365 static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
366 struct userdata *u = userdata;
367 struct pa_tagstruct *reply;
368 char name[256], un[128], hn[128];
369 assert(pd && u && u->pdispatch == pd);
370
371 if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) {
372 if (command == PA_COMMAND_ERROR)
373 pa_log(__FILE__": failed to authenticate\n");
374 else
375 pa_log(__FILE__": protocol error.\n");
376 die(u);
377 return;
378 }
379 #ifdef TUNNEL_SINK
380 snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'",
381 pa_get_host_name(hn, sizeof(hn)),
382 pa_get_user_name(un, sizeof(un)),
383 u->sink->name);
384 #else
385 snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', source '%s'",
386 pa_get_host_name(hn, sizeof(hn)),
387 pa_get_user_name(un, sizeof(un)),
388 u->source->name);
389 #endif
390
391 reply = pa_tagstruct_new(NULL, 0);
392 pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME);
393 pa_tagstruct_putu32(reply, tag = u->ctag++);
394 pa_tagstruct_puts(reply, name);
395 pa_pstream_send_tagstruct(u->pstream, reply);
396 /* We ignore the server's reply here */
397
398 reply = pa_tagstruct_new(NULL, 0);
399 #ifdef TUNNEL_SINK
400 pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM);
401 pa_tagstruct_putu32(reply, tag = u->ctag++);
402 pa_tagstruct_puts(reply, name);
403 pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec);
404 pa_tagstruct_putu32(reply, PA_INVALID_INDEX);
405 pa_tagstruct_puts(reply, u->sink_name);
406 pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH);
407 pa_tagstruct_put_boolean(reply, 0);
408 pa_tagstruct_putu32(reply, DEFAULT_TLENGTH);
409 pa_tagstruct_putu32(reply, DEFAULT_PREBUF);
410 pa_tagstruct_putu32(reply, DEFAULT_MINREQ);
411 pa_tagstruct_putu32(reply, PA_VOLUME_NORM);
412 #else
413 pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM);
414 pa_tagstruct_putu32(reply, tag = u->ctag++);
415 pa_tagstruct_puts(reply, name);
416 pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec);
417 pa_tagstruct_putu32(reply, PA_INVALID_INDEX);
418 pa_tagstruct_puts(reply, u->source_name);
419 pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH);
420 pa_tagstruct_put_boolean(reply, 0);
421 pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE);
422 #endif
423
424 pa_pstream_send_tagstruct(u->pstream, reply);
425 pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u);
426 }
427
428 static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
429 struct userdata *u = userdata;
430 assert(p && u);
431
432 pa_log(__FILE__": stream died.\n");
433 die(u);
434 }
435
436
437 static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
438 struct userdata *u = userdata;
439 assert(p && packet && u);
440
441 if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) {
442 pa_log(__FILE__": invalid packet\n");
443 die(u);
444 }
445 }
446
447 #ifndef TUNNEL_SINK
448 static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) {
449 struct userdata *u = userdata;
450 assert(p && chunk && u);
451
452 if (channel != u->channel) {
453 pa_log(__FILE__": recieved memory block on bad channel.\n");
454 die(u);
455 return;
456 }
457
458 pa_source_post(u->source, chunk);
459 }
460 #endif
461
462 static void on_connection(struct pa_socket_client *sc, struct pa_iochannel *io, void *userdata) {
463 struct userdata *u = userdata;
464 struct pa_tagstruct *t;
465 uint32_t tag;
466 assert(sc && u && u->client == sc);
467
468 pa_socket_client_unref(u->client);
469 u->client = NULL;
470
471 if (!io) {
472 pa_log(__FILE__": connection failed.\n");
473 pa_module_unload_request(u->module);
474 return;
475 }
476
477 u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->memblock_stat);
478 u->pdispatch = pa_pdispatch_new(u->core->mainloop, command_table, PA_COMMAND_MAX);
479
480 pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u);
481 pa_pstream_set_recieve_packet_callback(u->pstream, pstream_packet_callback, u);
482 #ifndef TUNNEL_SINK
483 pa_pstream_set_recieve_memblock_callback(u->pstream, pstream_memblock_callback, u);
484 #endif
485
486 t = pa_tagstruct_new(NULL, 0);
487 pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
488 pa_tagstruct_putu32(t, tag = u->ctag++);
489 pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie));
490 pa_pstream_send_tagstruct(u->pstream, t);
491 pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u);
492
493 }
494
495 #ifdef TUNNEL_SINK
496 static void sink_notify(struct pa_sink*sink) {
497 struct userdata *u;
498 assert(sink && sink->userdata);
499 u = sink->userdata;
500
501 send_bytes(u);
502 }
503
504 static pa_usec_t sink_get_latency(struct pa_sink *sink) {
505 struct userdata *u;
506 uint32_t l;
507 pa_usec_t usec = 0;
508 assert(sink && sink->userdata);
509 u = sink->userdata;
510
511 l = DEFAULT_TLENGTH;
512
513 if (l > u->requested_bytes) {
514 l -= u->requested_bytes;
515 usec += pa_bytes_to_usec(l, &u->sink->sample_spec);
516 }
517
518 usec += u->host_latency;
519
520 return usec;
521 }
522 #else
523 static pa_usec_t source_get_latency(struct pa_source *source) {
524 struct userdata *u;
525 assert(source && source->userdata);
526 u = source->userdata;
527
528 return u->host_latency;
529 }
530 #endif
531
532 static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) {
533 struct userdata *u = userdata;
534 struct timeval ntv;
535 assert(m && e && u);
536
537 request_latency(u);
538
539 gettimeofday(&ntv, NULL);
540 ntv.tv_sec += LATENCY_INTERVAL;
541 m->time_restart(e, &ntv);
542 }
543
544 static int load_key(struct userdata *u, const char*fn) {
545 assert(u);
546
547 u->auth_cookie_in_property = 0;
548
549 if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) {
550 pa_log_debug(__FILE__": using already loaded auth cookie.\n");
551 pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
552 u->auth_cookie_in_property = 1;
553 return 0;
554 }
555
556 if (!fn)
557 fn = PA_NATIVE_COOKIE_FILE;
558
559 if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0)
560 return -1;
561
562 pa_log_debug(__FILE__": loading cookie from disk.\n");
563
564 if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0)
565 u->auth_cookie_in_property = 1;
566
567 return 0;
568 }
569
570 int pa__init(struct pa_core *c, struct pa_module*m) {
571 struct pa_modargs *ma = NULL;
572 struct userdata *u = NULL;
573 struct pa_sample_spec ss;
574 struct timeval ntv;
575 assert(c && m);
576
577 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
578 pa_log(__FILE__": failed to parse module arguments\n");
579 goto fail;
580 }
581
582 u = pa_xmalloc(sizeof(struct userdata));
583 m->userdata = u;
584 u->module = m;
585 u->core = c;
586 u->client = NULL;
587 u->pdispatch = NULL;
588 u->pstream = NULL;
589 u->server_name = NULL;
590 #ifdef TUNNEL_SINK
591 u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));;
592 u->sink = NULL;
593 u->requested_bytes = 0;
594 #else
595 u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));;
596 u->source = NULL;
597 #endif
598 u->ctag = 1;
599 u->device_index = u->channel = PA_INVALID_INDEX;
600 u->host_latency = 0;
601 u->auth_cookie_in_property = 0;
602 u->time_event = NULL;
603
604 if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
605 goto fail;
606
607 if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) {
608 pa_log(__FILE__": no server specified.\n");
609 goto fail;
610 }
611
612 ss = c->default_sample_spec;
613 if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
614 pa_log(__FILE__": invalid sample format specification\n");
615 goto fail;
616 }
617
618 if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) {
619 pa_log(__FILE__": failed to connect to server '%s'\n", u->server_name);
620 goto fail;
621 }
622
623 if (!u->client)
624 goto fail;
625
626 pa_socket_client_set_callback(u->client, on_connection, u);
627
628 #ifdef TUNNEL_SINK
629 if (!(u->sink = pa_sink_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) {
630 pa_log(__FILE__": failed to create sink.\n");
631 goto fail;
632 }
633
634 u->sink->notify = sink_notify;
635 u->sink->get_latency = sink_get_latency;
636 u->sink->userdata = u;
637 u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name);
638
639 pa_sink_set_owner(u->sink, m);
640 #else
641 if (!(u->source = pa_source_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) {
642 pa_log(__FILE__": failed to create source.\n");
643 goto fail;
644 }
645
646 u->source->get_latency = source_get_latency;
647 u->source->userdata = u;
648 u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name);
649
650 pa_source_set_owner(u->source, m);
651 #endif
652
653 gettimeofday(&ntv, NULL);
654 ntv.tv_sec += LATENCY_INTERVAL;
655 u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u);
656
657 pa_modargs_free(ma);
658
659 return 0;
660
661 fail:
662 pa__done(c, m);
663
664 if (ma)
665 pa_modargs_free(ma);
666 return -1;
667 }
668
669 void pa__done(struct pa_core *c, struct pa_module*m) {
670 struct userdata* u;
671 assert(c && m);
672
673 if (!(u = m->userdata))
674 return;
675
676 close_stuff(u);
677
678 if (u->auth_cookie_in_property)
679 pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME);
680
681 #ifdef TUNNEL_SINK
682 pa_xfree(u->sink_name);
683 #else
684 pa_xfree(u->source_name);
685 #endif
686 pa_xfree(u->server_name);
687
688 pa_xfree(u);
689 }
690
691