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_LOAD_ONCE(true);
#define SERVICE_TYPE_SINK "_pulse-sink._tcp"
#define SERVICE_TYPE_SOURCE "_pulse-source._tcp"
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;
+
+ bool shutting_down;
};
/* Runs in PA mainloop context */
if (pa_sink_isinstance(device)) {
pa_sink *sink = PA_SINK(device);
- s->is_sink = TRUE;
+ s->is_sink = true;
s->service_type = SERVICE_TYPE_SINK;
s->ss = sink->sample_spec;
s->cm = sink->channel_map;
} else if (pa_source_isinstance(device)) {
pa_source *source = PA_SOURCE(device);
- s->is_sink = FALSE;
+ s->is_sink = false;
s->service_type = SERVICE_TYPE_SOURCE;
s->ss = source->sample_spec;
s->cm = source->channel_map;
}
/* Runs in PA mainloop context */
-static pa_bool_t shall_ignore(pa_object *o) {
+static bool shall_ignore(pa_object *o) {
pa_object_assert_ref(o);
if (pa_sink_isinstance(o))
pa_assert(c);
pa_object_assert_ref(o);
- if (!shall_ignore(o))
+ if (!shall_ignore(o)) {
+ pa_threaded_mainloop_lock(u->mainloop);
pa_mainloop_api_once(u->api, publish_service, get_service(u, o));
+ pa_threaded_mainloop_unlock(u->mainloop);
+ }
return PA_HOOK_OK;
}
pa_log_debug("Publishing services in Zeroconf");
for (sink = PA_SINK(pa_idxset_first(u->core->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(u->core->sinks, &idx)))
- if (!shall_ignore(PA_OBJECT(sink)))
+ if (!shall_ignore(PA_OBJECT(sink))) {
+ pa_threaded_mainloop_lock(u->mainloop);
pa_mainloop_api_once(u->api, publish_service, get_service(u, PA_OBJECT(sink)));
+ pa_threaded_mainloop_unlock(u->mainloop);
+ }
for (source = PA_SOURCE(pa_idxset_first(u->core->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(u->core->sources, &idx)))
- if (!shall_ignore(PA_OBJECT(source)))
+ if (!shall_ignore(PA_OBJECT(source))) {
+ pa_threaded_mainloop_lock(u->mainloop);
pa_mainloop_api_once(u->api, publish_service, get_service(u, PA_OBJECT(source)));
+ pa_threaded_mainloop_unlock(u->mainloop);
+ }
if (publish_main_service(u) < 0)
goto fail;
}
/* Runs in Avahi mainloop context */
-static void unpublish_all_services(struct userdata *u, pa_bool_t rem) {
+static void unpublish_all_services(struct userdata *u, bool rem) {
void *state = NULL;
struct service *s;
static int avahi_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = (struct userdata *) data;
+ pa_assert(u);
+
+ if (u->shutting_down)
+ return 0;
+
switch (code) {
case AVAHI_MESSAGE_PUBLISH_ALL:
publish_all_services(u);
pa_module_unload(u->core, u->module, true);
break;
- case AVAHI_MESSAGE_SHUTDOWN_COMPLETE:
- /* pa__done() is waiting for this */
- break;
-
default:
pa_assert_not_reached();
}
case AVAHI_CLIENT_S_COLLISION:
pa_log_debug("Host name collision");
- unpublish_all_services(u, FALSE);
+ unpublish_all_services(u, false);
break;
case AVAHI_CLIENT_FAILURE:
pa_log_debug("Avahi daemon disconnected.");
- unpublish_all_services(u, TRUE);
+ unpublish_all_services(u, true);
avahi_client_free(u->client);
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));
- pa_module_unload_request(u->module, TRUE);
+ pa_module_unload_request(u->module, true);
}
}
u->avahi_poll = pa_avahi_poll_new(u->api);
- u->services = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+ u->services = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) service_free);
u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u);
u->sink_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u);
pa_threaded_mainloop_set_name(u->mainloop, "avahi-ml");
pa_threaded_mainloop_start(u->mainloop);
+
+ pa_threaded_mainloop_lock(u->mainloop);
pa_mainloop_api_once(u->api, create_client, u);
+ pa_threaded_mainloop_unlock(u->mainloop);
pa_modargs_free(ma);
static void client_free(pa_mainloop_api *api PA_GCC_UNUSED, void *userdata) {
struct userdata *u = (struct userdata *) userdata;
- pa_hashmap_free(u->services, (pa_free_cb_t) service_free);
+ pa_hashmap_free(u->services);
if (u->main_entry_group)
avahi_entry_group_free(u->main_entry_group);
if (u->avahi_poll)
pa_avahi_poll_free(u->avahi_poll);
- pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->msg), AVAHI_MESSAGE_SHUTDOWN_COMPLETE, NULL, 0, NULL, NULL);
+ pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->msg), AVAHI_MESSAGE_SHUTDOWN_COMPLETE, u, 0, NULL, NULL);
}
void pa__done(pa_module*m) {
if (!(u = m->userdata))
return;
+ u->shutting_down = true;
+
+ pa_threaded_mainloop_lock(u->mainloop);
pa_mainloop_api_once(u->api, client_free, u);
+ pa_threaded_mainloop_unlock(u->mainloop);
pa_asyncmsgq_wait_for(u->thread_mq.outq, AVAHI_MESSAGE_SHUTDOWN_COMPLETE);
pa_threaded_mainloop_stop(u->mainloop);