diff options
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rwxr-xr-x | src/daemon/default.pa.in | 5 | ||||
-rw-r--r-- | src/modules/module-always-sink.c | 180 | ||||
-rw-r--r-- | src/modules/module-combine.c | 6 | ||||
-rw-r--r-- | src/modules/module-device-restore.c | 4 | ||||
-rw-r--r-- | src/modules/module-null-sink.c | 4 | ||||
-rw-r--r-- | src/modules/module-position-event-sounds.c | 2 | ||||
-rw-r--r-- | src/modules/module-rescue-streams.c | 4 | ||||
-rw-r--r-- | src/modules/module-suspend-on-idle.c | 30 | ||||
-rw-r--r-- | src/modules/module-volume-restore.c | 6 | ||||
-rw-r--r-- | src/modules/module-zeroconf-publish.c | 12 | ||||
-rw-r--r-- | src/pulsecore/hook-list.c | 37 | ||||
-rw-r--r-- | src/pulsecore/hook-list.h | 14 | ||||
-rw-r--r-- | src/tests/hook-list-test.c | 10 |
14 files changed, 262 insertions, 60 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index e626d04e..a5d0fd75 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1021,6 +1021,7 @@ modlibexec_LTLIBRARIES += \ module-volume-restore.la \ module-device-restore.la \ module-default-device-restore.la \ + module-always-sink.la \ module-rescue-streams.la \ module-suspend-on-idle.la \ module-http-protocol-tcp.la \ @@ -1200,6 +1201,7 @@ SYMDEF_FILES = \ modules/module-volume-restore-symdef.h \ modules/module-device-restore-symdef.h \ modules/module-default-device-restore-symdef.h \ + modules/module-always-sink-symdef.h \ modules/module-rescue-streams-symdef.h \ modules/module-suspend-on-idle-symdef.h \ modules/module-hal-detect-symdef.h \ @@ -1459,6 +1461,12 @@ module_default_device_restore_la_LDFLAGS = -module -avoid-version module_default_device_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la module_default_device_restore_la_CFLAGS = $(AM_CFLAGS) +# Always Sink module +module_always_sink_la_SOURCES = modules/module-always-sink.c +module_always_sink_la_LDFLAGS = -module -avoid-version +module_always_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la +module_always_sink_la_CFLAGS = $(AM_CFLAGS) + # Rescue streams module module_rescue_streams_la_SOURCES = modules/module-rescue-streams.c module_rescue_streams_la_LDFLAGS = -module -avoid-version diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index 057b79c8..aad9f5d6 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -74,11 +74,14 @@ load-module module-default-device-restore ### connected to dies, similar for sources load-module module-rescue-streams +### Make sure we always have a sink around, even if it is a null sink. +load-module module-always-sink + ### Automatically suspend sinks/sources that become idle for too long load-module module-suspend-on-idle ### Load X11 bell module -#load-module module-x11-bell sample=x11-bell +#load-module module-x11-bell sample=bell-windowing-system ### Register ourselves in the X11 session manager # Deactivated by default, to avoid deadlock when PA is started as esd from gnome-session diff --git a/src/modules/module-always-sink.c b/src/modules/module-always-sink.c new file mode 100644 index 00000000..fd644a2f --- /dev/null +++ b/src/modules/module-always-sink.c @@ -0,0 +1,180 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + Copyright 2008 Colin Guthrie + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pulse/xmalloc.h> + +#include <pulsecore/core.h> +#include <pulsecore/sink-input.h> +#include <pulsecore/modargs.h> +#include <pulsecore/log.h> +#include <pulsecore/namereg.h> +#include <pulsecore/core-util.h> + +#include "module-always-sink-symdef.h" + +PA_MODULE_AUTHOR("Colin Guthrie"); +PA_MODULE_DESCRIPTION("Always keeps at least one sink loaded even if it's a null one"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(TRUE); +PA_MODULE_USAGE( + "sink_name=<name of sink>"); + +#define DEFAULT_SINK_NAME "auto_null" + +static const char* const valid_modargs[] = { + "sink_name", + NULL, +}; + +struct userdata { + pa_hook_slot *put_slot, *unlink_slot; + pa_module* null_module; + pa_bool_t ignore; + char *sink_name; +}; + +static void load_null_sink_if_needed(pa_core *c, pa_sink *sink, struct userdata* u) { + pa_sink *target; + uint32_t idx; + char *t; + + pa_assert(c); + pa_assert(u); + pa_assert(!u->null_module); + + /* Loop through all sinks and check to see if we have *any* + * sinks. Ignore the sink passed in (if it's not null) */ + for (target = pa_idxset_first(c->sinks, &idx); target; target = pa_idxset_next(c->sinks, &idx)) + if (!sink || target != sink) + break; + + if (target) + return; + + pa_log_debug("Autoloading null-sink as no other sinks detected."); + + u->ignore = TRUE; + + t = pa_sprintf_malloc("sink_name=%s", u->sink_name); + u->null_module = pa_module_load(c, "module-null-sink", t); + pa_xfree(t); + + u->ignore = FALSE; + + if (!u->null_module) + pa_log_warn("Unable to load module-null-sink"); +} + +static pa_hook_result_t put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { + struct userdata *u = userdata; + + pa_assert(c); + pa_assert(sink); + pa_assert(u); + + /* This is us detecting ourselves on load... just ignore this. */ + if (u->ignore) + return PA_HOOK_OK; + + /* Auto-loaded null-sink not active, so ignoring newly detected sink. */ + if (!u->null_module) + return PA_HOOK_OK; + + /* This is us detecting ourselves on load in a different way... just ignore this too. */ + if (sink->module == u->null_module) + return PA_HOOK_OK; + + pa_log_info("A new sink has been discovered. Unloading null-sink."); + + pa_module_unload_request(u->null_module); + u->null_module = NULL; + + return PA_HOOK_OK; +} + +static pa_hook_result_t unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { + struct userdata *u = userdata; + + pa_assert(c); + pa_assert(sink); + pa_assert(u); + + /* First check to see if it's our own null-sink that's been removed... */ + if (u->null_module && sink->module == u->null_module) { + pa_log_debug("Autoloaded null-sink removed"); + u->null_module = NULL; + return PA_HOOK_OK; + } + + load_null_sink_if_needed(c, sink, u); + + return PA_HOOK_OK; +} + +int pa__init(pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u; + + pa_assert(m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments"); + return -1; + } + + m->userdata = u = pa_xnew(struct userdata, 1); + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); + u->put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) put_hook_callback, u); + u->unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) unlink_hook_callback, u); + u->null_module = NULL; + u->ignore = FALSE; + + pa_modargs_free(ma); + + load_null_sink_if_needed(m->core, NULL, u); + + return 0; +} + +void pa__done(pa_module*m) { + struct userdata *u; + + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->put_slot) + pa_hook_slot_free(u->put_slot); + if (u->unlink_slot) + pa_hook_slot_free(u->unlink_slot); + if (u->null_module) + pa_module_unload_request(u->null_module); + + pa_xfree(u->sink_name); + pa_xfree(u); +} diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c index fc8be18d..eab86531 100644 --- a/src/modules/module-combine.c +++ b/src/modules/module-combine.c @@ -1088,11 +1088,11 @@ int pa__init(pa_module*m) { } } - u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], (pa_hook_cb_t) sink_new_hook_cb, u); + u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_new_hook_cb, u); } - u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_unlink_hook_cb, u); - u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) sink_state_changed_hook_cb, u); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_cb, u); + u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_state_changed_hook_cb, u); pick_master(u, NULL); diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index f8f2e4ba..94b089d4 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -282,8 +282,8 @@ int pa__init(pa_module*m) { u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u); - u->sink_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_FIXATE], (pa_hook_cb_t) sink_fixate_hook_callback, u); - u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], (pa_hook_cb_t) source_fixate_hook_callback, u); + u->sink_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_fixate_hook_callback, u); + u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_fixate_hook_callback, u); m->userdata = u; diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index aff244fa..0d6a854e 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -59,8 +59,8 @@ PA_MODULE_USAGE( "format=<sample format> " "channels=<number of channels> " "rate=<sample rate> " - "sink_name=<name of sink>" - "channel_map=<channel map>" + "sink_name=<name of sink> " + "channel_map=<channel map> " "description=<description for the sink>"); #define DEFAULT_SINK_NAME "null" diff --git a/src/modules/module-position-event-sounds.c b/src/modules/module-position-event-sounds.c index 30f0fd9f..789db240 100644 --- a/src/modules/module-position-event-sounds.c +++ b/src/modules/module-position-event-sounds.c @@ -137,7 +137,7 @@ int pa__init(pa_module*m) { m->userdata = u = pa_xnew(struct userdata, 1); u->core = m->core; - u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], (pa_hook_cb_t) sink_input_fixate_hook_callback, u); + u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_fixate_hook_callback, u); pa_modargs_free(ma); diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c index 7241a99f..31ae8bf6 100644 --- a/src/modules/module-rescue-streams.c +++ b/src/modules/module-rescue-streams.c @@ -139,8 +139,8 @@ int pa__init(pa_module*m) { } m->userdata = u = pa_xnew(struct userdata, 1); - u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_hook_callback, NULL); - u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) source_hook_callback, NULL); + u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_hook_callback, NULL); + u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_hook_callback, NULL); pa_modargs_free(ma); return 0; diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index a3985974..f50e4f50 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -367,21 +367,21 @@ int pa__init(pa_module*m) { for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx)) device_new_hook_cb(m->core, PA_OBJECT(source), u); - u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], (pa_hook_cb_t) device_new_hook_cb, u); - u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], (pa_hook_cb_t) device_new_hook_cb, u); - u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], (pa_hook_cb_t) device_unlink_hook_cb, u); - u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], (pa_hook_cb_t) device_unlink_hook_cb, u); - u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u); - u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], (pa_hook_cb_t) device_state_changed_hook_cb, u); - - u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], (pa_hook_cb_t) sink_input_fixate_hook_cb, u); - u->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], (pa_hook_cb_t) source_output_fixate_hook_cb, u); - u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], (pa_hook_cb_t) sink_input_unlink_hook_cb, u); - u->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], (pa_hook_cb_t) source_output_unlink_hook_cb, u); - u->sink_input_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], (pa_hook_cb_t) sink_input_move_hook_cb, u); - u->source_output_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], (pa_hook_cb_t) source_output_move_hook_cb, u); - u->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], (pa_hook_cb_t) sink_input_state_changed_hook_cb, u); - u->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], (pa_hook_cb_t) source_output_state_changed_hook_cb, u); + u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) device_new_hook_cb, u); + u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) device_new_hook_cb, u); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) device_unlink_hook_cb, u); + u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) device_unlink_hook_cb, u); + u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u); + u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u); + + u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_fixate_hook_cb, u); + u->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_fixate_hook_cb, u); + u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_unlink_hook_cb, u); + u->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_unlink_hook_cb, u); + u->sink_input_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_move_hook_cb, u); + u->source_output_move_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_move_hook_cb, u); + u->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_input_state_changed_hook_cb, u); + u->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) source_output_state_changed_hook_cb, u); pa_modargs_free(ma); return 0; diff --git a/src/modules/module-volume-restore.c b/src/modules/module-volume-restore.c index 1266c2ab..4f0184aa 100644 --- a/src/modules/module-volume-restore.c +++ b/src/modules/module-volume-restore.c @@ -515,12 +515,12 @@ int pa__init(pa_module*m) { u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u); if (restore_device) { - u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], (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_cb_t) source_output_new_hook_callback, u); + u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (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, (pa_hook_cb_t) source_output_new_hook_callback, u); } if (restore_volume) - u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], (pa_hook_cb_t) sink_input_fixate_hook_callback, u); + u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_fixate_hook_callback, u); pa_modargs_free(ma); return 0; diff --git a/src/modules/module-zeroconf-publish.c b/src/modules/module-zeroconf-publish.c index 6ed8e3d9..c39a51af 100644 --- a/src/modules/module-zeroconf-publish.c +++ b/src/modules/module-zeroconf-publish.c @@ -578,12 +578,12 @@ int pa__init(pa_module*m) { u->services = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], (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_cb_t) device_new_or_changed_cb, u); - u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) device_unlink_cb, u); - u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], (pa_hook_cb_t) device_new_or_changed_cb, u); - u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], (pa_hook_cb_t) device_new_or_changed_cb, u); - u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) device_unlink_cb, u); + 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); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) device_unlink_cb, u); + u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); + u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); + u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) device_unlink_cb, u); u->main_entry_group = NULL; diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index 3a6874c4..5d306faa 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -33,8 +33,7 @@ void pa_hook_init(pa_hook *hook, void *data) { pa_assert(hook); PA_LLIST_HEAD_INIT(pa_hook_slot, hook->slots); - hook->last = NULL; - hook->n_dead = hook->firing = 0; + hook->n_dead = hook->n_firing = 0; hook->data = data; } @@ -42,9 +41,6 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) { pa_assert(hook); pa_assert(slot); - if (hook->last == slot) - hook->last = slot->prev; - PA_LLIST_REMOVE(pa_hook_slot, hook->slots, slot); pa_xfree(slot); @@ -52,7 +48,7 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) { void pa_hook_free(pa_hook *hook) { pa_assert(hook); - pa_assert(!hook->firing); + pa_assert(hook->n_firing == 0); while (hook->slots) slot_free(hook, hook->slots); @@ -60,19 +56,26 @@ void pa_hook_free(pa_hook *hook) { pa_hook_init(hook, NULL); } -pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) { - pa_hook_slot *slot; +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data) { + pa_hook_slot *slot, *where, *prev; pa_assert(cb); slot = pa_xnew(pa_hook_slot, 1); slot->hook = hook; - slot->dead = 0; + slot->dead = FALSE; slot->callback = cb; slot->data = data; + slot->priority = prio; + + prev = NULL; + for (where = hook->slots; where; where = where->next) { + if (prio < where->priority) + break; + prev = where; + } - PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, hook->last, slot); - hook->last = slot; + PA_LLIST_INSERT_AFTER(pa_hook_slot, hook->slots, prev, slot); return slot; } @@ -81,8 +84,8 @@ void pa_hook_slot_free(pa_hook_slot *slot) { pa_assert(slot); pa_assert(!slot->dead); - if (slot->hook->firing > 0) { - slot->dead = 1; + if (slot->hook->n_firing > 0) { + slot->dead = TRUE; slot->hook->n_dead++; } else slot_free(slot->hook, slot); @@ -94,7 +97,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { pa_assert(hook); - hook->firing ++; + hook->n_firing ++; for (slot = hook->slots; slot; slot = slot->next) { if (slot->dead) @@ -104,7 +107,8 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { break; } - hook->firing --; + hook->n_firing --; + pa_assert(hook->n_firing >= 0); for (slot = hook->slots; hook->n_dead > 0 && slot; slot = next) { next = slot->next; @@ -115,6 +119,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) { } } + pa_assert(hook->n_dead == 0); + return result; } - diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h index c288980d..d91f6f4d 100644 --- a/src/pulsecore/hook-list.h +++ b/src/pulsecore/hook-list.h @@ -38,14 +38,21 @@ typedef enum pa_hook_result { PA_HOOK_CANCEL = -1 } pa_hook_result_t; +typedef enum pa_hook_priority { + PA_HOOK_EARLY = -100, + PA_HOOK_NORMAL = 0, + PA_HOOK_LATE = 100 +} pa_hook_priority_t; + typedef pa_hook_result_t (*pa_hook_cb_t)( void *hook_data, void *call_data, void *slot_data); struct pa_hook_slot { - int dead; + pa_bool_t dead; pa_hook *hook; + pa_hook_priority_t priority; pa_hook_cb_t callback; void *data; PA_LLIST_FIELDS(pa_hook_slot); @@ -53,8 +60,7 @@ struct pa_hook_slot { struct pa_hook { PA_LLIST_HEAD(pa_hook_slot, slots); - pa_hook_slot *last; - int firing, n_dead; + int n_firing, n_dead; void *data; }; @@ -62,7 +68,7 @@ struct pa_hook { void pa_hook_init(pa_hook *hook, void *data); void pa_hook_free(pa_hook *hook); -pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t, void *data); +pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data); void pa_hook_slot_free(pa_hook_slot *slot); pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data); diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c index 8628f521..e66bb27c 100644 --- a/src/tests/hook-list-test.c +++ b/src/tests/hook-list-test.c @@ -7,12 +7,12 @@ #include <pulsecore/hook-list.h> #include <pulsecore/log.h> -static pa_hook_result_t func1(const char*hook_data, const char*call_data, const char*slot_data) { +static pa_hook_result_t func1(const char *hook_data, const char *call_data, const char *slot_data) { pa_log("(func1) hook=%s call=%s slot=%s", hook_data, call_data, slot_data); return PA_HOOK_OK; } -static pa_hook_result_t func2(const char*hook_data, const char*call_data, const char*slot_data) { +static pa_hook_result_t func2(const char *hook_data, const char *call_data, const char *slot_data) { pa_log("(func2) hook=%s call=%s slot=%s", hook_data, call_data, slot_data); return PA_HOOK_OK; } @@ -23,9 +23,9 @@ int main(int argc, char *argv[]) { pa_hook_init(&hook, (void*) "hook"); - pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot1"); - slot = pa_hook_connect(&hook, (pa_hook_cb_t) func2, (void*) "slot2"); - pa_hook_connect(&hook, (pa_hook_cb_t) func1, (void*) "slot3"); + pa_hook_connect(&hook, PA_HOOK_LATE, (pa_hook_cb_t) func1, (void*) "slot1"); + slot = pa_hook_connect(&hook, PA_HOOK_NORMAL, (pa_hook_cb_t) func2, (void*) "slot2"); + pa_hook_connect(&hook, PA_HOOK_NORMAL, (pa_hook_cb_t) func1, (void*) "slot3"); pa_hook_fire(&hook, (void*) "call1"); |