mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	module-raop: add match rules for discover
Useful for selecting only ip4 streams or for setting up the password.
This commit is contained in:
		
							parent
							
								
									9e56fae236
								
							
						
					
					
						commit
						8167e1b9be
					
				
					 2 changed files with 160 additions and 66 deletions
				
			
		| 
						 | 
					@ -31,19 +31,56 @@
 | 
				
			||||||
 * Automatically creates RAOP (Airplay) sink devices based on zeroconf
 | 
					 * Automatically creates RAOP (Airplay) sink devices based on zeroconf
 | 
				
			||||||
 * information.
 | 
					 * information.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This module will load module-raop-sink for each discovered sink
 | 
					 * This module will load module-raop-sink for each announced stream that matches
 | 
				
			||||||
 * with the right parameters.
 | 
					 * the rule with the create-stream action.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If no stream.rules are given, it will create a sink for all announced
 | 
				
			||||||
 | 
					 * streams.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * ## Module Options
 | 
					 * ## Module Options
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This module has no options.
 | 
					 * Options specific to the behavior of this module
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * - `stream.rules` = <rules>: match rules, use create-stream actions. See
 | 
				
			||||||
 | 
					 *   \ref page_module_raop_sink for module properties.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * ## Example configuration
 | 
					 * ## Example configuration
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *\code{.unparsed}
 | 
					 *\code{.unparsed}
 | 
				
			||||||
 * context.modules = [
 | 
					 * context.modules = [
 | 
				
			||||||
 * {   name = libpipewire-raop-discover
 | 
					 * {   name = libpipewire-raop-discover
 | 
				
			||||||
 *     args = { }
 | 
					 *     args = {
 | 
				
			||||||
 | 
					 *         stream.rules = [
 | 
				
			||||||
 | 
					 *             {   matches = [
 | 
				
			||||||
 | 
					 *                     {    raop.ip = "~.*"
 | 
				
			||||||
 | 
					 *                          #raop.ip.version = 4 | 6
 | 
				
			||||||
 | 
					 *                          #raop.ip.version = 4
 | 
				
			||||||
 | 
					 *                          #raop.port = 1000
 | 
				
			||||||
 | 
					 *                          #raop.name = ""
 | 
				
			||||||
 | 
					 *                          #raop.hostname = ""
 | 
				
			||||||
 | 
					 *                          #raop.domain = ""
 | 
				
			||||||
 | 
					 *                          #raop.device = ""
 | 
				
			||||||
 | 
					 *                          #raop.transport = "udp" | "tcp"
 | 
				
			||||||
 | 
					 *                          #raop.encryption.type = "RSA" | "auth_setup" | "none"
 | 
				
			||||||
 | 
					 *                          #raop.audio.codec = "PCM" | "ALAC" | "AAC" | "AAC-ELD"
 | 
				
			||||||
 | 
					 *                          #audio.channels = 2
 | 
				
			||||||
 | 
					 *                          #audio.format = "S16" | "S24" | "S32"
 | 
				
			||||||
 | 
					 *                          #audio.rate = 44100
 | 
				
			||||||
 | 
					 *                          #device.model = ""
 | 
				
			||||||
 | 
					 *                     }
 | 
				
			||||||
 | 
					 *                 ]
 | 
				
			||||||
 | 
					 *                 actions = {
 | 
				
			||||||
 | 
					 *                     create-stream = {
 | 
				
			||||||
 | 
					 *                         #raop.password = ""
 | 
				
			||||||
 | 
					 *                         stream.props = {
 | 
				
			||||||
 | 
					 *                             #target.object = ""
 | 
				
			||||||
 | 
					 *                             #media.class = "Audio/Sink"
 | 
				
			||||||
 | 
					 *                         }
 | 
				
			||||||
 | 
					 *                     }
 | 
				
			||||||
 | 
					 *                 }
 | 
				
			||||||
 | 
					 *             }
 | 
				
			||||||
 | 
					 *         ]
 | 
				
			||||||
 | 
					 *     }
 | 
				
			||||||
 * }
 | 
					 * }
 | 
				
			||||||
 * ]
 | 
					 * ]
 | 
				
			||||||
 *\endcode
 | 
					 *\endcode
 | 
				
			||||||
| 
						 | 
					@ -58,7 +95,10 @@
 | 
				
			||||||
PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
 | 
					PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
 | 
				
			||||||
