From 0bb0b524c7a489b830d62d38309c62e1fb2dd4d9 Mon Sep 17 00:00:00 2001 From: Christian Glombek Date: Sat, 29 Apr 2023 20:44:00 +0200 Subject: [PATCH] raop: Deduplicate sink creation Currently, RAOP sinks referencing the same remote ip and port may be created multiple times: One each for IPv4 and IPv6, times the number of network interfaces used for mDNS discovery. A recent change added `(IPv4)`and `(IPv6)`identifiers to the sinks' pretty names, however that is misleading, as often times the service advertised through an mDNSv6 record is actually an IPv4 service (i.e. the IP reference contained in the IPv6 record may be an IPv4 address). With this change, sink creation is skipped if a sink with the same advertised name already exists. --- src/modules/module-raop-discover.c | 54 ++++++++++++------------------ src/modules/module-raop-sink.c | 17 ++++++---- 2 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/modules/module-raop-discover.c b/src/modules/module-raop-discover.c index 4eceb577a..9fe2af7e0 100644 --- a/src/modules/module-raop-discover.c +++ b/src/modules/module-raop-discover.c @@ -125,12 +125,10 @@ struct impl { }; struct tunnel_info { - AvahiIfIndex interface; - AvahiProtocol protocol; const char *name; const char *host_name; - const char *type; - const char *domain; + const char *ip; + const char *port; }; #define TUNNEL_INFO(...) ((struct tunnel_info){ __VA_ARGS__ }) @@ -152,12 +150,10 @@ static struct tunnel *make_tunnel(struct impl *impl, const struct tunnel_info *i if (t == NULL) return NULL; - t->info.interface = info->interface; - t->info.protocol = info->protocol; t->info.name = strdup(info->name); t->info.host_name = strdup(info->host_name); - t->info.type = strdup(info->type); - t->info.domain = strdup(info->domain); + t->info.ip = strdup(info->ip); + t->info.port = strdup(info->port); spa_list_append(&impl->tunnel_list, &t->link); return t; @@ -167,11 +163,7 @@ static struct tunnel *find_tunnel(struct impl *impl, const struct tunnel_info *i { struct tunnel *t; spa_list_for_each(t, &impl->tunnel_list, link) { - if (t->info.interface == info->interface && - t->info.protocol == info->protocol && - spa_streq(t->info.name, info->name) && - spa_streq(t->info.type, info->type) && - spa_streq(t->info.domain, info->domain)) + if (spa_streq(t->info.name, info->name)) return t; } return NULL; @@ -298,8 +290,8 @@ static void submodule_destroy(void *data) free((char *) t->info.name); free((char *) t->info.host_name); - free((char *) t->info.type); - free((char *) t->info.domain); + free((char *) t->info.ip); + free((char *) t->info.port); free(t); } @@ -385,23 +377,18 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr { struct impl *impl = userdata; struct tunnel_info tinfo; - const char *str; + const char *str, *port_str; AvahiStringList *l; struct pw_properties *props = NULL; char at[AVAHI_ADDRESS_STR_MAX]; - int ipv; if (event != AVAHI_RESOLVER_FOUND) { pw_log_error("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(impl->client))); goto done; } - tinfo = TUNNEL_INFO(.interface = interface, - .protocol = protocol, - .host_name = host_name, - .name = name, - .type = type, - .domain = domain); + + avahi_address_snprint(at, sizeof(at), a); props = pw_properties_new(NULL, NULL); if (props == NULL) { @@ -409,11 +396,7 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr goto done; } - avahi_address_snprint(at, sizeof(at), a); - ipv = protocol == AVAHI_PROTO_INET ? 4 : 6; - pw_properties_setf(props, "raop.ip", "%s", at); - pw_properties_setf(props, "raop.ip.version", "%d", ipv); pw_properties_setf(props, "raop.port", "%u", port); pw_properties_setf(props, "raop.name", "%s", name); pw_properties_setf(props, "raop.hostname", "%s", host_name); @@ -430,6 +413,13 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr avahi_free(value); } + port_str = pw_properties_get(props, "raop.port"); + + tinfo = TUNNEL_INFO(.name = name, + .host_name = host_name, + .ip = at, + .port = port_str); + if ((str = pw_properties_get(impl->properties, "stream.rules")) == NULL) str = DEFAULT_CREATE_RULES; if (str != NULL) { @@ -462,18 +452,16 @@ static void browser_cb(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProt if (flags & AVAHI_LOOKUP_RESULT_LOCAL) return; - info = TUNNEL_INFO(.interface = interface, - .protocol = protocol, - .name = name, - .type = type, - .domain = domain); + info = TUNNEL_INFO(.name = name); t = find_tunnel(impl, &info); switch (event) { case AVAHI_BROWSER_NEW: - if (t != NULL) + if (t != NULL) { + pw_log_debug("found duplicate mdns entry - skipping tunnel creation"); return; + } if (!(avahi_service_resolver_new(impl->client, interface, protocol, name, type, domain, diff --git a/src/modules/module-raop-sink.c b/src/modules/module-raop-sink.c index cb5021018..966092043 100644 --- a/src/modules/module-raop-sink.c +++ b/src/modules/module-raop-sink.c @@ -1861,7 +1861,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) struct pw_context *context = pw_impl_module_get_context(module); struct pw_properties *props = NULL; struct impl *impl; - const char *str, *name, *hostname, *ipv; + const char *str, *name, *hostname, *ip, *port; int res; PW_LOG_TOPIC_INIT(mod_topic); @@ -1902,6 +1902,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) impl->context = context; impl->loop = pw_context_get_main_loop(context); + if ((ip = pw_properties_get(props, "raop.ip")) == NULL) + goto error; + if ((port = pw_properties_get(props, "raop.port")) == NULL) + goto error; + if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); @@ -1916,17 +1921,15 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args) if (strlen(str) > 0) name = str; } - if ((ipv = pw_properties_get(props, "raop.ip.version")) == NULL) - ipv = "4"; if ((hostname = pw_properties_get(props, "raop.hostname")) == NULL) hostname = name; + if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) + pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.%s.%s", + hostname, ip, port); if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, - "%s (IPv%s)", name, ipv); - if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) - pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.ipv%s", - hostname, ipv); + "%s", name); if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL) pw_properties_set(props, PW_KEY_NODE_LATENCY, "352/44100");