#include <pulsecore/pstream.h>
#include <pulsecore/pstream-util.h>
#include <pulsecore/database.h>
+#include <pulsecore/tagstruct.h>
#include "module-device-manager-symdef.h"
ROLE_ANIMATION,
ROLE_PRODUCTION,
ROLE_A11Y,
+ ROLE_MAX
};
typedef uint32_t role_indexes_t[NUM_ROLES];
struct entry {
uint8_t version;
- char description[PA_NAME_MAX];
+ char *description;
pa_bool_t user_set_description;
- char icon[PA_NAME_MAX];
+ char *icon;
role_indexes_t priority;
-} PA_GCC_PACKED;
+};
enum {
SUBCOMMAND_TEST,
};
-static struct entry* read_entry(struct userdata *u, const char *name) {
+/* Forward declarations */
+#ifdef DUMP_DATABASE
+static void dump_database(struct userdata *);
+#endif
+static void notify_subscribers(struct userdata *);
+
+
+static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
+ struct userdata *u = userdata;
+
+ pa_assert(a);
+ pa_assert(e);
+ pa_assert(u);
+
+ pa_assert(e == u->save_time_event);
+ u->core->mainloop->time_free(u->save_time_event);
+ u->save_time_event = NULL;
+
+ pa_database_sync(u->database);
+ pa_log_info("Synced.");
+
+#ifdef DUMP_DATABASE
+ dump_database(u);
+#endif
+}
+
+static void trigger_save(struct userdata *u) {
+
+ pa_assert(u);
+
+ notify_subscribers(u);
+
+ if (u->save_time_event)
+ return;
+
+ u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
+}
+
+static struct entry* entry_new(void) {
+ struct entry *r = pa_xnew0(struct entry, 1);
+ r->version = ENTRY_VERSION;
+ return r;
+}
+
+static void entry_free(struct entry* e) {
+ pa_assert(e);
+
+ pa_xfree(e->description);
+ pa_xfree(e->icon);
+}
+
+static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e) {
+ pa_tagstruct *t;
pa_datum key, data;
+ pa_bool_t r;
+
+ pa_assert(u);
+ pa_assert(name);
+ pa_assert(e);
+
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu8(t, e->version);
+ pa_tagstruct_puts(t, e->description);
+ pa_tagstruct_put_boolean(t, e->user_set_description);
+ pa_tagstruct_puts(t, e->icon);
+ for (uint8_t i=0; i<ROLE_MAX; ++i)
+ pa_tagstruct_putu32(t, e->priority[i]);
+
+ key.data = (char *) name;
+ key.size = strlen(name);
+
+ data.data = (void*)pa_tagstruct_data(t, &data.size);
+
+ r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
+
+ pa_tagstruct_free(t);
+
+ return r;
+}
+
+#ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
+
+#define LEGACY_ENTRY_VERSION 1
+static struct entry* legacy_entry_read(struct userdata *u, pa_datum *data) {
+ struct legacy_entry {
+ uint8_t version;
+ char description[PA_NAME_MAX];
+ pa_bool_t user_set_description;
+ char icon[PA_NAME_MAX];
+ role_indexes_t priority;
+ } PA_GCC_PACKED;
+ struct legacy_entry *le;
struct entry *e;
+ pa_assert(u);
+ pa_assert(data);
+
+ if (data->size != sizeof(struct legacy_entry)) {
+ pa_log_debug("Size does not match.");
+ return NULL;
+ }
+
+ le = (struct legacy_entry*)data->data;
+
+ if (le->version != LEGACY_ENTRY_VERSION) {
+ pa_log_debug("Version mismatch.");
+ return NULL;
+ }
+
+ if (!memchr(le->description, 0, sizeof(le->description))) {
+ pa_log_warn("Description has missing NUL byte.");
+ return NULL;
+ }
+
+ if (!memchr(le->icon, 0, sizeof(le->icon))) {
+ pa_log_warn("Icon has missing NUL byte.");
+ return NULL;
+ }
+
+ e = entry_new();
+ e->description = pa_xstrdup(le->description);
+ e->icon = pa_xstrdup(le->icon);
+ return e;
+}
+#endif
+
+static struct entry* entry_read(struct userdata *u, const char *name) {
+ pa_datum key, data;
+ struct entry *e = NULL;
+ pa_tagstruct *t = NULL;
+ const char *description, *icon;
+
pa_assert(u);
pa_assert(name);
if (!pa_database_get(u->database, &key, &data))
goto fail;
- if (data.size != sizeof(struct entry)) {
- pa_log_debug("Database contains entry for device %s of wrong size %lu != %lu. Probably due to upgrade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry));
- goto fail;
- }
+ t = pa_tagstruct_new(data.data, data.size);
+ e = entry_new();
- e = (struct entry*) data.data;
+ if (pa_tagstruct_getu8(t, &e->version) < 0 ||
+ e->version > ENTRY_VERSION ||
+ pa_tagstruct_gets(t, &description) < 0 ||
+ pa_tagstruct_get_boolean(t, &e->user_set_description) < 0 ||
+ pa_tagstruct_gets(t, &icon) < 0) {
- if (e->version != ENTRY_VERSION) {
- pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name);
goto fail;
}
- if (!memchr(e->description, 0, sizeof(e->description))) {
- pa_log_warn("Database contains entry for device %s with missing NUL byte in description", name);
- goto fail;
+ e->description = pa_xstrdup(description);
+ e->icon = pa_xstrdup(icon);
+
+ for (uint8_t i=0; i<ROLE_MAX; ++i) {
+ if (pa_tagstruct_getu32(t, &e->priority[i]) < 0)
+ goto fail;
}
- if (!memchr(e->icon, 0, sizeof(e->icon))) {
- pa_log_warn("Database contains entry for device %s with missing NUL byte in icon", name);
+ if (!pa_tagstruct_eof(t))
goto fail;
- }
+
+ pa_tagstruct_free(t);
+ pa_datum_free(&data);
return e;
fail:
+ pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
+
+ if (e)
+ entry_free(e);
+ if (t)
+ pa_tagstruct_free(t);
+
+#ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
+ pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
+ if ((e = legacy_entry_read(u, &data))) {
+ pa_log_debug("Success. Saving new format for key: %s", name);
+ if (entry_write(u, name, e))
+ trigger_save(u);
+ pa_datum_free(&data);
+ return e;
+ } else
+ pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
+#endif
pa_datum_free(&data);
return NULL;
name = pa_xstrndup(key.data, key.size);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
pa_log_debug(" Got entry: %s", name);
pa_log_debug(" Description: %s", e->description);
pa_log_debug(" Priorities: None: %3u, Video: %3u, Music: %3u, Game: %3u, Event: %3u",
e->priority[ROLE_NONE], e->priority[ROLE_VIDEO], e->priority[ROLE_MUSIC], e->priority[ROLE_GAME], e->priority[ROLE_EVENT]);
pa_log_debug(" Phone: %3u, Anim: %3u, Prodtn: %3u, A11y: %3u",
e->priority[ROLE_PHONE], e->priority[ROLE_ANIMATION], e->priority[ROLE_PRODUCTION], e->priority[ROLE_A11Y]);
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
}
#endif
-static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
- struct userdata *u = userdata;
-
- pa_assert(a);
- pa_assert(e);
- pa_assert(u);
-
- pa_assert(e == u->save_time_event);
- u->core->mainloop->time_free(u->save_time_event);
- u->save_time_event = NULL;
-
- pa_database_sync(u->database);
- pa_log_info("Synced.");
-
-#ifdef DUMP_DATABASE
- dump_database(u);
-#endif
-}
-
static void notify_subscribers(struct userdata *u) {
pa_native_connection *c;
}
}
-static void trigger_save(struct userdata *u) {
-
- pa_assert(u);
-
- notify_subscribers(u);
-
- if (u->save_time_event)
- return;
-
- u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
-}
-
static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
pa_assert(a);
pa_assert(b);
- if (strncmp(a->description, b->description, sizeof(a->description))
+ if (!pa_streq(a->description, b->description)
|| a->user_set_description != b->user_set_description
- || strncmp(a->icon, b->icon, sizeof(a->icon)))
+ || !pa_streq(a->icon, b->icon))
return FALSE;
for (int i=0; i < NUM_ROLES; ++i)
pa_assert(name);
pa_assert(prefix);
- if ((old = read_entry(u, name)))
+ if ((old = entry_read(u, name))) {
*entry = *old;
- else {
+ entry->description = pa_xstrdup(old->description);
+ entry->icon = pa_xstrdup(old->icon);
+ } else {
/* This is a new device, so make sure we write it's priority list correctly */
role_indexes_t max_priority;
pa_datum key;
name2 = pa_xstrndup(key.data, key.size);
- if ((e = read_entry(u, name2))) {
+ if ((e = entry_read(u, name2))) {
for (uint32_t i = 0; i < NUM_ROLES; ++i) {
max_priority[i] = PA_MAX(max_priority[i], e->priority[i]);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name2);
name = pa_xstrndup(key.data, key.size);
device_name = get_name(name, prefix);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
for (uint32_t i = 0; i < NUM_ROLES; ++i) {
if (!highest_priority_available[i] || e->priority[i] < highest_priority_available[i]) {
/* We've found a device with a higher priority than that we've currently got,
}
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
struct userdata *u = userdata;
- struct entry entry, *old = NULL;
+ struct entry *entry, *old = NULL;
char *name = NULL;
- pa_datum key, data;
pa_assert(c);
pa_assert(u);
t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
return;
- pa_zero(entry);
- entry.version = ENTRY_VERSION;
+ entry = entry_new();
if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
pa_sink_input *si;
name = pa_sprintf_malloc("sink:%s", sink->name);
- old = load_or_initialize_entry(u, &entry, name, "sink:");
+ old = load_or_initialize_entry(u, entry, name, "sink:");
- if (!entry.user_set_description)
- pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
- else if (strncmp(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description)) != 0) {
+ if (!entry->user_set_description) {
+ pa_xfree(entry->description);
+ entry->description = pa_xstrdup(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION));
+ } else if (!pa_streq(entry->description, pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION))) {
/* Warning: If two modules fight over the description, this could cause an infinite loop.
by changing the description here, we retrigger this subscription callback. The only thing stopping us from
looping is the fact that the string comparison will fail on the second iteration. If another module tries to manage
the description, this will fail... */
- pa_sink_set_description(sink, entry.description);
+ pa_sink_set_description(sink, entry->description);
}
- pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
+ pa_xfree(entry->icon);
+ entry->icon = pa_xstrdup(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME));
- } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
+ } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
pa_source *source;
pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
name = pa_sprintf_malloc("source:%s", source->name);
- old = load_or_initialize_entry(u, &entry, name, "source:");
+ old = load_or_initialize_entry(u, entry, name, "source:");
- if (!entry.user_set_description)
- pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
- else if (strncmp(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description)) != 0) {
+ if (!entry->user_set_description) {
+ pa_xfree(entry->description);
+ entry->description = pa_xstrdup(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION));
+ } else if (!pa_streq(entry->description, pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION))) {
/* Warning: If two modules fight over the description, this could cause an infinite loop.
by changing the description here, we retrigger this subscription callback. The only thing stopping us from
looping is the fact that the string comparison will fail on the second iteration. If another module tries to manage
the description, this will fail... */
- pa_source_set_description(source, entry.description);
+ pa_source_set_description(source, entry->description);
}
- pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
+ pa_xfree(entry->icon);
+ entry->icon = pa_xstrdup(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME));
}
pa_assert(name);
if (old) {
- if (entries_equal(old, &entry)) {
- pa_xfree(old);
+ if (entries_equal(old, entry)) {
+ entry_free(old);
+ entry_free(entry);
pa_xfree(name);
return;
}
- pa_xfree(old);
+ entry_free(old);
}
- key.data = name;
- key.size = strlen(name);
-
- data.data = &entry;
- data.size = sizeof(entry);
-
pa_log_info("Storing device %s.", name);
- if (pa_database_set(u->database, &key, &data, TRUE) == 0)
+ if (entry_write(u, name, entry))
trigger_save(u);
else
pa_log_warn("Could not save device");;
+ entry_free(entry);
pa_xfree(name);
}
name = pa_sprintf_malloc("sink:%s", new_data->name);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
if (e->user_set_description && strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
pa_log_info("Restoring description for sink %s.", new_data->name);
pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
name = pa_sprintf_malloc("source:%s", new_data->name);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
if (e->user_set_description && strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
/* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
pa_log_info("Restoring description for source %s.", new_data->name);
pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
pa_sink *sink;
if ((sink = pa_idxset_get_by_index(u->core->sinks, device_index))) {
- new_data->sink = sink;
- new_data->save_sink = FALSE;
+ if (!pa_sink_input_new_data_set_sink(new_data, sink, FALSE))
+ pa_log_debug("Not restoring device for stream because no supported format was found");
}
}
}
if (PA_INVALID_INDEX != device_index) {
pa_source *source;
- if ((source = pa_idxset_get_by_index(u->core->sources, device_index))) {
- new_data->source = source;
- new_data->save_source = FALSE;
- }
+ if ((source = pa_idxset_get_by_index(u->core->sources, device_index)))
+ if (!pa_source_output_new_data_set_source(new_data, source, FALSE))
+ pa_log_debug("Not restoring device for stream because no supported format was found");
}
}
}
name = pa_xstrndup(key.data, key.size);
pa_datum_free(&key);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
uint32_t idx;
- char *devname;
- uint32_t index = PA_INVALID_INDEX;
+ char *device_name;
+ uint32_t found_index = PA_INVALID_INDEX;
- if ((devname = get_name(name, "sink:"))) {
+ if ((device_name = get_name(name, "sink:"))) {
pa_sink* s;
PA_IDXSET_FOREACH(s, u->core->sinks, idx) {
- if (strcmp(s->name, devname) == 0) {
- index = s->index;
+ if (strcmp(s->name, device_name) == 0) {
+ found_index = s->index;
break;
}
}
- pa_xfree(devname);
- } else if ((devname = get_name(name, "source:"))) {
+ pa_xfree(device_name);
+ } else if ((device_name = get_name(name, "source:"))) {
pa_source* s;
PA_IDXSET_FOREACH(s, u->core->sources, idx) {
- if (strcmp(s->name, devname) == 0) {
- index = s->index;
+ if (strcmp(s->name, device_name) == 0) {
+ found_index = s->index;
break;
}
}
- pa_xfree(devname);
+ pa_xfree(device_name);
}
pa_tagstruct_puts(reply, name);
pa_tagstruct_puts(reply, e->description);
pa_tagstruct_puts(reply, e->icon);
- pa_tagstruct_putu32(reply, index);
+ pa_tagstruct_putu32(reply, found_index);
pa_tagstruct_putu32(reply, NUM_ROLES);
for (uint32_t i = ROLE_NONE; i < NUM_ROLES; ++i) {
pa_tagstruct_putu32(reply, e->priority[i]);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
if (!device || !*device || !description || !*description)
goto fail;
- if ((e = read_entry(u, device))) {
- pa_datum key, data;
-
- pa_strlcpy(e->description, description, sizeof(e->description));
+ if ((e = entry_read(u, device))) {
+ pa_xfree(e->description);
+ e->description = pa_xstrdup(description);
e->user_set_description = TRUE;
- key.data = (char *) device;
- key.size = strlen(device);
-
- data.data = e;
- data.size = sizeof(*e);
-
- if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
+ if (entry_write(u, (char *)device, e)) {
apply_entry(u, device, e);
trigger_save(u);
else
pa_log_warn("Could not save device");
- pa_xfree(e);
+ entry_free(e);
}
else
pa_log_warn("Could not rename device %s, no entry in database", device);
const char *role;
struct entry *e;
uint32_t role_index, n_devices;
- pa_datum key, data;
+ pa_datum key;
pa_bool_t done, sink_mode = TRUE;
struct device_t { uint32_t prio; char *device; };
struct device_t *device;
goto fail;
if (PA_INVALID_INDEX == (role_index = get_role_index(role)))
- goto fail;
+ goto fail;
/* Cycle through the devices given and make sure they exist */
h = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
}
/* Ensure this is a valid entry */
- if (!(e = read_entry(u, s))) {
+ if (!(e = entry_read(u, s))) {
while ((device = pa_hashmap_steal_first(h))) {
pa_xfree(device->device);
pa_xfree(device);
pa_log_error("Client specified an unknown device in it's reorder list.");
goto fail;
}
- pa_xfree(e);
+ entry_free(e);
if (first) {
first = FALSE;
sink_mode = (0 == strncmp("sink:", s, 5));
- } else if ((sink_mode && 0 != strncmp("sink:", s, 5))
- || (!sink_mode && 0 != strncmp("source:", s, 7)))
- {
+ } else if ((sink_mode && 0 != strncmp("sink:", s, 5)) || (!sink_mode && 0 != strncmp("source:", s, 7))) {
while ((device = pa_hashmap_steal_first(h))) {
pa_xfree(device->device);
pa_xfree(device);
/* Add the device to our hashmap. If it's alredy in it, free it now and carry on */
if (pa_hashmap_put(h, device->device, device) == 0
- && (e = read_entry(u, device->device))) {
+ && (e = entry_read(u, device->device))) {
/* We add offset on to the existing priorirty so that when we order, the
existing entries are always lower priority than the new ones. */
device->prio = (offset + e->priority[role_index]);
idx = 1;
first = TRUE;
for (i = 0; i < n_devices; ++i) {
- if ((e = read_entry(u, devices[i]->device))) {
+ if ((e = entry_read(u, devices[i]->device))) {
if (e->priority[role_index] == idx)
idx++;
else {
e->priority[role_index] = idx;
- key.data = (char *) devices[i]->device;
- key.size = strlen(devices[i]->device);
-
- data.data = e;
- data.size = sizeof(*e);
-
- if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
+ if (entry_write(u, (char *) devices[i]->device, e)) {
first = FALSE;
idx++;
}
return PA_HOOK_OK;
}
+struct prioritised_indexes {
+ uint32_t index;
+ int32_t priority;
+};
+
int pa__init(pa_module*m) {
pa_modargs *ma = NULL;
struct userdata *u;
pa_source *source;
uint32_t idx;
pa_bool_t do_routing = FALSE, on_hotplug = TRUE, on_rescue = TRUE;
+ uint32_t total_devices;
pa_assert(m);
goto fail;
}
- pa_log_info("Sucessfully opened database file '%s'.", fname);
+ pa_log_info("Successfully opened database file '%s'.", fname);
pa_xfree(fname);
- /* We cycle over all the available sinks so that they are added to our database if they are not in it yet */
- PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
- subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
+ /* Attempt to inject the devices into the list in priority order */
+ total_devices = PA_MAX(pa_idxset_size(m->core->sinks), pa_idxset_size(m->core->sources));
+ if (total_devices > 0 && total_devices < 128) {
+ uint32_t i;
+ struct prioritised_indexes p_i[128];
+
+ /* We cycle over all the available sinks so that they are added to our database if they are not in it yet */
+ i = 0;
+ PA_IDXSET_FOREACH(sink, m->core->sinks, idx) {
+ pa_log_debug("Found sink index %u", sink->index);
+ p_i[i ].index = sink->index;
+ p_i[i++].priority = sink->priority;
+ }
+ /* Bubble sort it (only really useful for first time creation) */
+ if (i > 1)
+ for (uint32_t j = 0; j < i; ++j)
+ for (uint32_t k = 0; k < i; ++k)
+ if (p_i[j].priority > p_i[k].priority) {
+ struct prioritised_indexes tmp_pi = p_i[k];
+ p_i[k] = p_i[j];
+ p_i[j] = tmp_pi;
+ }
+ /* Register it */
+ for (uint32_t j = 0; j < i; ++j)
+ subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, p_i[j].index, u);
+
+
+ /* We cycle over all the available sources so that they are added to our database if they are not in it yet */
+ i = 0;
+ PA_IDXSET_FOREACH(source, m->core->sources, idx) {
+ p_i[i ].index = source->index;
+ p_i[i++].priority = source->priority;
+ }
+ /* Bubble sort it (only really useful for first time creation) */
+ if (i > 1)
+ for (uint32_t j = 0; j < i; ++j)
+ for (uint32_t k = 0; k < i; ++k)
+ if (p_i[j].priority > p_i[k].priority) {
+ struct prioritised_indexes tmp_pi = p_i[k];
+ p_i[k] = p_i[j];
+ p_i[j] = tmp_pi;
+ }
+ /* Register it */
+ for (uint32_t j = 0; j < i; ++j)
+ subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, p_i[j].index, u);
+ }
+ else if (total_devices > 0) {
+ /* This user has a *lot* of devices... */
+ PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
+ subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
- PA_IDXSET_FOREACH(source, m->core->sources, idx)
- subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
+ PA_IDXSET_FOREACH(source, m->core->sources, idx)
+ subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
+ }
/* Perform the routing (if it's enabled) which will update our priority list cache too */
for (uint32_t i = 0; i < NUM_ROLES; ++i) {
if (ma)
pa_modargs_free(ma);
- return -1;
+ return -1;
}
void pa__done(pa_module*m) {
if (u->source_unlink_hook_slot)
pa_hook_slot_free(u->source_unlink_hook_slot);
+ if (u->connection_unlink_hook_slot)
+ pa_hook_slot_free(u->connection_unlink_hook_slot);
+
if (u->save_time_event)
u->core->mainloop->time_free(u->save_time_event);