#define PW_LOG_TOPIC_DEFAULT mod_topic
 | 
					#define PW_LOG_TOPIC_DEFAULT mod_topic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MODULE_USAGE	" "
 | 
					#define MODULE_USAGE "stream.rules=<rules>, use create-stream actions "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_CREATE_RULES	\
 | 
				
			||||||
 | 
					        "[ { matches = [ { raop.ip = \"~.*\" } ] actions = { create-stream = { } } } ] "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct spa_dict_item module_props[] = {
 | 
					static const struct spa_dict_item module_props[] = {
 | 
				
			||||||
	{ PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
 | 
						{ PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
 | 
				
			||||||
| 
						 | 
					@ -88,6 +128,7 @@ struct tunnel_info {
 | 
				
			||||||
	AvahiIfIndex interface;
 | 
						AvahiIfIndex interface;
 | 
				
			||||||
	AvahiProtocol protocol;
 | 
						AvahiProtocol protocol;
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
 | 
						const char *host_name;
 | 
				
			||||||
	const char *type;
 | 
						const char *type;
 | 
				
			||||||
	const char *domain;
 | 
						const char *domain;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -114,6 +155,7 @@ static struct tunnel *make_tunnel(struct impl *impl, const struct tunnel_info *i
 | 
				
			||||||
	t->info.interface = info->interface;
 | 
						t->info.interface = info->interface;
 | 
				
			||||||
	t->info.protocol = info->protocol;
 | 
						t->info.protocol = info->protocol;
 | 
				
			||||||
	t->info.name = strdup(info->name);
 | 
						t->info.name = strdup(info->name);
 | 
				
			||||||
 | 
						t->info.host_name = strdup(info->host_name);
 | 
				
			||||||
	t->info.type = strdup(info->type);
 | 
						t->info.type = strdup(info->type);
 | 
				
			||||||
	t->info.domain = strdup(info->domain);
 | 
						t->info.domain = strdup(info->domain);
 | 
				
			||||||
	spa_list_append(&impl->tunnel_list, &t->link);
 | 
						spa_list_append(&impl->tunnel_list, &t->link);
 | 
				
			||||||
| 
						 | 
					@ -255,6 +297,7 @@ static void submodule_destroy(void *data)
 | 
				
			||||||
	spa_hook_remove(&t->module_listener);
 | 
						spa_hook_remove(&t->module_listener);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	free((char *) t->info.name);
 | 
						free((char *) t->info.name);
 | 
				
			||||||
 | 
						free((char *) t->info.host_name);
 | 
				
			||||||
	free((char *) t->info.type);
 | 
						free((char *) t->info.type);
 | 
				
			||||||
	free((char *) t->info.domain);
 | 
						free((char *) t->info.domain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -266,20 +309,84 @@ static const struct pw_impl_module_events submodule_events = {
 | 
				
			||||||
	.destroy = submodule_destroy,
 | 
						.destroy = submodule_destroy,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct match_info {
 | 
				
			||||||
 | 
						struct impl *impl;
 | 
				
			||||||
 | 
						struct pw_properties *props;
 | 
				
			||||||
 | 
						struct tunnel_info *tinfo;
 | 
				
			||||||
 | 
						bool matched;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int create_stream(struct impl *impl, struct pw_properties *props,
 | 
				
			||||||
 | 
							struct tunnel_info *tinfo)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						FILE *f;
 | 
				
			||||||
 | 
						char *args;
 | 
				
			||||||
 | 
						size_t size;
 | 
				
			||||||
 | 
						int res = 0;
 | 
				
			||||||
 | 
						struct pw_impl_module *mod;
 | 
				
			||||||
 | 
						struct tunnel *t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((f = open_memstream(&args, &size)) == NULL) {
 | 
				
			||||||
 | 
							res = -errno;
 | 
				
			||||||
 | 
							pw_log_error("Can't open memstream: %m");
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(f, "{");
 | 
				
			||||||
 | 
						pw_properties_serialize_dict(f, &props->dict, 0);
 | 
				
			||||||
 | 
						fprintf(f, "}");
 | 
				
			||||||
 | 
					        fclose(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_info("loading module args:'%s'", args);
 | 
				
			||||||
 | 
						mod = pw_context_load_module(impl->context,
 | 
				
			||||||
 | 
								"libpipewire-module-raop-sink",
 | 
				
			||||||
 | 
								args, NULL);
 | 
				
			||||||
 | 
						free(args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mod == NULL) {
 | 
				
			||||||
 | 
							res = -errno;
 | 
				
			||||||
 | 
							pw_log_error("Can't load module: %m");
 | 
				
			||||||
 | 
					                goto done;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t = make_tunnel(impl, tinfo);
 | 
				
			||||||
 | 
						if (t == NULL) {
 | 
				
			||||||
 | 
							res = -errno;
 | 
				
			||||||
 | 
							pw_log_error("Can't make tunnel: %m");
 | 
				
			||||||
 | 
							pw_impl_module_destroy(mod);
 | 
				
			||||||
 | 
							goto done;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_impl_module_add_listener(mod, &t->module_listener, &submodule_events, t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t->module = mod;
 | 
				
			||||||
 | 
					done:
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rule_matched(void *data, const char *location, const char *action,
 | 
				
			||||||
 | 
					                        const char *str, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct match_info *i = data;
 | 
				
			||||||
 | 
						int res = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i->matched = true;
 | 
				
			||||||
 | 
						if (spa_streq(action, "create-stream")) {
 | 
				
			||||||
 | 
							pw_properties_update_string(i->props, str, len);
 | 
				
			||||||
 | 
							create_stream(i->impl, i->props, i->tinfo);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol,
 | 
					static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol,
 | 
				
			||||||
	AvahiResolverEvent event, const char *name, const char *type, const char *domain,
 | 
						AvahiResolverEvent event, const char *name, const char *type, const char *domain,
 | 
				
			||||||
	const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt,
 | 
						const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt,
 | 
				
			||||||
	AvahiLookupResultFlags flags, void *userdata)
 | 
						AvahiLookupResultFlags flags, void *userdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = userdata;
 | 
						struct impl *impl = userdata;
 | 
				
			||||||
	struct tunnel *t;
 | 
					 | 
				
			||||||
	struct tunnel_info tinfo;
 | 
						struct tunnel_info tinfo;
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	AvahiStringList *l;
 | 
						AvahiStringList *l;
 | 
				
			||||||
	FILE *f;
 | 
					 | 
				
			||||||
	char *args;
 | 
					 | 
				
			||||||
	size_t size;
 | 
					 | 
				
			||||||
	struct pw_impl_module *mod;
 | 
					 | 
				
			||||||
	struct pw_properties *props = NULL;
 | 
						struct pw_properties *props = NULL;
 | 
				
			||||||
	char at[AVAHI_ADDRESS_STR_MAX];
 | 
						char at[AVAHI_ADDRESS_STR_MAX];
 | 
				
			||||||
	int ipv;
 | 
						int ipv;
 | 
				
			||||||
| 
						 | 
					@ -291,6 +398,7 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tinfo = TUNNEL_INFO(.interface = interface,
 | 
						tinfo = TUNNEL_INFO(.interface = interface,
 | 
				
			||||||
			.protocol = protocol,
 | 
								.protocol = protocol,
 | 
				
			||||||
 | 
								.host_name = host_name,
 | 
				
			||||||
			.name = name,
 | 
								.name = name,
 | 
				
			||||||
			.type = type,
 | 
								.type = type,
 | 
				
			||||||
			.domain = domain);
 | 
								.domain = domain);
 | 
				
			||||||
| 
						 | 
					@ -302,21 +410,14 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	avahi_address_snprint(at, sizeof(at), a);
 | 
						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", "%s", at);
 | 
				
			||||||
 | 
						pw_properties_setf(props, "raop.ip.version", "%d", ipv);
 | 
				
			||||||
	pw_properties_setf(props, "raop.port", "%u", port);
 | 
						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);
 | 
						pw_properties_setf(props, "raop.hostname", "%s", host_name);
 | 
				
			||||||
 | 
						pw_properties_setf(props, "raop.domain", "%s", domain);
 | 
				
			||||||
	ipv = protocol == AVAHI_PROTO_INET ? 4 : 6;
 | 
					 | 
				
			||||||
	if ((str = strstr(name, "@"))) {
 | 
					 | 
				
			||||||
		str++;
 | 
					 | 
				
			||||||
		if (strlen(str) > 0)
 | 
					 | 
				
			||||||
			name = str;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
 | 
					 | 
				
			||||||
				"RAOP on %s (IPv%d)", name, ipv);
 | 
					 | 
				
			||||||
	pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.%s.ipv%d",
 | 
					 | 
				
			||||||
				name, host_name, ipv);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (l = txt; l; l = l->next) {
 | 
						for (l = txt; l; l = l->next) {
 | 
				
			||||||
		char *key, *value;
 | 
							char *key, *value;
 | 
				
			||||||
| 
						 | 
					@ -329,45 +430,24 @@ static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiPr
 | 
				
			||||||
		avahi_free(value);
 | 
							avahi_free(value);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((str = pw_properties_get(impl->properties, "stream.rules")) == NULL)
 | 
				
			||||||
 | 
							str = DEFAULT_CREATE_RULES;
 | 
				
			||||||
 | 
						if (str != NULL) {
 | 
				
			||||||
 | 
							struct match_info minfo = {
 | 
				
			||||||
 | 
								.impl = impl,
 | 
				
			||||||
 | 
								.props = props,
 | 
				
			||||||
 | 
								.tinfo = &tinfo,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							pw_conf_match_rules(str, strlen(str), NAME, &props->dict,
 | 
				
			||||||
 | 
									rule_matched, &minfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((f = open_memstream(&args, &size)) == NULL) {
 | 
							if (!minfo.matched)
 | 
				
			||||||
		pw_log_error("Can't open memstream: %m");
 | 
								pw_log_info("unmatched service found %s", str);
 | 
				
			||||||
		goto done;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fprintf(f, "{");
 | 
					 | 
				
			||||||
	pw_properties_serialize_dict(f, &props->dict, 0);
 | 
					 | 
				
			||||||
	fprintf(f, " stream.props = {");
 | 
					 | 
				
			||||||
	fprintf(f, " }");
 | 
					 | 
				
			||||||
	fprintf(f, "}");
 | 
					 | 
				
			||||||
        fclose(f);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_properties_free(props);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_info("loading module args:'%s'", args);
 | 
					 | 
				
			||||||
	mod = pw_context_load_module(impl->context,
 | 
					 | 
				
			||||||
			"libpipewire-module-raop-sink",
 | 
					 | 
				
			||||||
			args, NULL);
 | 
					 | 
				
			||||||
	free(args);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mod == NULL) {
 | 
					 | 
				
			||||||
		pw_log_error("Can't load module: %m");
 | 
					 | 
				
			||||||
                goto done;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t = make_tunnel(impl, &tinfo);
 | 
					 | 
				
			||||||
	if (t == NULL) {
 | 
					 | 
				
			||||||
		pw_log_error("Can't make tunnel: %m");
 | 
					 | 
				
			||||||
		pw_impl_module_destroy(mod);
 | 
					 | 
				
			||||||
		goto done;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_impl_module_add_listener(mod, &t->module_listener, &submodule_events, t);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	t->module = mod;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
	avahi_service_resolver_free(r);
 | 
						avahi_service_resolver_free(r);
 | 
				
			||||||
 | 
						pw_properties_free(props);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,8 +57,9 @@
 | 
				
			||||||
 * Options specific to the behavior of this module
 | 
					 * Options specific to the behavior of this module
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * - `raop.ip`: The ip address of the remote end.
 | 
					 * - `raop.ip`: The ip address of the remote end.
 | 
				
			||||||
 * - `raop.hostname`: The hostname of the remote end.
 | 
					 | 
				
			||||||
 * - `raop.port`: The port of the remote end.
 | 
					 * - `raop.port`: The port of the remote end.
 | 
				
			||||||
 | 
					 * - `raop.name`: The name of the remote end.
 | 
				
			||||||
 | 
					 * - `raop.hostname`: The hostname of the remote end.
 | 
				
			||||||
 * - `raop.transport`: The data transport to use, one of "udp" or "tcp". Defaults
 | 
					 * - `raop.transport`: The data transport to use, one of "udp" or "tcp". Defaults
 | 
				
			||||||
 *                    to "udp".
 | 
					 *                    to "udp".
 | 
				
			||||||
 * - `raop.encryption.type`: The encryption type to use. One of "none", "RSA" or
 | 
					 * - `raop.encryption.type`: The encryption type to use. One of "none", "RSA" or
 | 
				
			||||||
| 
						 | 
					@ -89,8 +90,9 @@
 | 
				
			||||||
 *     args = {
 | 
					 *     args = {
 | 
				
			||||||
 *         # Set the remote address to tunnel to
 | 
					 *         # Set the remote address to tunnel to
 | 
				
			||||||
 *         raop.ip = "127.0.0.1"
 | 
					 *         raop.ip = "127.0.0.1"
 | 
				
			||||||
 *         raop.hostname = "my-raop-device"
 | 
					 | 
				
			||||||
 *         raop.port = 8190
 | 
					 *         raop.port = 8190
 | 
				
			||||||
 | 
					 *         raop.name = "my-raop-device"
 | 
				
			||||||
 | 
					 *         raop.hostname = "My Service"
 | 
				
			||||||
 *         #raop.transport = "udp"
 | 
					 *         #raop.transport = "udp"
 | 
				
			||||||
 *         raop.encryption.type = "RSA"
 | 
					 *         raop.encryption.type = "RSA"
 | 
				
			||||||
 *         #raop.audio.codec = "PCM"
 | 
					 *         #raop.audio.codec = "PCM"
 | 
				
			||||||
| 
						 | 
					@ -144,8 +146,9 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
 | 
				
			||||||
#define DEFAULT_LATENCY 22050
 | 
					#define DEFAULT_LATENCY 22050
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MODULE_USAGE	"[ raop.ip=<ip address of host> ] "					\
 | 
					#define MODULE_USAGE	"[ raop.ip=<ip address of host> ] "					\
 | 
				
			||||||
			"[ raop.hostname=<name of host> ] "					\
 | 
					 | 
				
			||||||
			"[ raop.port=<remote port> ] "						\
 | 
								"[ raop.port=<remote port> ] "						\
 | 
				
			||||||
 | 
								"[ raop.name=<name of host> ] "						\
 | 
				
			||||||
 | 
								"[ raop.hostname=<hostname of host> ] "					\
 | 
				
			||||||
			"[ raop.transport=<transport, default:udp> ] "				\
 | 
								"[ raop.transport=<transport, default:udp> ] "				\
 | 
				
			||||||
			"[ raop.encryption.type=<encryption, default:none> ] "			\
 | 
								"[ raop.encryption.type=<encryption, default:none> ] "			\
 | 
				
			||||||
			"[ raop.audio.codec=PCM ] "						\
 | 
								"[ raop.audio.codec=PCM ] "						\
 | 
				
			||||||
| 
						 | 
					@ -1522,8 +1525,7 @@ static int rtsp_do_teardown(struct impl *impl)
 | 
				
			||||||
	if (!impl->ready)
 | 
						if (!impl->ready)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pw_rtsp_client_send(impl->rtsp, "TEARDOWN", NULL,
 | 
						return rtsp_send(impl, "TEARDOWN", NULL, NULL, rtsp_teardown_reply);
 | 
				
			||||||
			NULL, NULL, rtsp_teardown_reply, impl);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *param)
 | 
					static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *param)
 | 
				
			||||||
| 
						 | 
					@ -1759,7 +1761,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_context *context = pw_impl_module_get_context(module);
 | 
				
			||||||
	struct pw_properties *props = NULL;
 | 
						struct pw_properties *props = NULL;
 | 
				
			||||||
	struct impl *impl;
 | 
						struct impl *impl;
 | 
				
			||||||
	const char *str;
 | 
						const char *str, *name, *hostname, *ipv;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PW_LOG_TOPIC_INIT(mod_topic);
 | 
						PW_LOG_TOPIC_INIT(mod_topic);
 | 
				
			||||||
| 
						 | 
					@ -1806,13 +1808,25 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
				
			||||||
	if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
 | 
						if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
 | 
				
			||||||
		pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
 | 
							pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
 | 
						if ((name = pw_properties_get(props, "raop.name")) == NULL)
 | 
				
			||||||
		pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_output.%s",
 | 
							name = "RAOP";
 | 
				
			||||||
				pw_properties_get(props, "raop.hostname"));
 | 
					
 | 
				
			||||||
 | 
						if ((str = strstr(name, "@"))) {
 | 
				
			||||||
 | 
							str++;
 | 
				
			||||||
 | 
							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_DESCRIPTION) == NULL)
 | 
						if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
 | 
				
			||||||
		pw_properties_set(props, PW_KEY_NODE_DESCRIPTION,
 | 
							pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION,
 | 
				
			||||||
				pw_properties_get(props, PW_KEY_NODE_NAME));
 | 
										"%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);
 | 
				
			||||||
	if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL)
 | 
						if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL)
 | 
				
			||||||
		pw_properties_set(props, PW_KEY_NODE_LATENCY, "352/44100");
 | 
							pw_properties_set(props, PW_KEY_NODE_LATENCY, "352/44100");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue