summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorColin Guthrie <cguthrie@mandriva.org>2009-09-20 17:29:38 +0100
committerColin Guthrie <cguthrie@mandriva.org>2009-11-11 17:44:24 +0000
commita0567fb41b2bc265cd30a4e175878485878a19fc (patch)
tree8ab3f1acce4db04d63e96871c6ffc154d909a613 /src
parentfd5a5084d8112f01cbd2a061d86a39c6bacd044e (diff)
device-manager: Rough framework (slots etc.) for handling routing.
This is incomplete, it just adds the slots in question and assigns noops to them. Some minor cleanup of types. Due to the priority of the hooks, it seems we can actually coexist with module-stream restore so the code to detect and unload it will be removed shortly.
Diffstat (limited to 'src')
-rw-r--r--src/modules/module-device-manager.c206
1 files changed, 201 insertions, 5 deletions
diff --git a/src/modules/module-device-manager.c b/src/modules/module-device-manager.c
index e029c1d8..4c4e3f0b 100644
--- a/src/modules/module-device-manager.c
+++ b/src/modules/module-device-manager.c
@@ -58,11 +58,15 @@ PA_MODULE_AUTHOR("Colin Guthrie");
PA_MODULE_DESCRIPTION("Keep track of devices (and their descriptions) both past and present");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(TRUE);
-PA_MODULE_USAGE("This module does not take any arguments");
+PA_MODULE_USAGE(
+ "on_hotplug=<When new device becomes available, recheck streams?> "
+ "on_rescue=<When device becomes unavailable, recheck streams?>");
#define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
static const char* const valid_modargs[] = {
+ "on_hotplug",
+ "on_rescue",
NULL
};
@@ -73,6 +77,12 @@ struct userdata {
pa_hook_slot
*sink_new_hook_slot,
*source_new_hook_slot,
+ *sink_input_new_hook_slot,
+ *source_output_new_hook_slot,
+ *sink_put_hook_slot,
+ *source_put_hook_slot,
+ *sink_unlink_hook_slot,
+ *source_unlink_hook_slot,
*connection_unlink_hook_slot;
pa_time_event *save_time_event;
pa_database *database;
@@ -80,6 +90,8 @@ struct userdata {
pa_native_protocol *protocol;
pa_idxset *subscribed;
+ pa_bool_t on_hotplug;
+ pa_bool_t on_rescue;
pa_bool_t role_device_priority_routing;
pa_bool_t stream_restore_used;
pa_bool_t checked_stream_restore;
@@ -100,10 +112,12 @@ enum {
ROLE_A11Y,
};
+typedef uint32_t role_indexes_t[NUM_ROLES];
+
struct entry {
uint8_t version;
char description[PA_NAME_MAX];
- uint32_t priority[NUM_ROLES];
+ role_indexes_t priority;
} PA_GCC_PACKED;
enum {
@@ -215,7 +229,7 @@ static inline struct entry *load_or_initialize_entry(struct userdata *u, struct
*entry = *old;
else {
/* This is a new device, so make sure we write it's priority list correctly */
- uint32_t max_priority[NUM_ROLES];
+ role_indexes_t max_priority;
pa_datum key;
pa_bool_t done;
@@ -390,6 +404,138 @@ static char *get_name(const char *key, const char *prefix) {
return t;
}
+static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
+ char *name;
+ struct entry *e;
+
+ pa_assert(c);
+ pa_assert(new_data);
+ pa_assert(u);
+
+ if (!u->role_device_priority_routing)
+ return PA_HOOK_OK;
+
+ /*if (!(name = get_name(new_data->proplist, "sink-input")))
+ return PA_HOOK_OK;
+
+ if (new_data->sink)
+ pa_log_debug("Not restoring device for stream %s, because already set.", name);
+ else if ((e = read_entry(u, name))) {
+
+ pa_xfree(e);
+ }
+
+ pa_xfree(name);*/
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
+ char *name;
+ struct entry *e;
+
+ pa_assert(c);
+ pa_assert(new_data);
+ pa_assert(u);
+
+ if (!u->role_device_priority_routing)
+ return PA_HOOK_OK;
+
+ if (new_data->direct_on_input)
+ return PA_HOOK_OK;
+
+ /*if (!(name = get_name(new_data->proplist, "source-output")))
+ return PA_HOOK_OK;
+
+ if (new_data->source)
+ pa_log_debug("Not restoring device for stream %s, because already set", name);
+ else if ((e = read_entry(u, name))) {
+
+ pa_xfree(e);
+ }
+
+ pa_xfree(name);*/
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
+ pa_sink_input *si;
+ uint32_t idx;
+
+ pa_assert(c);
+ pa_assert(sink);
+ pa_assert(u);
+ pa_assert(u->on_hotplug);
+
+ if (!u->role_device_priority_routing)
+ return PA_HOOK_OK;
+
+ /** @todo Ensure redo the routing based on the priorities */
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
+ pa_source_output *so;
+ uint32_t idx;
+
+ pa_assert(c);
+ pa_assert(source);
+ pa_assert(u);
+ pa_assert(u->on_hotplug);
+
+ if (!u->role_device_priority_routing)
+ return PA_HOOK_OK;
+
+ /** @todo Ensure redo the routing based on the priorities */
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
+ pa_sink_input *si;
+ uint32_t idx;
+
+ pa_assert(c);
+ pa_assert(sink);
+ pa_assert(u);
+ pa_assert(u->on_rescue);
+
+ /* There's no point in doing anything if the core is shut down anyway */
+ if (c->state == PA_CORE_SHUTDOWN)
+ return PA_HOOK_OK;
+
+ if (!u->role_device_priority_routing)
+ return PA_HOOK_OK;
+
+ /** @todo Ensure redo the routing based on the priorities */
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
+ pa_source_output *so;
+ uint32_t idx;
+
+ pa_assert(c);
+ pa_assert(source);
+ pa_assert(u);
+ pa_assert(u->on_rescue);
+
+ /* There's no point in doing anything if the core is shut down anyway */
+ if (c->state == PA_CORE_SHUTDOWN)
+ return PA_HOOK_OK;
+
+ if (!u->role_device_priority_routing)
+ return PA_HOOK_OK;
+
+ /** @todo Ensure redo the routing based on the priorities */
+
+ return PA_HOOK_OK;
+}
+
+
static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
pa_sink *sink;
pa_source *source;
@@ -781,7 +927,10 @@ int pa__init(pa_module*m) {
char *fname;
pa_sink *sink;
pa_source *source;
+ pa_sink_input *si;
+ pa_source_output *so;
uint32_t idx;
+ pa_bool_t on_hotplug = TRUE, on_rescue = TRUE;
pa_assert(m);
@@ -790,9 +939,17 @@ int pa__init(pa_module*m) {
goto fail;
}
+ if (pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
+ pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
+ pa_log("on_hotplug= and on_rescue= expect boolean arguments");
+ goto fail;
+ }
+
m->userdata = u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->module = m;
+ u->on_hotplug = on_hotplug;
+ u->on_rescue = on_rescue;
u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
u->protocol = pa_native_protocol_get(m->core);
@@ -802,9 +959,27 @@ int pa__init(pa_module*m) {
u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
+ /* Used to handle device description management */
u->sink_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_new_hook_callback, u);
u->source_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_new_hook_callback, u);
+ /* The following slots are used to deal with routing */
+ /* A little bit later than module-stream-restore, module-intended-roles */
+ u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY+15, (pa_hook_cb_t) sink_input_new_hook_callback, u);
+ u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY+15, (pa_hook_cb_t) source_output_new_hook_callback, u);
+
+ if (on_hotplug) {
+ /* A little bit later than module-stream-restore, module-intended-roles */
+ u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+15, (pa_hook_cb_t) sink_put_hook_callback, u);
+ u->source_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+15, (pa_hook_cb_t) source_put_hook_callback, u);
+ }
+
+ if (on_rescue) {
+ /* A little bit later than module-stream-restore, module-intended-roles, a little bit earlier than module-rescue-streams, ... */
+ u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+15, (pa_hook_cb_t) sink_unlink_hook_callback, u);
+ u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+15, (pa_hook_cb_t) source_unlink_hook_callback, u);
+ }
+
if (!(fname = pa_state_path("device-manager", TRUE)))
goto fail;
@@ -817,12 +992,18 @@ int pa__init(pa_module*m) {
pa_log_info("Sucessfully opened database file '%s'.", fname);
pa_xfree(fname);
- for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx))
+ PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
- for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx))
+ 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(si, m->core->sink_inputs, idx)
+ subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, si->index, u);
+
+ PA_IDXSET_FOREACH(so, m->core->source_outputs, idx)
+ subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, so->index, u);
+
pa_modargs_free(ma);
return 0;
@@ -851,6 +1032,21 @@ void pa__done(pa_module*m) {
if (u->source_new_hook_slot)
pa_hook_slot_free(u->source_new_hook_slot);
+ if (u->sink_input_new_hook_slot)
+ pa_hook_slot_free(u->sink_input_new_hook_slot);
+ if (u->source_output_new_hook_slot)
+ pa_hook_slot_free(u->source_output_new_hook_slot);
+
+ if (u->sink_put_hook_slot)
+ pa_hook_slot_free(u->sink_put_hook_slot);
+ if (u->source_put_hook_slot)
+ pa_hook_slot_free(u->source_put_hook_slot);
+
+ if (u->sink_unlink_hook_slot)
+ pa_hook_slot_free(u->sink_unlink_hook_slot);
+ if (u->source_unlink_hook_slot)
+ pa_hook_slot_free(u->source_unlink_hook_slot);
+
if (u->save_time_event)
u->core->mainloop->time_free(u->save_time_event);