sink,source: Add a helper function to check whether this is a filter
[platform/upstream/pulseaudio.git] / src / modules / module-filter-apply.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2011 Colin Guthrie
5
6   PulseAudio 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.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio 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 PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <pulse/timeval.h>
25 #include <pulse/rtclock.h>
26 #include <pulse/xmalloc.h>
27
28 #include <pulsecore/core.h>
29 #include <pulsecore/core-util.h>
30 #include <pulsecore/i18n.h>
31 #include <pulsecore/macro.h>
32 #include <pulsecore/hashmap.h>
33 #include <pulsecore/hook-list.h>
34 #include <pulsecore/sink-input.h>
35 #include <pulsecore/modargs.h>
36 #include <pulsecore/proplist-util.h>
37
38 #include "module-filter-apply-symdef.h"
39
40 #define PA_PROP_FILTER_APPLY_MOVING "filter.apply.moving"
41
42 PA_MODULE_AUTHOR("Colin Guthrie");
43 PA_MODULE_DESCRIPTION("Load filter sinks automatically when needed");
44 PA_MODULE_VERSION(PACKAGE_VERSION);
45 PA_MODULE_LOAD_ONCE(true);
46 PA_MODULE_USAGE(_("autoclean=<automatically unload unused filters?>"));
47
48 static const char* const valid_modargs[] = {
49     "autoclean",
50     NULL
51 };
52
53 #define DEFAULT_AUTOCLEAN true
54 #define HOUSEKEEPING_INTERVAL (10 * PA_USEC_PER_SEC)
55
56 struct filter {
57     char *name;
58     uint32_t module_index;
59     pa_sink *sink;
60     pa_sink *sink_master;
61     pa_source *source;
62     pa_source *source_master;
63 };
64
65 struct userdata {
66     pa_core *core;
67     pa_hashmap *filters;
68     bool autoclean;
69     pa_time_event *housekeeping_time_event;
70 };
71
72 static unsigned filter_hash(const void *p) {
73     const struct filter *f = p;
74
75     if (f->sink_master && !f->source_master)
76         return (unsigned) (f->sink_master->index + pa_idxset_string_hash_func(f->name));
77     else if (!f->sink_master && f->source_master)
78         return (unsigned) ((f->source_master->index << 16) + pa_idxset_string_hash_func(f->name));
79     else
80         return (unsigned) (f->sink_master->index + (f->source_master->index << 16) + pa_idxset_string_hash_func(f->name));
81 }
82
83 static int filter_compare(const void *a, const void *b) {
84     const struct filter *fa = a, *fb = b;
85     int r;
86
87     if (fa->sink_master != fb->sink_master || fa->source_master != fb->source_master)
88         return 1;
89     if ((r = strcmp(fa->name, fb->name)))
90         return r;
91
92     return 0;
93 }
94
95 static struct filter *filter_new(const char *name, pa_sink *sink, pa_source *source) {
96     struct filter *f;
97
98     pa_assert(sink || source);
99
100     f = pa_xnew(struct filter, 1);
101     f->name = pa_xstrdup(name);
102     f->sink_master = sink;
103     f->source_master = source;
104     f->module_index = PA_INVALID_INDEX;
105     f->sink = NULL;
106     f->source = NULL;
107
108     return f;
109 }
110
111 static void filter_free(struct filter *f) {
112     pa_assert(f);
113
114     pa_xfree(f->name);
115     pa_xfree(f);
116 }
117
118 static const char* should_filter(pa_object *o, bool is_sink_input) {
119     const char *apply;
120     pa_proplist *pl;
121
122     if (is_sink_input)
123         pl = PA_SINK_INPUT(o)->proplist;
124     else
125         pl = PA_SOURCE_OUTPUT(o)->proplist;
126
127     /* If the stream doesn't what any filter, then let it be. */
128     if ((apply = pa_proplist_gets(pl, PA_PROP_FILTER_APPLY)) && !pa_streq(apply, "")) {
129         const char* suppress = pa_proplist_gets(pl, PA_PROP_FILTER_SUPPRESS);
130
131         if (!suppress || !pa_streq(suppress, apply))
132             return apply;
133     }
134
135     return NULL;
136 }
137
138 static bool should_group_filter(struct filter *filter) {
139     return pa_streq(filter->name, "echo-cancel");
140 }
141
142 static char* get_group(pa_object *o, bool is_sink_input) {
143     pa_proplist *pl;
144
145     if (is_sink_input)
146         pl = PA_SINK_INPUT(o)->proplist;
147     else
148         pl = PA_SOURCE_OUTPUT(o)->proplist;
149
150     /* There's a bit of cleverness here -- the second argument ensures that we
151      * only group streams that require the same filter */
152     return pa_proplist_get_stream_group(pl, pa_proplist_gets(pl, PA_PROP_FILTER_APPLY), NULL);
153 }
154
155 /* For filters that apply on a source-output/sink-input pair, this finds the
156  * master sink if we know the master source, or vice versa. It does this by
157  * looking up streams that belong to the same stream group as the original
158  * object. The idea is that streams from the sam group are always routed
159  * together. */
160 static bool find_paired_master(struct userdata *u, struct filter *filter, pa_object *o, bool is_sink_input) {
161     char *group;
162
163     if ((group = get_group(o, is_sink_input))) {
164         uint32_t idx;
165         char *g;
166         char *module_name = pa_sprintf_malloc("module-%s", filter->name);
167
168         if (is_sink_input) {
169             pa_source_output *so;
170
171             PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
172                 g = get_group(PA_OBJECT(so), false);
173
174                 if (pa_streq(g, group)) {
175                     if (pa_streq(module_name, so->source->module->name)) {
176                         /* Make sure we're not routing to another instance of
177                          * the same filter. */
178                         filter->source_master = so->source->output_from_master->source;
179                     } else {
180                         filter->source_master = so->source;
181                     }
182
183                     pa_xfree(g);
184                     break;
185                 }
186
187                 pa_xfree (g);
188             }
189         } else {
190             pa_sink_input *si;
191
192             PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
193                 g = get_group(PA_OBJECT(si), true);
194
195                 if (pa_streq(g, group)) {
196                     if (pa_streq(module_name, si->sink->module->name)) {
197                         /* Make sure we're not routing to another instance of
198                          * the same filter. */
199                         filter->sink_master = si->sink->input_to_master->sink;
200                     } else {
201                         filter->sink_master = si->sink;
202                     }
203
204                     pa_xfree(g);
205                     break;
206                 }
207
208                 pa_xfree(g);
209             }
210         }
211
212         pa_xfree(group);
213         pa_xfree(module_name);
214
215         if (!filter->sink_master || !filter->source_master)
216             return false;
217     }
218
219     return true;
220 }
221
222 static bool nothing_attached(struct filter *f) {
223     bool no_si = true, no_so = true;
224
225     if (f->sink)
226         no_si = pa_idxset_isempty(f->sink->inputs);
227     if (f->source)
228         no_so = pa_idxset_isempty(f->source->outputs);
229
230     return no_si && no_so;
231 }
232
233 static void housekeeping_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
234     struct userdata *u = userdata;
235     struct filter *filter;
236     void *state;
237
238     pa_assert(a);
239     pa_assert(e);
240     pa_assert(u);
241
242     pa_assert(e == u->housekeeping_time_event);
243     u->core->mainloop->time_free(u->housekeeping_time_event);
244     u->housekeeping_time_event = NULL;
245
246     PA_HASHMAP_FOREACH(filter, u->filters, state) {
247         if (nothing_attached(filter)) {
248             uint32_t idx;
249
250             pa_log_debug("Detected filter %s as no longer used. Unloading.", filter->name);
251             idx = filter->module_index;
252             pa_hashmap_remove(u->filters, filter);
253             filter_free(filter);
254             pa_module_unload_request_by_index(u->core, idx, true);
255         }
256     }
257
258     pa_log_info("Housekeeping Done.");
259 }
260
261 static void trigger_housekeeping(struct userdata *u) {
262     pa_assert(u);
263
264     if (!u->autoclean)
265         return;
266
267     if (u->housekeeping_time_event)
268         return;
269
270     u->housekeeping_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + HOUSEKEEPING_INTERVAL, housekeeping_time_callback, u);
271 }
272
273 static int do_move(pa_object *obj, pa_object *parent, bool restore, bool is_input) {
274     if (is_input)
275         return pa_sink_input_move_to(PA_SINK_INPUT(obj), PA_SINK(parent), restore);
276     else
277         return pa_source_output_move_to(PA_SOURCE_OUTPUT(obj), PA_SOURCE(parent), restore);
278 }
279
280 static void move_object_for_filter(pa_object *o, struct filter* filter, bool restore, bool is_sink_input) {
281     pa_object *parent;
282     pa_proplist *pl;
283     const char *name;
284
285     pa_assert(o);
286     pa_assert(filter);
287
288     if (is_sink_input) {
289         pl = PA_SINK_INPUT(o)->proplist;
290         parent = PA_OBJECT(restore ? filter->sink_master : filter->sink);
291         if (!parent)
292             return;
293         name = PA_SINK(parent)->name;
294     } else {
295         pl = PA_SOURCE_OUTPUT(o)->proplist;
296         parent = PA_OBJECT(restore ? filter->source_master : filter->source);
297         if (!parent)
298             return;
299         name = PA_SOURCE(parent)->name;
300     }
301
302     pa_proplist_sets(pl, PA_PROP_FILTER_APPLY_MOVING, "1");
303
304     if (do_move(o, parent, false, is_sink_input) < 0)
305         pa_log_info("Failed to move %s for \"%s\" to <%s>.", is_sink_input ? "sink-input" : "source-output",
306                     pa_strnull(pa_proplist_gets(pl, PA_PROP_APPLICATION_NAME)), name);
307     else
308         pa_log_info("Successfully moved %s for \"%s\" to <%s>.", is_sink_input ? "sink-input" : "source-output",
309                     pa_strnull(pa_proplist_gets(pl, PA_PROP_APPLICATION_NAME)), name);
310
311     pa_proplist_unset(pl, PA_PROP_FILTER_APPLY_MOVING);
312 }
313
314 static void move_objects_for_filter(struct userdata *u, pa_object *o, struct filter* filter, bool restore,
315         bool is_sink_input) {
316
317     if (!should_group_filter(filter))
318         move_object_for_filter(o, filter, restore, is_sink_input);
319     else {
320         pa_source_output *so;
321         pa_sink_input *si;
322         char *g, *group;
323         uint32_t idx;
324
325         group = get_group(o, is_sink_input);
326
327         PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
328             g = get_group(PA_OBJECT(so), false);
329
330             if (pa_streq(g, group))
331                 move_object_for_filter(PA_OBJECT(so), filter, restore, false);
332
333             pa_xfree(g);
334         }
335
336         PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
337             g = get_group(PA_OBJECT(si), true);
338
339             if (pa_streq(g, group))
340                 move_object_for_filter(PA_OBJECT(si), filter, restore, true);
341
342             pa_xfree(g);
343         }
344
345         pa_xfree(group);
346     }
347 }
348
349 /* Note that we assume a filter will provide at most one sink and at most one
350  * source (and at least one of either). */
351 static void find_filters_for_module(struct userdata *u, pa_module *m, const char *name) {
352     uint32_t idx;
353     pa_sink *sink;
354     pa_source *source;
355     struct filter *fltr = NULL;
356
357     PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
358         if (sink->module == m) {
359             pa_assert(pa_sink_is_filter(sink));
360
361             fltr = filter_new(name, sink->input_to_master->sink, NULL);
362             fltr->module_index = m->index;
363             fltr->sink = sink;
364
365             break;
366         }
367     }
368
369     PA_IDXSET_FOREACH(source, u->core->sources, idx) {
370         if (source->module == m && !source->monitor_of) {
371             pa_assert(pa_source_is_filter(source));
372
373             if (!fltr) {
374                 fltr = filter_new(name, NULL, source->output_from_master->source);
375                 fltr->module_index = m->index;
376                 fltr->source = source;
377             } else {
378                 fltr->source = source;
379                 fltr->source_master = source->output_from_master->source;
380             }
381
382             break;
383         }
384     }
385
386     pa_hashmap_put(u->filters, fltr, fltr);
387 }
388
389 static bool can_unload_module(struct userdata *u, uint32_t idx) {
390     void *state;
391     struct filter *filter;
392
393     /* Check if any other struct filters point to the same module */
394     PA_HASHMAP_FOREACH(filter, u->filters, state) {
395         if (filter->module_index == idx && !nothing_attached(filter))
396             return false;
397     }
398
399     return true;
400 }
401
402 static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_input) {
403     const char *want;
404     bool done_something = false;
405     pa_sink *sink = NULL;
406     pa_source *source = NULL;
407     pa_module *module = NULL;
408
409     if (is_sink_input) {
410         sink = PA_SINK_INPUT(o)->sink;
411
412         if (sink)
413             module = sink->module;
414     } else {
415         source = PA_SOURCE_OUTPUT(o)->source;
416
417         if (source)
418             module = source->module;
419     }
420
421     /* If there is no sink/source yet, we can't do much */
422     if ((is_sink_input && !sink) || (!is_sink_input && !source))
423         return PA_HOOK_OK;
424
425     /* If the stream doesn't what any filter, then let it be. */
426     if ((want = should_filter(o, is_sink_input))) {
427         char *module_name;
428         struct filter *fltr, *filter;
429
430         /* We need to ensure the SI is playing on a sink of this type
431          * attached to the sink it's "officially" playing on */
432
433         if (!module)
434             return PA_HOOK_OK;
435
436         module_name = pa_sprintf_malloc("module-%s", want);
437         if (pa_streq(module->name, module_name)) {
438             pa_log_debug("Stream appears to be playing on an appropriate sink already. Ignoring.");
439             pa_xfree(module_name);
440             return PA_HOOK_OK;
441         }
442
443         fltr = filter_new(want, sink, source);
444
445         if (should_group_filter(fltr) && !find_paired_master(u, fltr, o, is_sink_input)) {
446             pa_log_debug("Want group filtering but don't have enough streams.");
447             return PA_HOOK_OK;
448         }
449
450         if (!(filter = pa_hashmap_get(u->filters, fltr))) {
451             char *args;
452             pa_module *m;
453
454             args = pa_sprintf_malloc("autoloaded=1 %s%s %s%s",
455                     fltr->sink_master ? "sink_master=" : "",
456                     fltr->sink_master ? fltr->sink_master->name : "",
457                     fltr->source_master ? "source_master=" : "",
458                     fltr->source_master ? fltr->source_master->name : "");
459
460             pa_log_debug("Loading %s with arguments '%s'", module_name, args);
461
462             if ((m = pa_module_load(u->core, module_name, args))) {
463                 find_filters_for_module(u, m, want);
464                 filter = pa_hashmap_get(u->filters, fltr);
465                 done_something = true;
466             }
467             pa_xfree(args);
468         }
469
470         pa_xfree(fltr);
471
472         if (!filter) {
473             pa_log("Unable to load %s", module_name);
474             pa_xfree(module_name);
475             return PA_HOOK_OK;
476         }
477         pa_xfree(module_name);
478
479         /* We can move the stream now as we know the destination. If this
480          * isn't true, we will do it later when the sink appears. */
481         if ((is_sink_input && filter->sink) || (!is_sink_input && filter->source)) {
482             move_objects_for_filter(u, o, filter, false, is_sink_input);
483             done_something = true;
484         }
485     } else {
486         void *state;
487         struct filter *filter = NULL;
488
489         /* We do not want to filter... but are we already filtered?
490          * This can happen if an input's proplist changes */
491         PA_HASHMAP_FOREACH(filter, u->filters, state) {
492             if ((is_sink_input && sink == filter->sink) || (!is_sink_input && source == filter->source)) {
493                 move_objects_for_filter(u, o, filter, true, is_sink_input);
494                 done_something = true;
495                 break;
496             }
497         }
498     }
499
500     if (done_something)
501         trigger_housekeeping(u);
502
503     return PA_HOOK_OK;
504 }
505
506 static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
507     pa_core_assert_ref(core);
508     pa_sink_input_assert_ref(i);
509
510     return process(u, PA_OBJECT(i), true);
511 }
512
513 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
514     pa_core_assert_ref(core);
515     pa_sink_input_assert_ref(i);
516
517     if (pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY_MOVING))
518         return PA_HOOK_OK;
519
520     return process(u, PA_OBJECT(i), true);
521 }
522
523 static pa_hook_result_t sink_input_proplist_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
524     pa_core_assert_ref(core);
525     pa_sink_input_assert_ref(i);
526
527     return process(u, PA_OBJECT(i), true);
528 }
529
530 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
531     pa_core_assert_ref(core);
532     pa_sink_input_assert_ref(i);
533
534     pa_assert(u);
535
536     if (pa_hashmap_size(u->filters) > 0)
537         trigger_housekeeping(u);
538
539     return PA_HOOK_OK;
540 }
541
542 static pa_hook_result_t sink_unlink_cb(pa_core *core, pa_sink *sink, struct userdata *u) {
543     void *state;
544     struct filter *filter = NULL;
545
546     pa_core_assert_ref(core);
547     pa_sink_assert_ref(sink);
548     pa_assert(u);
549
550     /* If either the parent or the sink we've loaded disappears,
551      * we should remove it from our hashmap */
552     PA_HASHMAP_FOREACH(filter, u->filters, state) {
553         if (filter->sink_master == sink || filter->sink == sink) {
554             uint32_t idx;
555
556             /* Attempt to rescue any streams to the parent sink as this is likely
557              * the best course of action (as opposed to a generic rescue via
558              * module-rescue-streams */
559             if (filter->sink == sink) {
560                 pa_sink_input *i;
561
562                 PA_IDXSET_FOREACH(i, sink->inputs, idx)
563                     move_objects_for_filter(u, PA_OBJECT(i), filter, true, true);
564             }
565
566             idx = filter->module_index;
567             pa_hashmap_remove(u->filters, filter);
568             filter_free(filter);
569
570             if (can_unload_module(u, idx))
571                 pa_module_unload_request_by_index(u->core, idx, true);
572         }
573     }
574
575     return PA_HOOK_OK;
576 }
577
578 static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
579     pa_core_assert_ref(core);
580     pa_source_output_assert_ref(o);
581
582     return process(u, PA_OBJECT(o), false);
583 }
584
585 static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
586     pa_core_assert_ref(core);
587     pa_source_output_assert_ref(o);
588
589     if (pa_proplist_gets(o->proplist, PA_PROP_FILTER_APPLY_MOVING))
590         return PA_HOOK_OK;
591
592     return process(u, PA_OBJECT(o), false);
593 }
594
595 static pa_hook_result_t source_output_proplist_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
596     pa_core_assert_ref(core);
597     pa_source_output_assert_ref(o);
598
599     return process(u, PA_OBJECT(o), false);
600 }
601
602 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
603     pa_core_assert_ref(core);
604     pa_source_output_assert_ref(o);
605
606     pa_assert(u);
607
608     if (pa_hashmap_size(u->filters) > 0)
609         trigger_housekeeping(u);
610
611     return PA_HOOK_OK;
612 }
613
614 static pa_hook_result_t source_unlink_cb(pa_core *core, pa_source *source, struct userdata *u) {
615     void *state;
616     struct filter *filter = NULL;
617
618     pa_core_assert_ref(core);
619     pa_source_assert_ref(source);
620     pa_assert(u);
621
622     /* If either the parent or the source we've loaded disappears,
623      * we should remove it from our hashmap */
624     PA_HASHMAP_FOREACH(filter, u->filters, state) {
625         if (filter->source_master == source || filter->source == source) {
626             uint32_t idx;
627
628             /* Attempt to rescue any streams to the parent source as this is likely
629              * the best course of action (as opposed to a generic rescue via
630              * module-rescue-streams */
631             if (filter->source == source) {
632                 pa_source_output *o;
633
634                 PA_IDXSET_FOREACH(o, source->outputs, idx)
635                     move_objects_for_filter(u, PA_OBJECT(o), filter, true, false);
636             }
637
638             idx = filter->module_index;
639             pa_hashmap_remove(u->filters, filter);
640             filter_free(filter);
641
642             if (can_unload_module(u, idx))
643                 pa_module_unload_request_by_index(u->core, idx, true);
644         }
645     }
646
647     return PA_HOOK_OK;
648 }
649
650 int pa__init(pa_module *m) {
651     pa_modargs *ma = NULL;
652     struct userdata *u;
653
654     pa_assert(m);
655
656     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
657         pa_log("Failed to parse module arguments");
658         goto fail;
659     }
660
661     m->userdata = u = pa_xnew0(struct userdata, 1);
662
663     u->core = m->core;
664
665     u->autoclean = DEFAULT_AUTOCLEAN;
666     if (pa_modargs_get_value_boolean(ma, "autoclean", &u->autoclean) < 0) {
667         pa_log("Failed to parse autoclean value");
668         goto fail;
669     }
670
671     u->filters = pa_hashmap_new(filter_hash, filter_compare);
672
673     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_put_cb, u);
674     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_finish_cb, u);
675     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_proplist_cb, u);
676     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_unlink_cb, u);
677     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE-1, (pa_hook_cb_t) sink_unlink_cb, u);
678     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) source_output_put_cb, u);
679     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_LATE, (pa_hook_cb_t) source_output_move_finish_cb, u);
680     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) source_output_proplist_cb, u);
681     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_output_unlink_cb, u);
682     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE-1, (pa_hook_cb_t) source_unlink_cb, u);
683
684     pa_modargs_free(ma);
685
686     return 0;
687
688 fail:
689     pa__done(m);
690
691     if (ma)
692         pa_modargs_free(ma);
693
694     return -1;
695 }
696
697 void pa__done(pa_module *m) {
698     struct userdata* u;
699
700     pa_assert(m);
701
702     if (!(u = m->userdata))
703         return;
704
705     if (u->housekeeping_time_event)
706         u->core->mainloop->time_free(u->housekeeping_time_event);
707
708     if (u->filters) {
709         struct filter *f;
710
711         while ((f = pa_hashmap_steal_first(u->filters))) {
712             pa_module_unload_request_by_index(u->core, f->module_index, true);
713             filter_free(f);
714         }
715
716         pa_hashmap_free(u->filters);
717     }
718
719     pa_xfree(u);
720 }