mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-02 01:40:31 -05:00
pulse-server: port zeroconf publish to helper
This commit is contained in:
parent
c09bcfdc97
commit
a1db2b8d35
1 changed files with 136 additions and 335 deletions
|
|
@ -15,14 +15,7 @@
|
|||
#include "../module.h"
|
||||
#include "../pulse-server.h"
|
||||
#include "../server.h"
|
||||
#include "../../zeroconf-utils/avahi-poll.h"
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
#include <avahi-common/alternative.h>
|
||||
#include <avahi-common/error.h>
|
||||
#include <avahi-common/domain.h>
|
||||
#include <avahi-common/malloc.h>
|
||||
#include "../../zeroconf-utils/zeroconf.h"
|
||||
|
||||
/** \page page_pulse_module_zeroconf_publish Zeroconf Publish
|
||||
*
|
||||
|
|
@ -52,32 +45,17 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
|
||||
#define SERVICE_DATA_ID "module-zeroconf-publish.service"
|
||||
|
||||
enum service_subtype {
|
||||
SUBTYPE_HARDWARE,
|
||||
SUBTYPE_VIRTUAL,
|
||||
SUBTYPE_MONITOR
|
||||
};
|
||||
|
||||
struct service {
|
||||
struct spa_list link;
|
||||
|
||||
struct module_zeroconf_publish_data *userdata;
|
||||
|
||||
AvahiEntryGroup *entry_group;
|
||||
AvahiStringList *txt;
|
||||
struct server *server;
|
||||
|
||||
const char *service_type;
|
||||
enum service_subtype subtype;
|
||||
|
||||
char *name;
|
||||
bool is_sink;
|
||||
|
||||
struct sample_spec ss;
|
||||
struct channel_map cm;
|
||||
struct pw_properties *props;
|
||||
|
||||
char service_name[AVAHI_LABEL_MAX];
|
||||
unsigned published:1;
|
||||
};
|
||||
|
||||
|
|
@ -91,8 +69,8 @@ struct module_zeroconf_publish_data {
|
|||
struct spa_hook manager_listener;
|
||||
struct spa_hook impl_listener;
|
||||
|
||||
AvahiPoll *avahi_poll;
|
||||
AvahiClient *client;
|
||||
struct pw_zeroconf *zeroconf;
|
||||
struct spa_hook zeroconf_listener;
|
||||
|
||||
/* lists of services */
|
||||
struct spa_list pending;
|
||||
|
|
@ -116,47 +94,43 @@ static const struct pw_core_events core_events = {
|
|||
.error = on_core_error,
|
||||
};
|
||||
|
||||
static void get_service_name(struct pw_manager_object *o, char *buf, size_t length)
|
||||
static void unpublish_service(struct service *s)
|
||||
{
|
||||
const char *hn, *un, *n;
|
||||
const char *device;
|
||||
|
||||
hn = pw_get_host_name();
|
||||
un = pw_get_user_name();
|
||||
n = pw_properties_get(o->props, PW_KEY_NODE_DESCRIPTION);
|
||||
spa_list_remove(&s->link);
|
||||
spa_list_append(&s->userdata->pending, &s->link);
|
||||
s->published = false;
|
||||
s->server = NULL;
|
||||
|
||||
snprintf(buf, length, "%s@%s: %s", un, hn, n);
|
||||
device = pw_properties_get(s->props, "device");
|
||||
|
||||
pw_log_info("unpublished service: %s", device);
|
||||
|
||||
pw_zeroconf_set_announce(s->userdata->zeroconf, s, NULL);
|
||||
}
|
||||
|
||||
static void unpublish_all_services(struct module_zeroconf_publish_data *d)
|
||||
{
|
||||
struct service *s;
|
||||
spa_list_consume(s, &d->published, link)
|
||||
unpublish_service(s);
|
||||
}
|
||||
|
||||
static void service_free(struct service *s)
|
||||
{
|
||||
pw_log_debug("service %p: free", s);
|
||||
|
||||
if (s->entry_group)
|
||||
avahi_entry_group_free(s->entry_group);
|
||||
|
||||
if (s->name)
|
||||
free(s->name);
|
||||
if (s->published)
|
||||
unpublish_service(s);
|
||||
|
||||
pw_properties_free(s->props);
|
||||
avahi_string_list_free(s->txt);
|
||||
spa_list_remove(&s->link);
|
||||
/* no need to free, the service is added as custom
|
||||
* data on the object */
|
||||
}
|
||||
|
||||
static void unpublish_service(struct service *s)
|
||||
{
|
||||
spa_list_remove(&s->link);
|
||||
spa_list_append(&s->userdata->pending, &s->link);
|
||||
s->published = false;
|
||||
s->server = NULL;
|
||||
}
|
||||
|
||||
static void unpublish_all_services(struct module_zeroconf_publish_data *d)
|
||||
{
|
||||
struct service *s;
|
||||
|
||||
spa_list_consume(s, &d->published, link)
|
||||
unpublish_service(s);
|
||||
}
|
||||
#define PA_CHANNEL_MAP_SNPRINT_MAX (CHANNELS_MAX * 32)
|
||||
|
||||
static char* channel_map_snprint(char *s, size_t l, const struct channel_map *map)
|
||||
{
|
||||
|
|
@ -188,6 +162,39 @@ static char* channel_map_snprint(char *s, size_t l, const struct channel_map *ma
|
|||
return s;
|
||||
}
|
||||
|
||||
static void txt_record_server_data(struct pw_core_info *info, struct pw_properties *props)
|
||||
{
|
||||
struct utsname u;
|
||||
|
||||
spa_assert(info);
|
||||
|
||||
pw_properties_set(props, "server-version", PACKAGE_NAME" "PACKAGE_VERSION);
|
||||
pw_properties_set(props, "user-name", pw_get_user_name());
|
||||
pw_properties_set(props, "fqdn", pw_get_host_name());
|
||||
pw_properties_setf(props, "cookie", "0x%08x", info->cookie);
|
||||
if (uname(&u) >= 0)
|
||||
pw_properties_setf(props, "uname", "%s %s %s", u.sysname, u.machine, u.release);
|
||||
}
|
||||
|
||||
static void fill_service_txt(const struct service *s, const struct pw_properties *props)
|
||||
{
|
||||
static const struct mapping {
|
||||
const char *pw_key, *txt_key;
|
||||
} mappings[] = {
|
||||
{ PW_KEY_NODE_DESCRIPTION, "description" },
|
||||
{ PW_KEY_DEVICE_VENDOR_NAME, "vendor-name" },
|
||||
{ PW_KEY_DEVICE_PRODUCT_NAME, "product-name" },
|
||||
{ PW_KEY_DEVICE_CLASS, "class" },
|
||||
{ PW_KEY_DEVICE_FORM_FACTOR, "form-factor" },
|
||||
{ PW_KEY_DEVICE_ICON_NAME, "icon-name" },
|
||||
};
|
||||
SPA_FOR_EACH_ELEMENT_VAR(mappings, m) {
|
||||
const char *value = pw_properties_get(props, m->pw_key);
|
||||
if (value != NULL)
|
||||
pw_properties_set(s->props, m->txt_key, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_service_data(struct module_zeroconf_publish_data *d, struct service *s,
|
||||
struct pw_manager_object *o)
|
||||
{
|
||||
|
|
@ -200,6 +207,10 @@ static void fill_service_data(struct module_zeroconf_publish_data *d, struct ser
|
|||
struct card_info card_info = CARD_INFO_INIT;
|
||||
struct device_info dev_info;
|
||||
uint32_t flags = 0;
|
||||
const char *service_type, *subtype, *subtype_service[2];
|
||||
uint32_t n_subtype = 0;
|
||||
char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
|
||||
|
||||
|
||||
if (info == NULL || info->props == NULL)
|
||||
return;
|
||||
|
|
@ -228,19 +239,49 @@ static void fill_service_data(struct module_zeroconf_publish_data *d, struct ser
|
|||
|
||||
s->ss = dev_info.ss;
|
||||
s->cm = dev_info.map;
|
||||
s->name = strdup(name);
|
||||
s->props = pw_properties_copy(o->props);
|
||||
|
||||
s->props = pw_properties_new(NULL, NULL);
|
||||
|
||||
txt_record_server_data(s->userdata->manager->info, s->props);
|
||||
|
||||
if (is_sink) {
|
||||
s->is_sink = true;
|
||||
s->service_type = SERVICE_TYPE_SINK;
|
||||
s->subtype = flags & SINK_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL;
|
||||
service_type = SERVICE_TYPE_SINK;
|
||||
if (flags & SINK_HARDWARE) {
|
||||
subtype = "hardware";
|
||||
subtype_service[n_subtype++] = SERVICE_SUBTYPE_SINK_HARDWARE;
|
||||
} else {
|
||||
subtype = "virtual";
|
||||
subtype_service[n_subtype++] = SERVICE_SUBTYPE_SINK_VIRTUAL;
|
||||
}
|
||||
} else if (is_source) {
|
||||
s->is_sink = false;
|
||||
s->service_type = SERVICE_TYPE_SOURCE;
|
||||
s->subtype = flags & SOURCE_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL;
|
||||
service_type = SERVICE_TYPE_SOURCE;
|
||||
if (flags & SOURCE_HARDWARE) {
|
||||
subtype = "hardware";
|
||||
subtype_service[n_subtype++] = SERVICE_SUBTYPE_SOURCE_HARDWARE;
|
||||
} else {
|
||||
subtype = "virtual";
|
||||
subtype_service[n_subtype++] = SERVICE_SUBTYPE_SOURCE_VIRTUAL;
|
||||
}
|
||||
subtype_service[n_subtype++] = SERVICE_SUBTYPE_SOURCE_NON_MONITOR;
|
||||
} else
|
||||
spa_assert_not_reached();
|
||||
|
||||
pw_properties_set(s->props, "device", name);
|
||||
pw_properties_setf(s->props, "rate", "%u", s->ss.rate);
|
||||
pw_properties_setf(s->props, "channels", "%u", s->ss.channels);
|
||||
pw_properties_set(s->props, "format", format_id2paname(s->ss.format));
|
||||
pw_properties_set(s->props, "channel_map", channel_map_snprint(cm, sizeof(cm), &s->cm));
|
||||
pw_properties_set(s->props, "subtype", subtype);
|
||||
|
||||
pw_properties_setf(s->props, "zeroconf.session", "%s@%s: %s",
|
||||
pw_get_user_name(), pw_get_host_name(), desc);
|
||||
pw_properties_set(s->props, "zeroconf.service", service_type);
|
||||
pw_properties_setf(s->props, "zeroconf.subtypes", "[ %s%s%s ]",
|
||||
n_subtype > 0 ? subtype_service[0] : "",
|
||||
n_subtype > 1 ? ", " : "",
|
||||
n_subtype > 1 ? subtype_service[1] : "");
|
||||
|
||||
fill_service_txt(s, o->props);
|
||||
}
|
||||
|
||||
static struct service *create_service(struct module_zeroconf_publish_data *d, struct pw_manager_object *o)
|
||||
|
|
@ -252,8 +293,6 @@ static struct service *create_service(struct module_zeroconf_publish_data *d, st
|
|||
return NULL;
|
||||
|
||||
s->userdata = d;
|
||||
s->entry_group = NULL;
|
||||
get_service_name(o, s->service_name, sizeof(s->service_name));
|
||||
spa_list_append(&d->pending, &s->link);
|
||||
|
||||
fill_service_data(d, s, o);
|
||||
|
|
@ -263,127 +302,6 @@ static struct service *create_service(struct module_zeroconf_publish_data *d, st
|
|||
return s;
|
||||
}
|
||||
|
||||
static AvahiStringList* txt_record_server_data(struct pw_core_info *info, AvahiStringList *l)
|
||||
{
|
||||
const char *t;
|
||||
struct utsname u;
|
||||
|
||||
spa_assert(info);
|
||||
|
||||
l = avahi_string_list_add_pair(l, "server-version", PACKAGE_NAME" "PACKAGE_VERSION);
|
||||
|
||||
t = pw_get_user_name();
|
||||
l = avahi_string_list_add_pair(l, "user-name", t);
|
||||
|
||||
if (uname(&u) >= 0) {
|
||||
char sysname[sizeof(u.sysname) + sizeof(u.machine) + sizeof(u.release)];
|
||||
|
||||
snprintf(sysname, sizeof(sysname), "%s %s %s", u.sysname, u.machine, u.release);
|
||||
l = avahi_string_list_add_pair(l, "uname", sysname);
|
||||
}
|
||||
|
||||
t = pw_get_host_name();
|
||||
l = avahi_string_list_add_pair(l, "fqdn", t);
|
||||
l = avahi_string_list_add_printf(l, "cookie=0x%08x", info->cookie);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void clear_entry_group(struct service *s)
|
||||
{
|
||||
if (s->entry_group == NULL)
|
||||
return;
|
||||
|
||||
avahi_entry_group_free(s->entry_group);
|
||||
s->entry_group = NULL;
|
||||
}
|
||||
|
||||
static void publish_service(struct service *s);
|
||||
|
||||
static void service_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
|
||||
{
|
||||
struct service *s = userdata;
|
||||
|
||||
spa_assert(s);
|
||||
if (!s->published) {
|
||||
pw_log_info("cancel unpublished service: %s", s->service_name);
|
||||
clear_entry_group(s);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||
pw_log_info("established service: %s", s->service_name);
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_COLLISION:
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = avahi_alternative_service_name(s->service_name);
|
||||
pw_log_info("service name collision: renaming '%s' to '%s'", s->service_name, t);
|
||||
snprintf(s->service_name, sizeof(s->service_name), "%s", t);
|
||||
avahi_free(t);
|
||||
|
||||
unpublish_service(s);
|
||||
publish_service(s);
|
||||
break;
|
||||
}
|
||||
case AVAHI_ENTRY_GROUP_FAILURE:
|
||||
pw_log_error("failed to establish service '%s': %s",
|
||||
s->service_name,
|
||||
avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
|
||||
unpublish_service(s);
|
||||
clear_entry_group(s);
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||
case AVAHI_ENTRY_GROUP_REGISTERING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define PA_CHANNEL_MAP_SNPRINT_MAX (CHANNELS_MAX * 32)
|
||||
|
||||
static AvahiStringList *get_service_txt(const struct service *s)
|
||||
{
|
||||
static const char * const subtype_text[] = {
|
||||
[SUBTYPE_HARDWARE] = "hardware",
|
||||
[SUBTYPE_VIRTUAL] = "virtual",
|
||||
[SUBTYPE_MONITOR] = "monitor"
|
||||
};
|
||||
|
||||
static const struct mapping {
|
||||
const char *pw_key, *txt_key;
|
||||
} mappings[] = {
|
||||
{ PW_KEY_NODE_DESCRIPTION, "description" },
|
||||
{ PW_KEY_DEVICE_VENDOR_NAME, "vendor-name" },
|
||||
{ PW_KEY_DEVICE_PRODUCT_NAME, "product-name" },
|
||||
{ PW_KEY_DEVICE_CLASS, "class" },
|
||||
{ PW_KEY_DEVICE_FORM_FACTOR, "form-factor" },
|
||||
{ PW_KEY_DEVICE_ICON_NAME, "icon-name" },
|
||||
};
|
||||
|
||||
char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
|
||||
AvahiStringList *txt = NULL;
|
||||
|
||||
txt = txt_record_server_data(s->userdata->manager->info, txt);
|
||||
|
||||
txt = avahi_string_list_add_pair(txt, "device", s->name);
|
||||
txt = avahi_string_list_add_printf(txt, "rate=%u", s->ss.rate);
|
||||
txt = avahi_string_list_add_printf(txt, "channels=%u", s->ss.channels);
|
||||
txt = avahi_string_list_add_pair(txt, "format", format_id2paname(s->ss.format));
|
||||
txt = avahi_string_list_add_pair(txt, "channel_map", channel_map_snprint(cm, sizeof(cm), &s->cm));
|
||||
txt = avahi_string_list_add_pair(txt, "subtype", subtype_text[s->subtype]);
|
||||
|
||||
SPA_FOR_EACH_ELEMENT_VAR(mappings, m) {
|
||||
const char *value = pw_properties_get(s->props, m->pw_key);
|
||||
if (value != NULL)
|
||||
txt = avahi_string_list_add_pair(txt, m->txt_key, value);
|
||||
}
|
||||
|
||||
return txt;
|
||||
}
|
||||
|
||||
static struct server *find_server(struct service *s, int *proto, uint16_t *port)
|
||||
{
|
||||
struct module_zeroconf_publish_data *d = s->userdata;
|
||||
|
|
@ -392,109 +310,47 @@ static struct server *find_server(struct service *s, int *proto, uint16_t *port)
|
|||
|
||||
spa_list_for_each(server, &impl->servers, link) {
|
||||
if (server->addr.ss_family == AF_INET) {
|
||||
*proto = AVAHI_PROTO_INET;
|
||||
*proto = 4;
|
||||
*port = ntohs(((struct sockaddr_in*) &server->addr)->sin_port);
|
||||
return server;
|
||||
} else if (server->addr.ss_family == AF_INET6) {
|
||||
*proto = AVAHI_PROTO_INET6;
|
||||
*proto = 6;
|
||||
*port = ntohs(((struct sockaddr_in6*) &server->addr)->sin6_port);
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void publish_service(struct service *s)
|
||||
{
|
||||
struct module_zeroconf_publish_data *d = s->userdata;
|
||||
int proto;
|
||||
int proto, res;
|
||||
uint16_t port;
|
||||
|
||||
struct server *server = find_server(s, &proto, &port);
|
||||
const char *device;
|
||||
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
device = pw_properties_get(s->props, "device");
|
||||
|
||||
pw_log_debug("found server:%p proto:%d port:%d", server, proto, port);
|
||||
|
||||
if (!d->client || avahi_client_get_state(d->client) != AVAHI_CLIENT_S_RUNNING)
|
||||
pw_properties_setf(s->props, "zeroconf.proto", "%d", proto);
|
||||
pw_properties_setf(s->props, "zeroconf.port", "%d", port);
|
||||
|
||||
if ((res = pw_zeroconf_set_announce(s->userdata->zeroconf, s, &s->props->dict)) < 0) {
|
||||
pw_log_error("failed to announce service %s: %s", device, spa_strerror(res));
|
||||
return;
|
||||
|
||||
s->published = true;
|
||||
if (!s->entry_group) {
|
||||
s->entry_group = avahi_entry_group_new(d->client, service_entry_group_callback, s);
|
||||
if (s->entry_group == NULL) {
|
||||
pw_log_error("avahi_entry_group_new(): %s",
|
||||
avahi_strerror(avahi_client_errno(d->client)));
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
avahi_entry_group_reset(s->entry_group);
|
||||
}
|
||||
|
||||
if (s->txt == NULL)
|
||||
s->txt = get_service_txt(s);
|
||||
|
||||
if (avahi_entry_group_add_service_strlst(
|
||||
s->entry_group,
|
||||
AVAHI_IF_UNSPEC, proto,
|
||||
0,
|
||||
s->service_name,
|
||||
s->service_type,
|
||||
NULL,
|
||||
NULL,
|
||||
port,
|
||||
s->txt) < 0) {
|
||||
pw_log_error("avahi_entry_group_add_service_strlst(): %s",
|
||||
avahi_strerror(avahi_client_errno(d->client)));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (avahi_entry_group_add_service_subtype(
|
||||
s->entry_group,
|
||||
AVAHI_IF_UNSPEC, proto,
|
||||
0,
|
||||
s->service_name,
|
||||
s->service_type,
|
||||
NULL,
|
||||
s->is_sink ? (s->subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SINK_HARDWARE : SERVICE_SUBTYPE_SINK_VIRTUAL) :
|
||||
(s->subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SOURCE_HARDWARE : (s->subtype == SUBTYPE_VIRTUAL ? SERVICE_SUBTYPE_SOURCE_VIRTUAL : SERVICE_SUBTYPE_SOURCE_MONITOR))) < 0) {
|
||||
|
||||
pw_log_error("avahi_entry_group_add_service_subtype(): %s",
|
||||
avahi_strerror(avahi_client_errno(d->client)));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!s->is_sink && s->subtype != SUBTYPE_MONITOR) {
|
||||
if (avahi_entry_group_add_service_subtype(
|
||||
s->entry_group,
|
||||
AVAHI_IF_UNSPEC, proto,
|
||||
0,
|
||||
s->service_name,
|
||||
SERVICE_TYPE_SOURCE,
|
||||
NULL,
|
||||
SERVICE_SUBTYPE_SOURCE_NON_MONITOR) < 0) {
|
||||
pw_log_error("avahi_entry_group_add_service_subtype(): %s",
|
||||
avahi_strerror(avahi_client_errno(d->client)));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (avahi_entry_group_commit(s->entry_group) < 0) {
|
||||
pw_log_error("avahi_entry_group_commit(): %s",
|
||||
avahi_strerror(avahi_client_errno(d->client)));
|
||||
goto error;
|
||||
}
|
||||
|
||||
spa_list_remove(&s->link);
|
||||
spa_list_append(&d->published, &s->link);
|
||||
s->published = true;
|
||||
s->server = server;
|
||||
|
||||
pw_log_info("created service: %s", s->service_name);
|
||||
return;
|
||||
|
||||
error:
|
||||
s->published = false;
|
||||
pw_log_info("published service: %s", device);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -506,62 +362,6 @@ static void publish_pending(struct module_zeroconf_publish_data *data)
|
|||
publish_service(s);
|
||||
}
|
||||
|
||||
static void clear_pending_entry_groups(struct module_zeroconf_publish_data *data)
|
||||
{
|
||||
struct service *s;
|
||||
|
||||
spa_list_for_each(s, &data->pending, link)
|
||||
clear_entry_group(s);
|
||||
}
|
||||
|
||||
static void client_callback(AvahiClient *c, AvahiClientState state, void *d)
|
||||
{
|
||||
struct module_zeroconf_publish_data *data = d;
|
||||
|
||||
spa_assert(c);
|
||||
spa_assert(data);
|
||||
|
||||
data->client = c;
|
||||
|
||||
switch (state) {
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
pw_log_info("the avahi daemon is up and running");
|
||||
publish_pending(data);
|
||||
break;
|
||||
case AVAHI_CLIENT_S_COLLISION:
|
||||
pw_log_error("host name collision");
|
||||
unpublish_all_services(d);
|
||||
break;
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
{
|
||||
int err = avahi_client_errno(data->client);
|
||||
|
||||
pw_log_error("avahi client failure: %s", avahi_strerror(err));
|
||||
|
||||
unpublish_all_services(data);
|
||||
clear_pending_entry_groups(data);
|
||||
avahi_client_free(data->client);
|
||||
data->client = NULL;
|
||||
|
||||
if (err == AVAHI_ERR_DISCONNECTED) {
|
||||
data->client = avahi_client_new(data->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, data, &err);
|
||||
if (data->client == NULL)
|
||||
pw_log_error("failed to create avahi client: %s", avahi_strerror(err));
|
||||
}
|
||||
|
||||
if (data->client == NULL)
|
||||
module_schedule_unload(data->module);
|
||||
|
||||
break;
|
||||
}
|
||||
case AVAHI_CLIENT_CONNECTING:
|
||||
pw_log_info("connecting to the avahi daemon...");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void manager_removed(void *d, struct pw_manager_object *o)
|
||||
{
|
||||
if (!pw_manager_object_is_sink(o) && !pw_manager_object_is_source(o))
|
||||
|
|
@ -624,7 +424,6 @@ static void impl_server_stopped(void *data, struct server *server)
|
|||
if (s->server == server)
|
||||
unpublish_service(s);
|
||||
}
|
||||
|
||||
publish_pending(d);
|
||||
}
|
||||
|
||||
|
|
@ -634,10 +433,18 @@ static const struct impl_events impl_events = {
|
|||
.server_stopped = impl_server_stopped,
|
||||
};
|
||||
|
||||
static void on_zeroconf_error(void *data, int err, const char *message)
|
||||
{
|
||||
pw_log_error("got zeroconf error %d: %s", err, message);
|
||||
}
|
||||
static const struct pw_zeroconf_events zeroconf_events = {
|
||||
PW_VERSION_ZEROCONF_EVENTS,
|
||||
.error = on_zeroconf_error,
|
||||
};
|
||||
|
||||
static int module_zeroconf_publish_load(struct module *module)
|
||||
{
|
||||
struct module_zeroconf_publish_data *data = module->user_data;
|
||||
int error;
|
||||
|
||||
data->core = pw_context_connect(module->impl->context, NULL, 0);
|
||||
if (data->core == NULL) {
|
||||
|
|
@ -649,24 +456,22 @@ static int module_zeroconf_publish_load(struct module *module)
|
|||
&data->core_listener,
|
||||
&core_events, data);
|
||||
|
||||
data->avahi_poll = pw_avahi_poll_new(module->impl->context);
|
||||
|
||||
data->client = avahi_client_new(data->avahi_poll, AVAHI_CLIENT_NO_FAIL,
|
||||
client_callback, data, &error);
|
||||
if (!data->client) {
|
||||
pw_log_error("failed to create avahi client: %s", avahi_strerror(error));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
data->manager = pw_manager_new(data->core);
|
||||
if (data->manager == NULL) {
|
||||
pw_log_error("failed to create pipewire manager: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
pw_manager_add_listener(data->manager, &data->manager_listener,
|
||||
&manager_events, data);
|
||||
|
||||
data->zeroconf = pw_zeroconf_new(module->impl->context, NULL);
|
||||
if (!data->zeroconf) {
|
||||
pw_log_error("failed to create zeroconf: %m");
|
||||
return -errno;
|
||||
}
|
||||
pw_zeroconf_add_listener(data->zeroconf, &data->zeroconf_listener,
|
||||
&zeroconf_events, data);
|
||||
|
||||
impl_add_listener(module->impl, &data->impl_listener, &impl_events, data);
|
||||
|
||||
return 0;
|
||||
|
|
@ -684,22 +489,18 @@ static int module_zeroconf_publish_unload(struct module *module)
|
|||
spa_list_consume(s, &d->pending, link)
|
||||
service_free(s);
|
||||
|
||||
if (d->client)
|
||||
avahi_client_free(d->client);
|
||||
|
||||
if (d->avahi_poll)
|
||||
pw_avahi_poll_free(d->avahi_poll);
|
||||
|
||||
if (d->zeroconf) {
|
||||
spa_hook_remove(&d->zeroconf_listener);
|
||||
pw_zeroconf_destroy(d->zeroconf);
|
||||
}
|
||||
if (d->manager != NULL) {
|
||||
spa_hook_remove(&d->manager_listener);
|
||||
pw_manager_destroy(d->manager);
|
||||
}
|
||||
|
||||
if (d->core != NULL) {
|
||||
spa_hook_remove(&d->core_listener);
|
||||
pw_core_disconnect(d->core);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue