diff options
author | Sylvain Baubeau <lebauce@gmail.com> | 2016-09-01 11:14:05 +0200 |
---|---|---|
committer | Tanu Kaskinen <tanuk@iki.fi> | 2016-09-05 18:59:03 +0300 |
commit | 963b3ea695a7dd62efd7cb3ccbc930d53b88fabf (patch) | |
tree | 93f0c097bcfbaa18a2ea9cf775778d9404c0f51a | |
parent | 83f0a34ea6c6a6599207cacab29cced81e787001 (diff) |
zeroconf: use local icon for shared devices
systemd-hostnamed provides an icon for the machine it is running on.
If it is running, module-zeroconf-publish uses this icon for the
'icon-name' attribute in the Avahi properties. module-zeroconf-discover
passes this icon to module-tunnel using the module parameter
{sink/source}_properties.
This allows to display a portable, desktop or phone instead of
the generic sound card icon.
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/modules/module-zeroconf-discover.c | 9 | ||||
-rw-r--r-- | src/modules/module-zeroconf-publish.c | 84 |
3 files changed, 93 insertions, 4 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 7b194975..2d5bdd49 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1899,8 +1899,8 @@ module_solaris_la_LIBADD = $(MODULE_LIBADD) module_zeroconf_publish_la_SOURCES = modules/module-zeroconf-publish.c module_zeroconf_publish_la_LDFLAGS = $(MODULE_LDFLAGS) -module_zeroconf_publish_la_LIBADD = $(MODULE_LIBADD) $(AVAHI_LIBS) libavahi-wrap.la libprotocol-native.la -module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) +module_zeroconf_publish_la_LIBADD = $(MODULE_LIBADD) $(AVAHI_LIBS) $(DBUS_LIBS) libavahi-wrap.la libprotocol-native.la +module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS) $(DBUS_CFLAGS) module_zeroconf_discover_la_SOURCES = modules/module-zeroconf-discover.c module_zeroconf_discover_la_LDFLAGS = $(MODULE_LDFLAGS) diff --git a/src/modules/module-zeroconf-discover.c b/src/modules/module-zeroconf-discover.c index a1655798..bd7e6abe 100644 --- a/src/modules/module-zeroconf-discover.c +++ b/src/modules/module-zeroconf-discover.c @@ -149,6 +149,7 @@ static void resolver_cb( const char *t; char *if_suffix = NULL; char at[AVAHI_ADDRESS_STR_MAX], cmt[PA_CHANNEL_MAP_SNPRINT_MAX]; + char *properties = NULL; pa_sample_spec ss; pa_channel_map cm; AvahiStringList *l; @@ -172,6 +173,8 @@ static void resolver_cb( ss.channels = (uint8_t) atoi(value); else if (pa_streq(key, "format")) ss.format = pa_parse_sample_format(value); + else if (pa_streq(key, "icon-name")) + properties = pa_sprintf_malloc("device.icon_name=%s", value); else if (pa_streq(key, "channel_map")) { pa_channel_map_parse(&cm, value); channel_map_set = true; @@ -187,12 +190,14 @@ static void resolver_cb( if (!pa_sample_spec_valid(&ss)) { pa_log("Service '%s' contains an invalid sample specification.", name); avahi_free(device); + pa_xfree(properties); goto finish; } if (!pa_channel_map_valid(&cm) || cm.channels != ss.channels) { pa_log("Service '%s' contains an invalid channel map.", name); avahi_free(device); + pa_xfree(properties); goto finish; } @@ -205,6 +210,7 @@ static void resolver_cb( pa_log("Cannot construct valid device name from credentials of service '%s'.", dname); avahi_free(device); pa_xfree(dname); + pa_xfree(properties); goto finish; } @@ -220,6 +226,7 @@ static void resolver_cb( "format=%s " "channels=%u " "rate=%u " + "%s_properties=%s " "%s_name=%s " "channel_map=%s", avahi_address_snprint(at, sizeof(at), a), @@ -228,6 +235,7 @@ static void resolver_cb( pa_sample_format_to_string(ss.format), ss.channels, ss.rate, + t, properties ? properties : "", t, dname, pa_channel_map_snprint(cmt, sizeof(cmt), &cm)); @@ -243,6 +251,7 @@ static void resolver_cb( pa_xfree(dname); pa_xfree(args); pa_xfree(if_suffix); + pa_xfree(properties); avahi_free(device); } diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 6ca0369a..1816c749 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -46,6 +46,14 @@ #include <pulsecore/avahi-wrap.h> #include <pulsecore/protocol-native.h> +#ifdef HAVE_DBUS +#include <pulsecore/dbus-shared.h> + +#define HOSTNAME_DBUS_INTERFACE "org.freedesktop.hostname1" +#define HOSTNAME_DBUS_PATH "/org/freedesktop/hostname1" +#define HOSTNAME_DBUS_ICON_PROPERTY "IconName" +#endif + #include "module-zeroconf-publish-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering"); @@ -133,6 +141,7 @@ struct userdata { pa_hashmap *services; /* protect with mainloop lock */ char *service_name; + char *icon_name; AvahiEntryGroup *main_entry_group; @@ -308,8 +317,6 @@ static void publish_service(pa_mainloop_api *api PA_GCC_UNUSED, void *service) { if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION))) txt = avahi_string_list_add_pair(txt, "description", t); - if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_ICON_NAME))) - txt = avahi_string_list_add_pair(txt, "icon-name", t); if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_VENDOR_NAME))) txt = avahi_string_list_add_pair(txt, "vendor-name", t); if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_PRODUCT_NAME))) @@ -319,6 +326,12 @@ static void publish_service(pa_mainloop_api *api PA_GCC_UNUSED, void *service) { if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_FORM_FACTOR))) txt = avahi_string_list_add_pair(txt, "form-factor", t); + if (s->userdata->icon_name) { + txt = avahi_string_list_add_pair(txt, "icon-name", s->userdata->icon_name); + } else if ((t = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_ICON_NAME))) { + txt = avahi_string_list_add_pair(txt, "icon-name", t); + } + if (avahi_entry_group_add_service_strlst( s->entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, @@ -653,6 +666,66 @@ static int avahi_process_msg(pa_msgobject *o, int code, void *data, int64_t offs return 0; } +#ifdef HAVE_DBUS +static char *get_icon_name(pa_module*m) { + const char *interface = HOSTNAME_DBUS_INTERFACE; + const char *property = HOSTNAME_DBUS_ICON_PROPERTY; + char *icon_name; + pa_dbus_connection *bus; + DBusError error; + DBusMessageIter args; + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + DBusConnection *conn = NULL; + DBusMessageIter sub; + + if (!(bus = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error))) { + pa_log("Failed to get system bus connection: %s", error.message); + goto out; + } + + conn = pa_dbus_connection_get(bus); + + msg = dbus_message_new_method_call(HOSTNAME_DBUS_INTERFACE, + HOSTNAME_DBUS_PATH, + "org.freedesktop.DBus.Properties", + "Get"); + dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); + + dbus_error_init(&error); + if ((reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &error)) == NULL) { + pa_log("Failed to send: %s:%s", error.name, error.message); + dbus_error_free(&error); + goto out; + } + + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) { + pa_log("Incorrect reply type"); + goto out; + } + + dbus_message_iter_recurse(&args, &sub); + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { + pa_log("Incorrect value type"); + goto out; + } + + dbus_message_iter_get_basic(&sub, &icon_name); + icon_name = pa_xstrdup(icon_name); + +out: + if (reply) + dbus_message_unref(reply); + + if (msg) + dbus_message_unref(msg); + + return icon_name; +} +#endif + /* Runs in Avahi mainloop context */ static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { struct userdata *u = userdata; @@ -666,6 +739,12 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void *userda case AVAHI_CLIENT_S_RUNNING: /* Collect all sinks/sources, and publish them */ pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->msg), AVAHI_MESSAGE_PUBLISH_ALL, u, 0, NULL, NULL); + +#ifdef HAVE_DBUS + /* Request icon name through D-BUS */ + u->icon_name = get_icon_name(u->module); +#endif + break; case AVAHI_CLIENT_S_COLLISION: @@ -844,5 +923,6 @@ void pa__done(pa_module*m) { pa_xfree(u->msg); pa_xfree(u->service_name); + pa_xfree(u->icon_name); pa_xfree(u); } |