summaryrefslogtreecommitdiffstats
path: root/src/modules/module-device-manager.c
diff options
context:
space:
mode:
authorColin Guthrie <cguthrie@mandriva.org>2009-09-20 17:29:38 +0100
committerColin Guthrie <cguthrie@mandriva.org>2009-10-01 09:08:30 +0100
commited8af7c8fd7bf845a243518357b6b73667d209c0 (patch)
treef42c187eeb5fbc02c955b61cb0f3ddcdf85bcc7e /src/modules/module-device-manager.c
parentfaae33d808480a34f02bea6e66ba0da0523694cf (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/modules/module-device-manager.c')
-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);