3 #include <pulsecore/pulsecore-config.h>
5 #include <pulsecore/hashmap.h>
6 #include <pulsecore/idxset.h>
7 #include <pulsecore/client.h>
8 #include <pulsecore/core-util.h>
9 #include <pulsecore/log.h>
10 #include <pulsecore/card.h>
11 #include <pulsecore/device-port.h>
12 #include <pulsecore/sink-input.h>
13 #include <pulsecore/source-output.h>
14 #include <pulsecore/strbuf.h>
21 #include "multiplex.h"
25 #define MAX_CARD_TARGET 4
26 #define MAX_NAME_LENGTH 256
33 static const char combine_pattern[] = "Simultaneous output on ";
35 static void handle_alsa_card(struct userdata *, pa_card *);
36 static void handle_bluetooth_card(struct userdata *, pa_card *);
38 static void handle_udev_loaded_card(struct userdata *, pa_card *,
40 static void handle_card_ports(struct userdata *, mir_node *,
41 pa_card *, pa_card_profile *);
43 static mir_node *create_node(struct userdata *, mir_node *, pa_bool_t *);
44 static void destroy_node(struct userdata *, mir_node *);
46 static void parse_profile_name(pa_card_profile *,
47 char **, char **, char *, int);
49 static char *node_key_from_card(struct userdata *, mir_direction,
50 void *, char *, size_t);
52 static pa_sink *make_output_prerouting(struct userdata *, mir_node *,
53 pa_channel_map *, mir_node **);
55 static mir_node_type get_stream_routing_class(pa_proplist *);
58 static void schedule_deferred_routing(struct userdata *);
59 static void schedule_card_check(struct userdata *, pa_card *);
62 static void pa_hashmap_node_free(void *node, void *u)
64 mir_node_destroy(u, node);
68 struct pa_discover *pa_discover_init(struct userdata *u)
70 pa_discover *discover = pa_xnew0(pa_discover, 1);
74 discover->selected = TRUE;
76 discover->nodes.byname = pa_hashmap_new(pa_idxset_string_hash_func,
77 pa_idxset_string_compare_func);
78 discover->nodes.byptr = pa_hashmap_new(pa_idxset_trivial_hash_func,
79 pa_idxset_trivial_compare_func);
83 void pa_discover_done(struct userdata *u)
85 pa_discover *discover;
87 if (u && (discover = u->discover)) {
88 pa_hashmap_free(discover->nodes.byname, pa_hashmap_node_free,u);
89 pa_hashmap_free(discover->nodes.byptr, NULL,NULL);
95 void pa_discover_domain_up(struct userdata *u)
97 pa_discover *discover;
102 pa_assert_se((discover = u->discover));
104 PA_HASHMAP_FOREACH(node, discover->nodes.byname, state) {
105 node->amid = AM_ID_INVALID;
107 if (node->visible && node->available)
108 pa_audiomgr_register_node(u, node);
112 void pa_discover_domain_down(struct userdata *u)
116 void pa_discover_add_card(struct userdata *u, pa_card *card)
123 if (!(bus = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_BUS))) {
124 pa_log_debug("ignoring card '%s' due to lack of '%s' property",
125 pa_utils_get_card_name(card), PA_PROP_DEVICE_BUS);
129 if (pa_streq(bus, "pci") || pa_streq(bus, "usb")) {
130 handle_alsa_card(u, card);
133 else if (pa_streq(bus, "bluetooth")) {
134 handle_bluetooth_card(u, card);
138 pa_log_debug("ignoring card '%s' due to unsupported bus type '%s'",
139 pa_utils_get_card_name(card), bus);
142 void pa_discover_remove_card(struct userdata *u, pa_card *card)
144 pa_discover *discover;
150 pa_assert_se((discover = u->discover));
152 PA_HASHMAP_FOREACH(node, discover->nodes.byname, state) {
153 if (node->implement == mir_device &&
154 node->pacard.index == card->index)
156 destroy_node(u, node);
161 void pa_discover_profile_changed(struct userdata *u, pa_card *card)
163 pa_card_profile *prof;
164 pa_discover *discover;
175 pa_assert_se((discover = u->discover));
178 if ((bus = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_BUS)) == NULL) {
179 pa_log_debug("ignoring profile change on card '%s' due to lack of '%s'"
180 "property", pa_utils_get_card_name(card),
185 pci = pa_streq(bus, "pci");
186 usb = pa_streq(bus, "usb");
187 bluetooth = pa_streq(bus, "bluetooth");
189 if (!pci && !usb && !bluetooth) {
190 pa_log_debug("ignoring profile change on card '%s' due to unsupported "
191 "bus type '%s'", pa_utils_get_card_name(card), bus);
195 pa_assert_se((prof = card->active_profile));
197 pa_log_debug("bluetooth profile changed to '%s' on card '%s'",
198 prof->name, card->name);
200 if (!prof->n_sinks && !prof->n_sources) {
201 /* switched of but not unloaded yet */
202 PA_HASHMAP_FOREACH(node, discover->nodes.byname, state) {
203 if (node->implement == mir_device &&
204 node->pacard.index == card->index)
206 node->available = FALSE;
212 pa_log_debug("alsa profile changed to '%s' on card '%s'",
213 card->active_profile->name, card->name);
215 stamp = pa_utils_get_stamp();
217 handle_alsa_card(u, card);
219 PA_HASHMAP_FOREACH(node, discover->nodes.byname, state) {
220 if (node->implement == mir_device &&
221 node->pacard.index == card->index &&
224 destroy_node(u, node);
231 void pa_discover_add_sink(struct userdata *u, pa_sink *sink, pa_bool_t route)
234 pa_discover *discover;
244 pa_assert_se((discover = u->discover));
246 module = sink->module;
248 if ((card = sink->card)) {
249 if (!(key = node_key_from_card(u, mir_output, sink, buf, sizeof(buf))))
251 if (!(node = pa_discover_find_node(u, key))) {
252 pa_log_debug("can't find node for sink (key '%s')", key);
255 pa_log_debug("node for '%s' found (key %s). Updating with sink data",
256 node->paname, node->key);
257 node->paidx = sink->index;
258 pa_hashmap_put(discover->nodes.byptr, sink, node);
263 if (type != mir_bluetooth_a2dp && type != mir_bluetooth_sco)
264 mir_router_make_routing(u);
266 if (!u->state.profile)
267 schedule_deferred_routing(u);
271 else if (!module || !pa_streq(module->name, "module-combine-sink")) {
272 memset(&data, 0, sizeof(data));
273 data.key = pa_xstrdup(sink->name);
274 data.direction = mir_output;
275 data.implement = mir_device;
276 data.channels = sink->channel_map.channels;
278 if (sink == pa_utils_get_null_sink(u)) {
279 data.visible = FALSE;
280 data.available = TRUE;
281 data.type = mir_null;
282 data.amname = pa_xstrdup("Silent");
283 data.amid = AM_ID_INVALID;
284 data.paname = pa_xstrdup(sink->name);
285 data.paidx = sink->index;
288 pa_xfree(data.key); /* for now */
289 pa_log_info("currently we do not support statically loaded sinks");
293 create_node(u, &data, NULL);
298 void pa_discover_remove_sink(struct userdata *u, pa_sink *sink)
300 pa_discover *discover;
307 pa_assert_se((discover = u->discover));
309 name = pa_utils_get_sink_name(sink);
311 if (!(node = pa_hashmap_get(discover->nodes.byptr, sink)))
312 pa_log_debug("can't find node for sink (name '%s')", name);
314 pa_log_debug("node found for '%s'. Reseting sink data", name);
315 node->paidx = PA_IDXSET_INVALID;
316 pa_hashmap_remove(discover->nodes.byptr, sink);
321 if (type != mir_bluetooth_a2dp && type != mir_bluetooth_sco)
322 node->available = FALSE;
324 if (!u->state.profile)
325 schedule_deferred_routing(u);
329 pa_log_info("currently we do not support statically loaded sinks");
335 void pa_discover_add_source(struct userdata *u, pa_source *source)
337 pa_discover *discover;
345 pa_assert_se((discover = u->discover));
347 if ((card = source->card)) {
348 if (!(key = node_key_from_card(u, mir_output,source, buf,sizeof(buf))))
350 if (!(node = pa_discover_find_node(u, key))) {
351 pa_log_debug("can't find node for source (key '%s')", key);
354 pa_log_debug("node for '%s' found. Updating with source data",
356 node->paidx = source->index;
357 pa_hashmap_put(discover->nodes.byptr, source, node);
362 void pa_discover_remove_source(struct userdata *u, pa_source *source)
364 pa_discover *discover;
370 pa_assert_se((discover = u->discover));
372 name = pa_utils_get_source_name(source);
374 if (!(node = pa_hashmap_get(discover->nodes.byptr, source)))
375 pa_log_debug("can't find node for source (name '%s')", name);
377 pa_log_debug("node found. Reseting source data");
378 node->paidx = PA_IDXSET_INVALID;
379 pa_hashmap_remove(discover->nodes.byptr, source);
384 void pa_discover_register_sink_input(struct userdata *u, pa_sink_input *sinp)
387 pa_discover *discover;
400 pa_assert_se((core = u->core));
401 pa_assert_se((discover = u->discover));
402 pa_assert_se((pl = sinp->proplist));
404 if ((media = pa_proplist_gets(sinp->proplist, PA_PROP_MEDIA_NAME)) &&
405 !strncmp(media, combine_pattern, sizeof(combine_pattern)-1))
407 pa_log_debug("Seems to be a combine stream. Nothing to do ...");
411 name = pa_utils_get_sink_input_name(sinp);
413 pa_log_debug("registering stream '%s'", name);
415 if (!(type = pa_classify_guess_stream_node_type(pl))) {
416 pa_log_debug("cant find stream class for '%s'. "
417 "Leaving it alone", name);
421 pa_utils_set_stream_routing_properties(pl, type, NULL);
423 snprintf(key, sizeof(key), "stream_input.%d", sinp->index);
425 memset(&data, 0, sizeof(data));
427 data.direction = mir_input;
428 data.implement = mir_stream;
429 data.channels = sinp->channel_map.channels;
432 data.available = TRUE;
434 data.amdescr = (char *)pa_proplist_gets(pl, PA_PROP_MEDIA_NAME);
435 data.amid = AM_ID_INVALID;
437 data.paidx = sinp->index;
440 * here we can't guess whether the application requested an explicit
441 * route by sepcifying the target sink @ stream creation time.
443 * the brute force solution: we make a default route for this stream
444 * possibly overwiriting the orginal app request :(
446 /* this will set data.mux */
447 sink = make_output_prerouting(u, &data, &sinp->channel_map, &target);
449 node = create_node(u, &data, NULL);
451 pa_hashmap_put(discover->nodes.byptr, sinp, node);
453 if (sink && target) {
454 pa_log_debug("move stream to sink %u (%s)", sink->index, sink->name);
456 if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
457 pa_log("failed to route '%s' => '%s'",node->amname,target->amname);
459 pa_log_debug("register route '%s' => '%s'",
460 node->amname, target->amname);
461 /* FIXME: and actually do it ... */
466 void pa_discover_preroute_sink_input(struct userdata *u,
467 pa_sink_input_new_data *data)
472 pa_discover *discover;
479 pa_assert_se((core = u->core));
480 pa_assert_se((discover = u->discover));
481 pa_assert_se((pl = data->proplist));
482 pa_assert_se((module = data->module));
484 if (pa_streq(module->name, "module-combine-sink"))
485 type = mir_node_type_unknown;
487 type = pa_classify_guess_stream_node_type(pl);
488 pa_utils_set_stream_routing_properties(pl, type, data->sink);
492 memset(&fake, 0, sizeof(fake));
493 fake.direction = mir_input;
494 fake.implement = mir_stream;
495 fake.channels = data->channel_map.channels;
498 fake.available = TRUE;
499 fake.amname = "<preroute>";
501 if ((sink = make_output_prerouting(u,&fake,&data->channel_map,NULL))) {
502 if (!pa_sink_input_new_data_set_sink(data, sink, FALSE))
503 pa_log("can't set sink %d for new sink-input", sink->index);
509 void pa_discover_add_sink_input(struct userdata *u, pa_sink_input *sinp)
513 pa_sink_input *csinp;
515 pa_discover *discover;
527 pa_assert_se((core = u->core));
528 pa_assert_se((discover = u->discover));
529 pa_assert_se((pl = sinp->proplist));
532 if ((media = pa_proplist_gets(sinp->proplist, PA_PROP_MEDIA_NAME)) &&
533 !strncmp(media, combine_pattern, sizeof(combine_pattern)-1))
535 pa_log_debug("New stream is a combine stream. Nothing to do ...");
539 name = pa_utils_get_sink_input_name(sinp);
541 pa_log_debug("dealing with new stream '%s'", name);
543 if ((type = get_stream_routing_class(pl)) == mir_node_type_unknown) {
544 if (!(type = pa_classify_guess_stream_node_type(pl))) {
545 pa_log_debug("cant find stream class for '%s'. "
546 "Leaving it alone", name);
550 pa_utils_set_stream_routing_properties(pl, type, NULL);
552 /* if needed, make some post-routing here */
555 /* we need to add this to main hashmap as that is used for loop
556 through on all nodes. */
557 snprintf(key, sizeof(key), "stream_input.%d", sinp->index);
559 memset(&data, 0, sizeof(data));
561 data.direction = mir_input;
562 data.implement = mir_stream;
563 data.channels = sinp->channel_map.channels;
566 data.available = TRUE;
568 data.amdescr = (char *)pa_proplist_gets(pl, PA_PROP_MEDIA_NAME);
569 data.amid = AM_ID_INVALID;
571 data.paidx = sinp->index;
572 data.mux = pa_multiplex_find(u->multiplex, sinp->sink->index);
574 node = create_node(u, &data, &created);
579 pa_log("%s: confused with stream. '%s' did exists",
580 __FILE__, node->amname);
584 pa_hashmap_put(discover->nodes.byptr, sinp, node);
589 csinp = pa_idxset_get_by_index(core->sink_inputs,
590 data.mux->defstream_index);
591 s = csinp ? csinp->sink : NULL;
595 pa_log_debug("routing target candidate is %u (%s)", s->index, s->name);
597 if (!s || !(snod = pa_hashmap_get(discover->nodes.byptr, s)))
598 pa_log_debug("can't figure out where this stream is routed");
600 pa_log_debug("register route '%s' => '%s'",
601 node->amname, snod->amname);
602 /* FIXME: and actually do it ... */
607 void pa_discover_remove_sink_input(struct userdata *u, pa_sink_input *sinp)
609 pa_discover *discover;
616 pa_assert_se((discover = u->discover));
618 name = pa_utils_get_sink_input_name(sinp);
620 if (!(node = pa_hashmap_remove(discover->nodes.byptr, sinp)))
621 pa_log_debug("can't find node for sink-input (name '%s')", name);
623 pa_log_debug("node found for '%s'. After clearing the route "
624 "it will be destroyed", name);
626 if (!(sinknod = pa_hashmap_get(discover->nodes.byptr, sinp->sink)))
627 pa_log_debug("can't figure out where this stream is routed");
629 pa_log_debug("clear route '%s' => '%s'",
630 node->amname, sinknod->amname);
632 /* FIXME: and actually do it ... */
635 destroy_node(u, node);
640 mir_node *pa_discover_find_node(struct userdata *u, const char *key)
642 pa_discover *discover;
646 pa_assert_se((discover = u->discover));
649 node = pa_hashmap_get(discover->nodes.byname, key);
657 static void handle_alsa_card(struct userdata *u, pa_card *card)
664 memset(&data, 0, sizeof(data));
666 data.amid = AM_ID_INVALID;
667 data.implement = mir_device;
668 data.paidx = PA_IDXSET_INVALID;
669 data.stamp = pa_utils_get_stamp();
671 cnam = pa_utils_get_card_name(card);
672 udd = pa_proplist_gets(card->proplist, "module-udev-detect.discovered");
674 if (udd && pa_streq(udd, "1")) {
675 /* udev loaded alsa card */
676 if (!strncmp(cnam, "alsa_card.", 10)) {
678 handle_udev_loaded_card(u, card, &data, cid);
683 /* statically loaded pci or usb card */
686 pa_log_debug("ignoring unrecognized pci card '%s'", cnam);
690 static void handle_bluetooth_card(struct userdata *u, pa_card *card)
692 pa_discover *discover;
693 pa_card_profile *prof;
699 char paname[MAX_NAME_LENGTH+1];
700 char amname[MAX_NAME_LENGTH+1];
701 char key[MAX_NAME_LENGTH+1];
704 pa_assert_se((discover = u->discover));
706 cdescr = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_DESCRIPTION);
709 memset(paname, 0, sizeof(paname));
710 memset(amname, 0, sizeof(amname));
711 memset(key , 0, sizeof(key) );
713 memset(&data, 0, sizeof(data));
716 data.amid = AM_ID_INVALID;
717 data.implement = mir_device;
718 data.paidx = PA_IDXSET_INVALID;
719 data.paname = paname;
720 data.amname = amname;
721 data.amdescr = (char *)cdescr;
722 data.pacard.index = card->index;
723 data.stamp = pa_utils_get_stamp();
725 cnam = pa_utils_get_card_name(card);
727 if (!strncmp(cnam, "bluez_card.", 11)) {
730 PA_HASHMAP_FOREACH(prof, card->profiles, state) {
731 data.available = TRUE;
732 data.pacard.profile = prof->name;
734 if (prof->n_sinks > 0) {
735 data.direction = mir_output;
736 data.channels = prof->max_sink_channels;
737 data.amname = amname;
739 snprintf(paname, sizeof(paname), "bluez_sink.%s", cid);
740 snprintf(key, sizeof(key), "%s@%s", paname, prof->name);
741 pa_classify_node_by_card(&data, card, prof, NULL);
742 create_node(u, &data, NULL);
745 if (prof->n_sources > 0) {
746 data.direction = mir_input;
747 data.channels = prof->max_source_channels;
748 data.amname = amname;
750 snprintf(paname, sizeof(paname), "bluez_source.%s", cid);
751 snprintf(key, sizeof(key), "%s@%s", paname, prof->name);
752 pa_classify_node_by_card(&data, card, prof, NULL);
753 create_node(u, &data, NULL);
757 if (!(prof = card->active_profile))
758 pa_log("card '%s' has no active profile", card->name);
760 pa_log_debug("card '%s' default profile '%s'",
761 card->name, prof->name);
764 schedule_card_check(u, card);
769 static void handle_udev_loaded_card(struct userdata *u, pa_card *card,
770 mir_node *data, char *cardid)
772 pa_discover *discover;
773 pa_card_profile *prof;
774 pa_card_profile *active;
778 char *sinks[MAX_CARD_TARGET+1];
779 char *sources[MAX_CARD_TARGET+1];
780 char buf[MAX_NAME_LENGTH+1];
781 char paname[MAX_NAME_LENGTH+1];
782 char amname[MAX_NAME_LENGTH+1];
786 pa_assert(card->profiles);
787 pa_assert_se((discover = u->discover));
789 alsanam = pa_proplist_gets(card->proplist, "alsa.card_name");
791 memset(amname, 0, sizeof(amname));
793 data->paname = paname;
794 data->amname = amname;
795 data->amdescr = (char *)alsanam;
797 data->pacard.index = card->index;
799 active = card->active_profile;
801 PA_HASHMAP_FOREACH(prof, card->profiles, state) {
802 /* filtering: deal with sepected profiles if requested so */
803 if (discover->selected && (!active || (active && prof != active)))
806 /* filtering: skip the 'off' profiles */
807 if (!prof->n_sinks && !prof->n_sources)
810 /* filtering: consider sinks with suitable amount channels */
812 (prof->max_sink_channels < discover->chmin ||
813 prof->max_sink_channels > discover->chmax ))
816 /* filtering: consider sources with suitable amount channels */
817 if (prof->n_sources &&
818 (prof->max_source_channels < discover->chmin ||
819 prof->max_source_channels > discover->chmax ))
822 data->pacard.profile = prof->name;
824 parse_profile_name(prof, sinks,sources, buf,sizeof(buf));
826 data->direction = mir_output;
827 data->channels = prof->max_sink_channels;
828 for (i = 0; (sid = sinks[i]); i++) {
829 snprintf(paname, sizeof(paname), "alsa_output.%s.%s", cardid, sid);
830 handle_card_ports(u, data, card, prof);
833 data->direction = mir_input;
834 data->channels = prof->max_source_channels;
835 for (i = 0; (sid = sources[i]); i++) {
836 snprintf(paname, sizeof(paname), "alsa_input.%s.%s", cardid, sid);
837 handle_card_ports(u, data, card, prof);
843 static void handle_card_ports(struct userdata *u, mir_node *data,
844 pa_card *card, pa_card_profile *prof)
846 mir_node *node = NULL;
847 pa_bool_t have_ports = FALSE;
848 char *amname = data->amname;
849 pa_device_port *port;
852 char key[MAX_NAME_LENGTH+1];
860 PA_HASHMAP_FOREACH(port, card->ports, state) {
862 * if this port did not belong to any profile
863 * (ie. prof->profiles == NULL) we assume that this port
864 * does works with all the profiles
866 if (port->profiles && pa_hashmap_get(port->profiles, prof->name) &&
867 ((port->is_input && data->direction == mir_input)||
868 (port->is_output && data->direction == mir_output)))
872 /* make constrain if node != NULL and add node to it */
875 snprintf(key, sizeof(key), "%s@%s", data->paname, port->name);
878 data->available = (port->available != PA_PORT_AVAILABLE_NO);
880 data->amname = amname;
881 data->paport = port->name;
883 pa_classify_node_by_card(data, card, prof, port);
885 node = create_node(u, data, &created);
888 ; /* if constrain != NULL add the node to it */
890 node->stamp = data->stamp;
897 data->key = data->paname;
898 data->available = TRUE;
900 pa_classify_node_by_card(data, card, prof, NULL);
902 node = create_node(u, data, &created);
905 node->stamp = data->stamp;
908 data->amname = amname;
913 static mir_node *create_node(struct userdata *u, mir_node *data,
914 pa_bool_t *created_ret)
916 pa_discover *discover;
923 pa_assert(data->key);
924 pa_assert(data->paname);
925 pa_assert_se((discover = u->discover));
927 if ((node = pa_hashmap_get(discover->nodes.byname, data->key)))
932 node = mir_node_create(u, data);
933 pa_hashmap_put(discover->nodes.byname, node->key, node);
935 mir_node_print(node, buf, sizeof(buf));
936 pa_log_debug("new node:\n%s", buf);
938 pa_audiomgr_register_node(u, node);
942 *created_ret = created;
947 static void destroy_node(struct userdata *u, mir_node *node)
949 pa_discover *discover;
953 pa_assert_se((discover = u->discover));
956 removed = pa_hashmap_remove(discover->nodes.byname, node->key);
958 if (node != removed) {
960 pa_log("%s: confused with data structures: key mismatch. "
961 " attempted to destroy '%s'; actually destroyed '%s'",
962 __FILE__, node->key, removed->key);
964 pa_log("%s: confused with data structures: node '%s' "
965 "is not in the hash table", __FILE__, node->key);
969 pa_log_debug("destroying node: %s / '%s'", node->key, node->amname);
971 if (node->implement == mir_stream) {
972 if (node->direction == mir_input) {
974 pa_log_debug("removing multiplexer");
979 pa_audiomgr_unregister_node(u, node);
981 pa_multiplex_destroy(u->multiplex, u->core, node->mux);
983 mir_node_destroy(u, node);
987 static char *get_name(char **string_ptr, int offs)
991 name = *string_ptr + offs;
993 for (end = name; (c = *end); end++) {
1005 static void parse_profile_name(pa_card_profile *prof,
1015 pa_assert(prof->name);
1017 strncpy(buf, prof->name, buflen);
1018 buf[buflen-1] = '\0';
1020 memset(sinks, 0, sizeof(char *) * (MAX_CARD_TARGET+1));
1021 memset(sources, 0, sizeof(char *) * (MAX_CARD_TARGET+1));
1024 if (!strncmp(p, "output:", 7)) {
1025 if (i >= MAX_CARD_TARGET) {
1026 pa_log_debug("number of outputs exeeds the maximum %d in "
1027 "profile name '%s'", MAX_CARD_TARGET, prof->name);
1030 sinks[i++] = get_name(&p, 7);
1032 else if (!strncmp(p, "input:", 6)) {
1033 if (j >= MAX_CARD_TARGET) {
1034 pa_log_debug("number of inputs exeeds the maximum %d in "
1035 "profile name '%s'", MAX_CARD_TARGET, prof->name);
1038 sources[j++] = get_name(&p, 6);
1041 pa_log("%s: failed to parse profile name '%s'",
1042 __FILE__, prof->name);
1049 static char *node_key_from_card(struct userdata *u, mir_direction direction,
1050 void *data, char *buf, size_t len)
1053 pa_card_profile *profile;
1054 pa_device_port *port;
1058 pa_bool_t bluetooth;
1061 const char *profile_name;
1066 pa_assert(direction == mir_input || direction == mir_output);
1068 if (direction == mir_input) {
1069 pa_sink *sink = data;
1071 name = pa_utils_get_sink_name(sink);
1073 port = sink->active_port;
1076 pa_source *source = data;
1078 name = pa_utils_get_source_name(source);
1079 card = source->card;
1080 port = source->active_port;
1086 pa_assert_se((profile = card->active_profile));
1088 if (!u->state.profile)
1089 profile_name = profile->name;
1091 pa_log_debug("state.profile is not null. '%s' supresses '%s'",
1092 u->state.profile, profile->name);
1093 profile_name = u->state.profile;
1097 if (!(bus = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_BUS))) {
1098 pa_log_debug("ignoring %s '%s' due to lack of '%s' property "
1099 "on its card", type, name, PA_PROP_DEVICE_BUS);
1103 pci = pa_streq(bus, "pci");
1104 usb = pa_streq(bus, "usb");
1105 bluetooth = pa_streq(bus, "bluetooth");
1107 if (!pci && !usb && !bluetooth) {
1108 pa_log_debug("ignoring %s '%s' due to unsupported bus type '%s' "
1109 "of its card", type, name, bus);
1115 snprintf(buf, len, "%s@%s", name, profile_name);
1122 snprintf(buf, len, "%s@%s", name, port->name);
1129 static pa_sink *make_output_prerouting(struct userdata *u,
1131 pa_channel_map *chmap,
1132 mir_node **target_ret)
1136 pa_sink *sink = NULL;
1141 pa_assert_se((core = u->core));
1145 target = mir_router_make_prerouting(u, data);
1148 pa_log("there is no default route for the stream '%s'", data->amname);
1149 else if (target->paidx == PA_IDXSET_INVALID)
1150 pa_log("can't route to default '%s': no sink", target->amname);
1152 if (!(sink = pa_idxset_get_by_index(core->sinks, target->paidx)))
1153 pa_log("can't route to default '%s': sink is gone",target->amname);
1155 if (pa_classify_multiplex_stream(data)) {
1156 data->mux = pa_multiplex_create(u->multiplex, core,
1157 sink->index, chmap, NULL,
1160 sink = pa_idxset_get_by_index(core->sinks,
1161 data->mux->sink_index);
1169 *target_ret = target;
1175 static mir_node_type get_stream_routing_class(pa_proplist *pl)
1183 if ((clid = pa_proplist_gets(pl, PA_PROP_ROUTING_CLASS_ID))) {
1184 type = strtol(clid, &e, 10);
1187 if (type >= mir_application_class_begin &&
1188 type < mir_application_class_end)
1195 return mir_node_type_unknown;
1200 static void deferred_routing_cb(pa_mainloop_api *m, void *d)
1202 struct userdata *u = d;
1208 pa_log_debug("deferred routing starts");
1210 mir_router_make_routing(u);
1214 static void schedule_deferred_routing(struct userdata *u)
1219 pa_assert_se((core = u->core));
1221 pa_log_debug("scheduling deferred routing");
1223 pa_mainloop_api_once(core->mainloop, deferred_routing_cb, u);
1227 static void card_check_cb(pa_mainloop_api *m, void *d)
1229 card_check_t *cc = d;
1235 int n_sink, n_source;
1241 pa_assert((u = cc->u));
1242 pa_assert((core = u->core));
1244 pa_log_debug("card check starts");
1246 if (!(card = pa_idxset_get_by_index(core->cards, cc->index)))
1247 pa_log_debug("card %u is gone", cc->index);
1249 n_sink = n_source = 0;
1251 PA_IDXSET_FOREACH(sink, core->sinks, idx) {
1252 if ((sink->card) && sink->card->index == card->index)
1256 PA_IDXSET_FOREACH(source, core->sources, idx) {
1257 if ((source->card) && source->card->index == card->index)
1261 if (n_sink || n_source) {
1262 pa_log_debug("found %u sinks and %u sources belonging to "
1263 "'%s' card", n_sink, n_source, card->name);
1264 pa_log_debug("nothing to do");
1267 pa_log_debug("card '%s' has no sinks/sources. Do routing ...",
1269 mir_router_make_routing(u);
1277 static void schedule_card_check(struct userdata *u, pa_card *card)
1284 pa_assert_se((core = u->core));
1286 pa_log_debug("scheduling card check");
1288 cc = pa_xnew0(card_check_t, 1);
1290 cc->index = card->index;
1292 pa_mainloop_api_once(core->mainloop, card_check_cb, cc);
1299 * indent-tabs-mode: nil