• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2006 Lennart Poettering
5   Copyright 2011 Canonical Ltd
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include <pulsecore/core.h>
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/device-port.h>
28 #include <pulsecore/hashmap.h>
29 
30 PA_MODULE_AUTHOR("David Henningsson");
31 PA_MODULE_DESCRIPTION("Switches ports and profiles when devices are plugged/unplugged");
32 PA_MODULE_LOAD_ONCE(true);
33 PA_MODULE_VERSION(PACKAGE_VERSION);
34 
35 struct card_info {
36     struct userdata *userdata;
37     pa_card *card;
38 
39     /* We need to cache the active profile, because we want to compare the old
40      * and new profiles in the PROFILE_CHANGED hook. Without this we'd only
41      * have access to the new profile. */
42     pa_card_profile *active_profile;
43 };
44 
45 struct userdata {
46     pa_hashmap *card_infos; /* pa_card -> struct card_info */
47 };
48 
card_info_new(struct userdata * u,pa_card * card)49 static void card_info_new(struct userdata *u, pa_card *card) {
50     struct card_info *info;
51 
52     info = pa_xnew0(struct card_info, 1);
53     info->userdata = u;
54     info->card = card;
55     info->active_profile = card->active_profile;
56 
57     pa_hashmap_put(u->card_infos, card, info);
58 }
59 
card_info_free(struct card_info * info)60 static void card_info_free(struct card_info *info) {
61     pa_hashmap_remove(info->userdata->card_infos, info->card);
62     pa_xfree(info);
63 }
64 
profile_good_for_output(pa_card_profile * profile,pa_device_port * port)65 static bool profile_good_for_output(pa_card_profile *profile, pa_device_port *port) {
66     pa_card *card;
67     pa_sink *sink;
68     uint32_t idx;
69 
70     pa_assert(profile);
71 
72     card = profile->card;
73 
74     if (!pa_safe_streq(card->active_profile->input_name, profile->input_name))
75         return false;
76 
77     if (card->active_profile->n_sources != profile->n_sources)
78         return false;
79 
80     if (card->active_profile->max_source_channels != profile->max_source_channels)
81         return false;
82 
83     if (port == card->preferred_output_port)
84         return true;
85 
86     PA_IDXSET_FOREACH(sink, card->sinks, idx) {
87         if (!sink->active_port)
88             continue;
89 
90         if ((sink->active_port->available != PA_AVAILABLE_NO) && (sink->active_port->priority >= port->priority))
91             return false;
92     }
93 
94     return true;
95 }
96 
profile_good_for_input(pa_card_profile * profile,pa_device_port * port)97 static bool profile_good_for_input(pa_card_profile *profile, pa_device_port *port) {
98     pa_card *card;
99     pa_source *source;
100     uint32_t idx;
101 
102     pa_assert(profile);
103 
104     card = profile->card;
105 
106     if (!pa_safe_streq(card->active_profile->output_name, profile->output_name))
107         return false;
108 
109     if (card->active_profile->n_sinks != profile->n_sinks)
110         return false;
111 
112     if (card->active_profile->max_sink_channels != profile->max_sink_channels)
113         return false;
114 
115     if (port == card->preferred_input_port)
116         return true;
117 
118     PA_IDXSET_FOREACH(source, card->sources, idx) {
119         if (!source->active_port)
120             continue;
121 
122         if ((source->active_port->available != PA_AVAILABLE_NO) && (source->active_port->priority >= port->priority))
123             return false;
124     }
125 
126     return true;
127 }
128 
try_to_switch_profile(pa_device_port * port)129 static int try_to_switch_profile(pa_device_port *port) {
130     pa_card_profile *best_profile = NULL, *profile;
131     void *state;
132     unsigned best_prio = 0;
133 
134     pa_log_debug("Finding best profile for port %s, preferred = %s",
135                  port->name, pa_strnull(port->preferred_profile));
136 
137     PA_HASHMAP_FOREACH(profile, port->profiles, state) {
138         bool good = false;
139         const char *name;
140         unsigned prio = profile->priority;
141 
142         /* We make a best effort to keep other direction unchanged */
143         switch (port->direction) {
144             case PA_DIRECTION_OUTPUT:
145                 name = profile->output_name;
146                 good = profile_good_for_output(profile, port);
147                 break;
148 
149             case PA_DIRECTION_INPUT:
150                 name = profile->input_name;
151                 good = profile_good_for_input(profile, port);
152                 break;
153         }
154 
155         if (!good)
156             continue;
157 
158         /* Give a high bonus in case this is the preferred profile */
159         if (pa_safe_streq(name ? name : profile->name, port->preferred_profile))
160             prio += 1000000;
161 
162         if (best_profile && best_prio >= prio)
163             continue;
164 
165         best_profile = profile;
166         best_prio = prio;
167     }
168 
169     if (!best_profile) {
170         pa_log_debug("No suitable profile found");
171         return -1;
172     }
173 
174     if (pa_card_set_profile(port->card, best_profile, false) != 0) {
175         pa_log_debug("Could not set profile %s", best_profile->name);
176         return -1;
177     }
178 
179     return 0;
180 }
181 
182 struct port_pointers {
183     pa_device_port *port;
184     pa_sink *sink;
185     pa_source *source;
186     bool is_possible_profile_active;
187     bool is_preferred_profile_active;
188     bool is_port_active;
189 };
190 
profile_name_for_dir(pa_card_profile * cp,pa_direction_t dir)191 static const char* profile_name_for_dir(pa_card_profile *cp, pa_direction_t dir) {
192     if (dir == PA_DIRECTION_OUTPUT && cp->output_name)
193         return cp->output_name;
194     if (dir == PA_DIRECTION_INPUT && cp->input_name)
195         return cp->input_name;
196     return cp->name;
197 }
198 
find_port_pointers(pa_device_port * port)199 static struct port_pointers find_port_pointers(pa_device_port *port) {
200     struct port_pointers pp = { .port = port };
201     uint32_t state;
202     pa_card *card;
203 
204     pa_assert(port);
205     pa_assert_se(card = port->card);
206 
207     switch (port->direction) {
208         case PA_DIRECTION_OUTPUT:
209             PA_IDXSET_FOREACH(pp.sink, card->sinks, state)
210                 if (port == pa_hashmap_get(pp.sink->ports, port->name))
211                     break;
212             break;
213 
214         case PA_DIRECTION_INPUT:
215             PA_IDXSET_FOREACH(pp.source, card->sources, state)
216                 if (port == pa_hashmap_get(pp.source->ports, port->name))
217                     break;
218             break;
219     }
220 
221     pp.is_possible_profile_active =
222         card->active_profile == pa_hashmap_get(port->profiles, card->active_profile->name);
223     pp.is_preferred_profile_active = pp.is_possible_profile_active && (!port->preferred_profile ||
224         pa_safe_streq(port->preferred_profile, profile_name_for_dir(card->active_profile, port->direction)));
225     pp.is_port_active = (pp.sink && pp.sink->active_port == port) || (pp.source && pp.source->active_port == port);
226 
227     return pp;
228 }
229 
230 /* Switches to a port, switching profiles if necessary or preferred */
switch_to_port(pa_device_port * port,struct port_pointers pp)231 static void switch_to_port(pa_device_port *port, struct port_pointers pp) {
232     if (pp.is_port_active)
233         return; /* Already selected */
234 
235     pa_log_debug("Trying to switch to port %s", port->name);
236     if (!pp.is_preferred_profile_active) {
237         if (try_to_switch_profile(port) < 0) {
238             if (!pp.is_possible_profile_active)
239                 return;
240         }
241         else
242             /* Now that profile has changed, our sink and source pointers must be updated */
243             pp = find_port_pointers(port);
244     }
245 
246     if (pp.source)
247         pa_source_set_port(pp.source, port->name, false);
248     if (pp.sink)
249         pa_sink_set_port(pp.sink, port->name, false);
250 }
251 
252 /* Switches away from a port, switching profiles if necessary or preferred */
switch_from_port(pa_device_port * port,struct port_pointers pp)253 static void switch_from_port(pa_device_port *port, struct port_pointers pp) {
254     pa_device_port *p, *best_port = NULL;
255     void *state;
256 
257     if (!pp.is_port_active)
258         return; /* Already deselected */
259 
260     /* Try to find a good enough port to switch to */
261     PA_HASHMAP_FOREACH(p, port->card->ports, state) {
262         if (p == port)
263             continue;
264 
265         if (p->available == PA_AVAILABLE_NO)
266             continue;
267 
268         if (p->direction != port->direction)
269             continue;
270 
271         if (!best_port || best_port->priority < p->priority)
272            best_port = p;
273     }
274 
275     pa_log_debug("Trying to switch away from port %s, found %s", port->name, best_port ? best_port->name : "no better option");
276 
277     /* If there is no available port to switch to we need check if the active
278      * profile is still available in the
279      * PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED callback, as at this point
280      * the profile availability hasn't been updated yet. */
281     if (best_port) {
282         struct port_pointers best_pp = find_port_pointers(best_port);
283         switch_to_port(best_port, best_pp);
284     }
285 }
286 
287 
port_available_hook_callback(pa_core * c,pa_device_port * port,void * userdata)288 static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port *port, void* userdata) {
289     struct port_pointers pp = find_port_pointers(port);
290 
291     if (!port->card) {
292         pa_log_warn("Port %s does not have a card", port->name);
293         return PA_HOOK_OK;
294     }
295 
296     /* Our profile switching logic caused trouble with bluetooth headsets (see
297      * https://bugs.freedesktop.org/show_bug.cgi?id=107044) and
298      * module-bluetooth-policy takes care of automatic profile switching
299      * anyway, so we ignore bluetooth cards in
300      * module-switch-on-port-available. */
301     if (pa_safe_streq(pa_proplist_gets(port->card->proplist, PA_PROP_DEVICE_BUS), "bluetooth"))
302         return PA_HOOK_OK;
303 
304     switch (port->available) {
305     case PA_AVAILABLE_UNKNOWN:
306         /* If a port availability became unknown, let's see if it's part of
307          * some availability group. If it is, it is likely to be a headphone
308          * jack that does not have impedance sensing to detect whether what was
309          * plugged in was a headphone, headset or microphone. In desktop
310          * environments that support it, this will trigger a user choice to
311          * select what kind of device was plugged in. However, let's switch to
312          * the headphone port at least, so that we have don't break
313          * functionality for setups that can't trigger this kind of
314          * interaction.
315          *
316          * For headset or microphone, if they are part of some availability group
317          * and they become unknown from off, it needs to check if their source is
318          * unlinked or not, if their source is unlinked, let switch_to_port()
319          * process them, then with the running of pa_card_set_profile(), their
320          * source will be created, otherwise the headset or microphone can't be used
321          * to record sound since there is no source for these 2 ports. This issue
322          * is observed on Dell machines which have multi-function audio jack but no
323          * internal mic.
324          *
325          * We should make this configurable so that users can optionally
326          * override the default to a headset or mic. */
327 
328         /* Not part of a group of ports, so likely not a combination port */
329         if (!port->availability_group) {
330             pa_log_debug("Not switching to port %s, its availability is unknown and it's not in any availability group.", port->name);
331             break;
332         }
333 
334         /* Switch the headphone port, the input ports without source and the
335          * input ports their source->active_port is part of a group of ports.
336          */
337         if (port->direction == PA_DIRECTION_INPUT && pp.source && !pp.source->active_port->availability_group) {
338             pa_log_debug("Not switching to input port %s, its availability is unknown.", port->name);
339             break;
340         }
341 
342         switch_to_port(port, pp);
343         break;
344 
345     case PA_AVAILABLE_YES:
346         switch_to_port(port, pp);
347         break;
348     case PA_AVAILABLE_NO:
349         switch_from_port(port, pp);
350         break;
351     default:
352         break;
353     }
354 
355     return PA_HOOK_OK;
356 }
357 
find_best_profile(pa_card * card)358 static pa_card_profile *find_best_profile(pa_card *card) {
359     pa_card_profile *profile, *best_profile;
360     void *state;
361 
362     pa_assert(card);
363     best_profile = pa_hashmap_get(card->profiles, "off");
364 
365     PA_HASHMAP_FOREACH(profile, card->profiles, state) {
366         if (profile->available == PA_AVAILABLE_NO)
367             continue;
368 
369         if (profile->priority > best_profile->priority)
370             best_profile = profile;
371     }
372 
373     return best_profile;
374 }
375 
card_profile_available_hook_callback(pa_core * c,pa_card_profile * profile,struct userdata * u)376 static pa_hook_result_t card_profile_available_hook_callback(pa_core *c, pa_card_profile *profile, struct userdata *u) {
377     pa_card *card;
378 
379     pa_assert(profile);
380     pa_assert_se(card = profile->card);
381 
382     if (profile->available != PA_AVAILABLE_NO)
383         return PA_HOOK_OK;
384 
385     if (!pa_streq(profile->name, card->active_profile->name))
386         return PA_HOOK_OK;
387 
388     pa_log_debug("Active profile %s on card %s became unavailable, switching to another profile", profile->name, card->name);
389     pa_card_set_profile(card, find_best_profile(card), false);
390 
391     return PA_HOOK_OK;
392 
393 }
394 
handle_all_unavailable(pa_core * core)395 static void handle_all_unavailable(pa_core *core) {
396     pa_card *card;
397     uint32_t state;
398 
399     PA_IDXSET_FOREACH(card, core->cards, state) {
400         pa_device_port *port;
401         void *state2;
402 
403         PA_HASHMAP_FOREACH(port, card->ports, state2) {
404             if (port->available == PA_AVAILABLE_NO)
405                 port_available_hook_callback(core, port, NULL);
406         }
407     }
408 }
409 
new_sink_source(pa_hashmap * ports,const char * name)410 static pa_device_port *new_sink_source(pa_hashmap *ports, const char *name) {
411 
412     void *state;
413     pa_device_port *i, *p = NULL;
414 
415     if (!ports)
416         return NULL;
417     if (name)
418         p = pa_hashmap_get(ports, name);
419     if (!p)
420         PA_HASHMAP_FOREACH(i, ports, state)
421             if (!p || i->priority > p->priority)
422                 p = i;
423     if (!p)
424         return NULL;
425     if (p->available != PA_AVAILABLE_NO)
426         return NULL;
427 
428     pa_assert_se(p = pa_device_port_find_best(ports));
429     return p;
430 }
431 
sink_new_hook_callback(pa_core * c,pa_sink_new_data * new_data,void * u)432 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, void *u) {
433 
434     pa_device_port *p = new_sink_source(new_data->ports, new_data->active_port);
435 
436     if (p) {
437         pa_log_debug("Switching initial port for sink '%s' to '%s'", new_data->name, p->name);
438         pa_sink_new_data_set_port(new_data, p->name);
439     }
440     return PA_HOOK_OK;
441 }
442 
source_new_hook_callback(pa_core * c,pa_source_new_data * new_data,void * u)443 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, void *u) {
444 
445     pa_device_port *p = new_sink_source(new_data->ports, new_data->active_port);
446 
447     if (p) {
448         pa_log_debug("Switching initial port for source '%s' to '%s'", new_data->name, p->name);
449         pa_source_new_data_set_port(new_data, p->name);
450     }
451     return PA_HOOK_OK;
452 }
453 
card_put_hook_callback(pa_core * core,pa_card * card,struct userdata * u)454 static pa_hook_result_t card_put_hook_callback(pa_core *core, pa_card *card, struct userdata *u) {
455     card_info_new(u, card);
456 
457     return PA_HOOK_OK;
458 }
459 
card_unlink_hook_callback(pa_core * core,pa_card * card,struct userdata * u)460 static pa_hook_result_t card_unlink_hook_callback(pa_core *core, pa_card *card, struct userdata *u) {
461     card_info_free(pa_hashmap_get(u->card_infos, card));
462 
463     return PA_HOOK_OK;
464 }
465 
update_preferred_input_port(pa_card * card,pa_card_profile * old_profile,pa_card_profile * new_profile)466 static void update_preferred_input_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) {
467     pa_source *source;
468 
469     /* If the profile change didn't affect input, it doesn't indicate change in
470      * the user's input port preference. */
471     if (pa_safe_streq(old_profile->input_name, new_profile->input_name))
472         return;
473 
474     /* If there are more than one source, we don't know which of those the user
475      * prefers. If there are no sources, then the user doesn't seem to care
476      * about input at all. */
477     if (pa_idxset_size(card->sources) != 1) {
478         pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL);
479         return;
480     }
481 
482     /* If the profile change modified the set of sinks, then it's unclear
483      * whether the user wanted to activate some specific input port, or was the
484      * input change only a side effect of activating some output. If the new
485      * profile contains no sinks, though, then we know the user only cares
486      * about input. */
487     if (pa_idxset_size(card->sinks) > 0 && !pa_safe_streq(old_profile->output_name, new_profile->output_name)) {
488         pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL);
489         return;
490     }
491 
492     source = pa_idxset_first(card->sources, NULL);
493 
494     /* We know the user wanted to activate this source. The user might not have
495      * wanted to activate the port that was selected by default, but if that's
496      * the case, the user will change the port manually, and we'll update the
497      * port preference at that time. If no port change occurs, we can assume
498      * that the user likes the port that is now active. */
499     pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, source->active_port);
500 }
501 
update_preferred_output_port(pa_card * card,pa_card_profile * old_profile,pa_card_profile * new_profile)502 static void update_preferred_output_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) {
503     pa_sink *sink;
504 
505     /* If the profile change didn't affect output, it doesn't indicate change in
506      * the user's output port preference. */
507     if (pa_safe_streq(old_profile->output_name, new_profile->output_name))
508         return;
509 
510     /* If there are more than one sink, we don't know which of those the user
511      * prefers. If there are no sinks, then the user doesn't seem to care about
512      * output at all. */
513     if (pa_idxset_size(card->sinks) != 1) {
514         pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL);
515         return;
516     }
517 
518     /* If the profile change modified the set of sources, then it's unclear
519      * whether the user wanted to activate some specific output port, or was
520      * the output change only a side effect of activating some input. If the
521      * new profile contains no sources, though, then we know the user only
522      * cares about output. */
523     if (pa_idxset_size(card->sources) > 0 && !pa_safe_streq(old_profile->input_name, new_profile->input_name)) {
524         pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL);
525         return;
526     }
527 
528     sink = pa_idxset_first(card->sinks, NULL);
529 
530     /* We know the user wanted to activate this sink. The user might not have
531      * wanted to activate the port that was selected by default, but if that's
532      * the case, the user will change the port manually, and we'll update the
533      * port preference at that time. If no port change occurs, we can assume
534      * that the user likes the port that is now active. */
535     pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, sink->active_port);
536 }
537 
card_profile_changed_callback(pa_core * core,pa_card * card,struct userdata * u)538 static pa_hook_result_t card_profile_changed_callback(pa_core *core, pa_card *card, struct userdata *u) {
539     struct card_info *info;
540     pa_card_profile *old_profile;
541     pa_card_profile *new_profile;
542 
543     info = pa_hashmap_get(u->card_infos, card);
544     old_profile = info->active_profile;
545     new_profile = card->active_profile;
546     info->active_profile = new_profile;
547 
548     /* This profile change wasn't initiated by the user, so it doesn't signal
549      * a change in the user's port preferences. */
550     if (!card->save_profile)
551         return PA_HOOK_OK;
552 
553     update_preferred_input_port(card, old_profile, new_profile);
554     update_preferred_output_port(card, old_profile, new_profile);
555 
556     return PA_HOOK_OK;
557 }
558 
source_port_changed_callback(pa_core * core,pa_source * source,void * userdata)559 static pa_hook_result_t source_port_changed_callback(pa_core *core, pa_source *source, void *userdata) {
560     if (!source->save_port)
561         return PA_HOOK_OK;
562 
563     pa_card_set_preferred_port(source->card, PA_DIRECTION_INPUT, source->active_port);
564 
565     return PA_HOOK_OK;
566 }
567 
sink_port_changed_callback(pa_core * core,pa_sink * sink,void * userdata)568 static pa_hook_result_t sink_port_changed_callback(pa_core *core, pa_sink *sink, void *userdata) {
569     if (!sink->save_port)
570         return PA_HOOK_OK;
571 
572     pa_card_set_preferred_port(sink->card, PA_DIRECTION_OUTPUT, sink->active_port);
573 
574     return PA_HOOK_OK;
575 }
576 
pa__init(pa_module * m)577 int pa__init(pa_module*m) {
578     struct userdata *u;
579     pa_card *card;
580     uint32_t idx;
581 
582     pa_assert(m);
583 
584     u = m->userdata = pa_xnew0(struct userdata, 1);
585     u->card_infos = pa_hashmap_new(NULL, NULL);
586 
587     PA_IDXSET_FOREACH(card, m->core->cards, idx)
588         card_info_new(u, card);
589 
590     /* Make sure we are after module-device-restore, so we can overwrite that suggestion if necessary */
591     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_NEW],
592                            PA_HOOK_NORMAL, (pa_hook_cb_t) sink_new_hook_callback, NULL);
593     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_NEW],
594                            PA_HOOK_NORMAL, (pa_hook_cb_t) source_new_hook_callback, NULL);
595     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED],
596                            PA_HOOK_LATE, (pa_hook_cb_t) port_available_hook_callback, NULL);
597     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED],
598                            PA_HOOK_LATE, (pa_hook_cb_t) card_profile_available_hook_callback, NULL);
599     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PUT],
600                            PA_HOOK_NORMAL, (pa_hook_cb_t) card_put_hook_callback, u);
601     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_UNLINK],
602                            PA_HOOK_NORMAL, (pa_hook_cb_t) card_unlink_hook_callback, u);
603     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED],
604                            PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u);
605     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED],
606                            PA_HOOK_NORMAL, (pa_hook_cb_t) source_port_changed_callback, NULL);
607     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED],
608                            PA_HOOK_NORMAL, (pa_hook_cb_t) sink_port_changed_callback, NULL);
609 
610     handle_all_unavailable(m->core);
611 
612     return 0;
613 }
614 
pa__done(pa_module * module)615 void pa__done(pa_module *module) {
616     struct userdata *u;
617     struct card_info *info;
618 
619     pa_assert(module);
620 
621     if (!(u = module->userdata))
622         return;
623 
624     while ((info = pa_hashmap_last(u->card_infos)))
625         card_info_free(info);
626 
627     pa_hashmap_free(u->card_infos);
628 
629     pa_xfree(u);
630 }
631