static void card_changed(struct userdata *u, struct udev_device *dev) { struct device *d; const char *path; const char *t; char *n; pa_assert(u); pa_assert(dev); /* Maybe /dev/snd is now available? */ setup_inotify(u); path = udev_device_get_devpath(dev); if ((d = pa_hashmap_get(u->devices, path))) { verify_access(u, d); return; } d = pa_xnew0(struct device, 1); d->path = pa_xstrdup(path); d->module = PA_INVALID_INDEX; PA_INIT_RATELIMIT(d->ratelimit, 10*PA_USEC_PER_SEC, 5); if (!(t = udev_device_get_property_value(dev, "PULSE_NAME"))) if (!(t = udev_device_get_property_value(dev, "ID_ID"))) if (!(t = udev_device_get_property_value(dev, "ID_PATH"))) t = path_get_card_id(path); n = pa_namereg_make_valid_name(t); d->card_name = pa_sprintf_malloc("alsa_card.%s", n); d->args = pa_sprintf_malloc("device_id=\"%s\" " "name=\"%s\" " "card_name=\"%s\" " "namereg_fail=false " "tsched=%s " "fixed_latency_range=%s " "ignore_dB=%s " "deferred_volume=%s " "use_ucm=1 " "card_properties=\"module-udev-detect.discovered=1\"", path_get_card_id(path), n, d->card_name, pa_yes_no(u->use_tsched), pa_yes_no(u->fixed_latency_range), pa_yes_no(u->ignore_dB), pa_yes_no(u->deferred_volume)); pa_xfree(n); pa_hashmap_put(u->devices, d->path, d); verify_access(u, d); }
static void resolver_cb( AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) { struct userdata *u = userdata; struct tunnel *tnl; char *device = NULL, *nicename, *dname, *vname, *args; char *tp = NULL, *et = NULL, *cn = NULL; char *ch = NULL, *ss = NULL, *sr = NULL; char *t = NULL; char at[AVAHI_ADDRESS_STR_MAX]; AvahiStringList *l; pa_module *m; pa_assert(u); tnl = tunnel_new(interface, protocol, name, type, domain); if (event != AVAHI_RESOLVER_FOUND) { pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client))); goto finish; } if ((nicename = strstr(name, "@"))) { ++nicename; if (strlen(nicename) > 0) { pa_log_debug("Found RAOP: %s", nicename); nicename = pa_escape(nicename, "\"'"); } else nicename = NULL; } for (l = txt; l; l = l->next) { char *key, *value; pa_assert_se(avahi_string_list_get_pair(l, &key, &value, NULL) == 0); pa_log_debug("Found key: '%s' with value: '%s'", key, value); if (pa_streq(key, "device")) { device = value; value = NULL; } else if (pa_streq(key, "tp")) { /* Transport protocol: * - TCP = only TCP, * - UDP = only UDP, * - TCP,UDP = both supported (UDP should be prefered) */ pa_xfree(tp); if (pa_str_in_list(value, ",", "UDP")) tp = pa_xstrdup("UDP"); else if (pa_str_in_list(value, ",", "TCP")) tp = pa_xstrdup("TCP"); else tp = pa_xstrdup(value); } else if (pa_streq(key, "et")) { /* Supported encryption types: * - 0 = none, * - 1 = RSA, * - 2 = FairPlay, * - 3 = MFiSAP, * - 4 = FairPlay SAPv2.5. */ pa_xfree(et); if (pa_str_in_list(value, ",", "1")) et = pa_xstrdup("RSA"); else et = pa_xstrdup("none"); } else if (pa_streq(key, "cn")) { /* Suported audio codecs: * - 0 = PCM, * - 1 = ALAC, * - 2 = AAC, * - 3 = AAC ELD. */ pa_xfree(cn); if (pa_str_in_list(value, ",", "1")) cn = pa_xstrdup("ALAC"); else cn = pa_xstrdup("PCM"); } else if (pa_streq(key, "md")) { /* Supported metadata types: * - 0 = text, * - 1 = artwork, * - 2 = progress. */ } else if (pa_streq(key, "pw")) { /* Requires password ? (true/false) */ } else if (pa_streq(key, "ch")) { /* Number of channels */ pa_xfree(ch); ch = pa_xstrdup(value); } else if (pa_streq(key, "ss")) { /* Sample size */ pa_xfree(ss); ss = pa_xstrdup(value); } else if (pa_streq(key, "sr")) { /* Sample rate */ pa_xfree(sr); sr = pa_xstrdup(value); } avahi_free(key); avahi_free(value); } if (device) dname = pa_sprintf_malloc("raop_output.%s.%s", host_name, device); else dname = pa_sprintf_malloc("raop_output.%s", host_name); if (!(vname = pa_namereg_make_valid_name(dname))) { pa_log("Cannot construct valid device name from '%s'.", dname); avahi_free(device); pa_xfree(dname); pa_xfree(tp); pa_xfree(et); pa_xfree(cn); pa_xfree(ch); pa_xfree(ss); pa_xfree(sr); goto finish; } avahi_free(device); pa_xfree(dname); avahi_address_snprint(at, sizeof(at), a); if (nicename) { args = pa_sprintf_malloc("server=[%s]:%u " "sink_name=%s " "sink_properties='device.description=\"%s (%s:%u)\"'", at, port, vname, nicename, at, port); pa_xfree(nicename); } else { args = pa_sprintf_malloc("server=[%s]:%u " "sink_name=%s" "sink_properties='device.description=\"%s:%u\"'", at, port, vname, at, port); } if (tp != NULL) { t = args; args = pa_sprintf_malloc("%s protocol=%s", args, tp); pa_xfree(tp); pa_xfree(t); } if (et != NULL) { t = args; args = pa_sprintf_malloc("%s encryption=%s", args, et); pa_xfree(et); pa_xfree(t); } if (cn != NULL) { t = args; args = pa_sprintf_malloc("%s codec=%s", args, cn); pa_xfree(cn); pa_xfree(t); } if (ch != NULL) { t = args; args = pa_sprintf_malloc("%s channels=%s", args, ch); pa_xfree(ch); pa_xfree(t); } if (ss != NULL) { t = args; args = pa_sprintf_malloc("%s format=%s", args, ss); pa_xfree(ss); pa_xfree(t); } if (sr != NULL) { t = args; args = pa_sprintf_malloc("%s rate=%s", args, sr); pa_xfree(sr); pa_xfree(t); } pa_log_debug("Loading module-raop-sink with arguments '%s'", args); if ((m = pa_module_load(u->core, "module-raop-sink", args))) { tnl->module_index = m->index; pa_hashmap_put(u->tunnels, tnl, tnl); tnl = NULL; } pa_xfree(vname); pa_xfree(args); finish: avahi_service_resolver_free(r); if (tnl) tunnel_free(tnl); }
static void resolver_cb( AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) { struct userdata *u = userdata; struct tunnel *tnl; pa_assert(u); tnl = tunnel_new(interface, protocol, name, type, domain); if (event != AVAHI_RESOLVER_FOUND) pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client))); else { char *device = NULL, *nicename, *dname, *vname, *args; char at[AVAHI_ADDRESS_STR_MAX]; AvahiStringList *l; pa_module *m; if ((nicename = strstr(name, "@"))) { ++nicename; if (strlen(nicename) > 0) { pa_log_debug("Found RAOP: %s", nicename); nicename = pa_escape(nicename, "\"'"); } else nicename = NULL; } for (l = txt; l; l = l->next) { char *key, *value; pa_assert_se(avahi_string_list_get_pair(l, &key, &value, NULL) == 0); pa_log_debug("Found key: '%s' with value: '%s'", key, value); if (pa_streq(key, "device")) { pa_xfree(device); device = value; value = NULL; } avahi_free(key); avahi_free(value); } if (device) dname = pa_sprintf_malloc("raop.%s.%s", host_name, device); else dname = pa_sprintf_malloc("raop.%s", host_name); if (!(vname = pa_namereg_make_valid_name(dname))) { pa_log("Cannot construct valid device name from '%s'.", dname); avahi_free(device); pa_xfree(dname); goto finish; } pa_xfree(dname); if (nicename) { args = pa_sprintf_malloc("server=[%s]:%u " "sink_name=%s " "sink_properties='device.description=\"%s\"'", avahi_address_snprint(at, sizeof(at), a), port, vname, nicename); pa_xfree(nicename); } else { args = pa_sprintf_malloc("server=[%s]:%u " "sink_name=%s", avahi_address_snprint(at, sizeof(at), a), port, vname); } pa_log_debug("Loading module-raop-sink with arguments '%s'", args); if ((m = pa_module_load(u->core, "module-raop-sink", args))) { tnl->module_index = m->index; pa_hashmap_put(u->tunnels, tnl, tnl); tnl = NULL; } pa_xfree(vname); pa_xfree(args); avahi_free(device); } finish: avahi_service_resolver_free(r); if (tnl) tunnel_free(tnl); }