X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/ff38eaf67773e0039befb95c0f9ad91e7a06fc3f..a41c510e42db7fc20b0e6abf7bc56a747e7d5a35:/src/modules/module-zeroconf-publish.c diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 692ffe91..d72d2647 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include "module-zeroconf-publish-symdef.h" @@ -54,7 +56,6 @@ PA_MODULE_AUTHOR("Lennart Poettering"); PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); -PA_MODULE_USAGE("port="); #define SERVICE_TYPE_SINK "_pulse-sink._tcp" #define SERVICE_TYPE_SOURCE "_pulse-source._tcp" @@ -67,7 +68,6 @@ PA_MODULE_USAGE("port="); #define SERVICE_SUBTYPE_SOURCE_NON_MONITOR "_non-monitor._sub."SERVICE_TYPE_SOURCE static const char* const valid_modargs[] = { - "port", NULL }; @@ -88,6 +88,7 @@ struct service { struct userdata { pa_core *core; pa_module *module; + AvahiPoll *avahi_poll; AvahiClient *client; @@ -96,15 +97,15 @@ struct userdata { AvahiEntryGroup *main_entry_group; - uint16_t port; - pa_hook_slot *sink_new_slot, *source_new_slot, *sink_unlink_slot, *source_unlink_slot, *sink_changed_slot, *source_changed_slot; + + pa_native_protocol *native; }; -static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_channel_map *ret_map, const char **ret_name, const char **ret_description, enum service_subtype *ret_subtype) { +static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_channel_map *ret_map, const char **ret_name, pa_proplist **ret_proplist, enum service_subtype *ret_subtype) { pa_assert(s); pa_assert(ret_ss); - pa_assert(ret_description); + pa_assert(ret_proplist); pa_assert(ret_subtype); if (pa_sink_isinstance(s->device)) { @@ -113,7 +114,7 @@ static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_chann *ret_ss = sink->sample_spec; *ret_map = sink->channel_map; *ret_name = sink->name; - *ret_description = pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)); + *ret_proplist = sink->proplist; *ret_subtype = sink->flags & PA_SINK_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL; } else if (pa_source_isinstance(s->device)) { @@ -122,7 +123,7 @@ static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_chann *ret_ss = source->sample_spec; *ret_map = source->channel_map; *ret_name = source->name; - *ret_description = pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)); + *ret_proplist = source->proplist; *ret_subtype = source->monitor_of ? SUBTYPE_MONITOR : (source->flags & PA_SOURCE_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL); } else @@ -131,11 +132,24 @@ static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_chann static AvahiStringList* txt_record_server_data(pa_core *c, AvahiStringList *l) { char s[128]; + char *t; pa_assert(c); l = avahi_string_list_add_pair(l, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); - l = avahi_string_list_add_pair(l, "user-name", pa_get_user_name(s, sizeof(s))); + + t = pa_get_user_name_malloc(); + l = avahi_string_list_add_pair(l, "user-name", t); + pa_xfree(t); + + t = pa_machine_id(); + l = avahi_string_list_add_pair(l, "machine-id", t); + pa_xfree(t); + + t = pa_uname_string(); + l = avahi_string_list_add_pair(l, "uname", t); + pa_xfree(t); + l = avahi_string_list_add_pair(l, "fqdn", pa_get_fqdn(s, sizeof(s))); l = avahi_string_list_add_printf(l, "cookie=0x%08x", c->cookie); @@ -184,10 +198,35 @@ static void service_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupStat static void service_free(struct service *s); +static uint16_t compute_port(struct userdata *u) { + pa_strlist *i; + + pa_assert(u); + + for (i = pa_native_protocol_servers(u->native); i; i = pa_strlist_next(i)) { + pa_parsed_address a; + + if (pa_parse_address(pa_strlist_data(i), &a) >= 0 && + (a.type == PA_PARSED_ADDRESS_TCP4 || + a.type == PA_PARSED_ADDRESS_TCP6 || + a.type == PA_PARSED_ADDRESS_TCP_AUTO) && + a.port > 0) { + + pa_xfree(a.path_or_host); + return a.port; + } + + pa_xfree(a.path_or_host); + } + + return PA_NATIVE_DEFAULT_PORT; +} + static int publish_service(struct service *s) { int r = -1; AvahiStringList *txt = NULL; - const char *description = NULL, *name = NULL; + const char *name = NULL, *t; + pa_proplist *proplist = NULL; pa_sample_spec ss; pa_channel_map map; char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; @@ -214,7 +253,7 @@ static int publish_service(struct service *s) { txt = txt_record_server_data(s->userdata->core, txt); - get_service_data(s, &ss, &map, &name, &description, &subtype); + get_service_data(s, &ss, &map, &name, &proplist, &subtype); txt = avahi_string_list_add_pair(txt, "device", name); txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate); txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels); @@ -222,6 +261,19 @@ static int publish_service(struct service *s) { txt = avahi_string_list_add_pair(txt, "channel_map", pa_channel_map_snprint(cm, sizeof(cm), &map)); txt = avahi_string_list_add_pair(txt, "subtype", subtype_text[subtype]); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_DESCRIPTION))) + txt = avahi_string_list_add_pair(txt, "description", t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_ICON_NAME))) + txt = avahi_string_list_add_pair(txt, "icon-name", t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_VENDOR_NAME))) + txt = avahi_string_list_add_pair(txt, "vendor-name", t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_PRODUCT_NAME))) + txt = avahi_string_list_add_pair(txt, "product-name", t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_CLASS))) + txt = avahi_string_list_add_pair(txt, "class", t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_FORM_FACTOR))) + txt = avahi_string_list_add_pair(txt, "form-factor", t); + if (avahi_entry_group_add_service_strlst( s->entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, @@ -230,7 +282,7 @@ static int publish_service(struct service *s) { pa_sink_isinstance(s->device) ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, NULL, NULL, - s->userdata->port, + compute_port(s->userdata), txt) < 0) { pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(s->userdata->client))); @@ -287,7 +339,7 @@ finish: static struct service *get_service(struct userdata *u, pa_object *device) { struct service *s; - char hn[64], un[64]; + char *hn, *un; const char *n; pa_assert(u); @@ -309,11 +361,13 @@ static struct service *get_service(struct userdata *u, pa_object *device) { n = PA_SOURCE(device)->name; } - s->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s: %s", - pa_get_user_name(un, sizeof(un)), - pa_get_host_name(hn, sizeof(hn)), - n), - AVAHI_LABEL_MAX-1); + hn = pa_get_host_name_malloc(); + un = pa_get_user_name_malloc(); + + s->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s: %s", un, hn, n), AVAHI_LABEL_MAX-1); + + pa_xfree(un); + pa_xfree(hn); pa_hashmap_put(u->services, s->device, s); @@ -430,7 +484,7 @@ static int publish_main_service(struct userdata *u) { SERVICE_TYPE_SERVER, NULL, NULL, - u->port, + compute_port(u), txt) < 0) { pa_log("avahi_entry_group_add_service_strlst() failed: %s", avahi_strerror(avahi_client_errno(u->client))); @@ -552,9 +606,8 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda int pa__init(pa_module*m) { struct userdata *u; - uint32_t port = PA_NATIVE_DEFAULT_PORT; pa_modargs *ma = NULL; - char hn[256], un[256]; + char *hn, *un; int error; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -562,15 +615,10 @@ int pa__init(pa_module*m) { goto fail; } - if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port <= 0 || port > 0xFFFF) { - pa_log("Invalid port specified."); - goto fail; - } - m->userdata = u = pa_xnew(struct userdata, 1); u->core = m->core; u->module = m; - u->port = (uint16_t) port; + u->native = pa_native_protocol_get(u->core); u->avahi_poll = pa_avahi_poll_new(m->core->mainloop); @@ -585,7 +633,11 @@ int pa__init(pa_module*m) { u->main_entry_group = NULL; - u->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s", pa_get_user_name(un, sizeof(un)), pa_get_host_name(hn, sizeof(hn))), AVAHI_LABEL_MAX); + un = pa_get_user_name_malloc(); + hn = pa_get_host_name_malloc(); + u->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s", un, hn), AVAHI_LABEL_MAX-1); + pa_xfree(un); + pa_xfree(hn); if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) { pa_log("avahi_client_new() failed: %s", avahi_strerror(error)); @@ -643,6 +695,9 @@ void pa__done(pa_module*m) { if (u->avahi_poll) pa_avahi_poll_free(u->avahi_poll); + if (u->native) + pa_native_protocol_unref(u->native); + pa_xfree(u->service_name); pa_xfree(u); }