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); }