pulse/def.h \
pulse/direction.c pulse/direction.h \
pulse/error.c pulse/error.h \
+ pulse/extension.c pulse/extension.h \
pulse/ext-device-manager.c pulse/ext-device-manager.h \
pulse/ext-device-restore.c pulse/ext-device-restore.h \
pulse/ext-stream-restore.c pulse/ext-stream-restore.h \
}
}
+ c->extensions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+
return c;
}
static void context_unlink(pa_context *c) {
+ pa_extension *extension;
pa_stream *s;
pa_assert(c);
+ while ((extension = pa_hashmap_first(c->extensions)))
+ pa_extension_kill(extension);
+
s = c->streams ? pa_stream_ref(c->streams) : NULL;
while (s) {
pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
}
void pa_context_set_state(pa_context *c, pa_context_state_t st) {
+ pa_extension *extension;
+ void *state;
+
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
c->state = st;
+ PA_HASHMAP_FOREACH(extension, c->extensions, state)
+ pa_extension_context_state_changed(extension, 1);
+
+ PA_HASHMAP_FOREACH(extension, c->extensions, state)
+ pa_extension_context_state_changed(extension, 2);
+
if (c->state_callback)
c->state_callback(c, c->state_userdata);
pa_context *c = userdata;
uint32_t idx;
const char *name;
+ pa_extension *extension;
pa_assert(pd);
pa_assert(command == PA_COMMAND_EXTENSION);
pa_ext_stream_restore_command(c, tag, t);
else if (pa_streq(name, "module-node-manager"))
pa_ext_node_manager_command(c, tag, t);
- else
+ else if ((extension = pa_context_get_extension(c, name))) {
+ uint32_t subcommand;
+
+ if (pa_tagstruct_getu32(t, &subcommand) < 0) {
+ pa_context_fail(c, PA_ERR_PROTOCOL);
+ goto finish;
+ }
+
+ pa_extension_process_command(extension, subcommand, tag, t);
+ } else
pa_log(_("Received message for unknown extension '%s'"), name);
finish:
return pa_client_conf_load_cookie_from_file(c->conf, cookie_file_path);
}
+
+pa_extension *pa_context_get_extension(pa_context *context, const char *name) {
+ pa_assert(context);
+ pa_assert(name);
+
+ return pa_hashmap_get(context->extensions, name);
+}
+
+void pa_context_add_extension(pa_context *context, pa_extension *extension) {
+ pa_assert(context);
+ pa_assert(extension);
+
+ pa_assert_se(pa_hashmap_put(context->extensions, extension->name, extension) >= 0);
+}
+
+int pa_context_remove_extension(pa_context *context, pa_extension *extension) {
+ pa_assert(context);
+ pa_assert(extension);
+
+ return pa_hashmap_remove(context->extensions, extension->name) ? 0 : -1;
+}
--- /dev/null
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2014 Intel Corporation
+
+ 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.1 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 "extension.h"
+
+#include <pulsecore/macro.h>
+
+#include <pulse/internal.h>
+#include <pulse/xmalloc.h>
+
+pa_extension *pa_extension_new(pa_context *context, const char *name) {
+ pa_extension *extension = NULL;
+
+ pa_assert(context);
+ pa_assert(name);
+
+ extension = pa_xnew0(pa_extension, 1);
+ extension->context = context;
+ extension->name = pa_xstrdup(name);
+
+ return extension;
+}
+
+void pa_extension_put(pa_extension *extension) {
+ pa_assert(extension);
+ pa_assert(extension->kill);
+
+ pa_context_add_extension(extension->context, extension);
+}
+
+static void extension_unlink(pa_extension *extension) {
+ pa_assert(extension);
+
+ if (extension->unlinked)
+ return;
+
+ extension->unlinked = true;
+
+ pa_context_remove_extension(extension->context, extension);
+}
+
+void pa_extension_free(pa_extension *extension) {
+ pa_assert(extension);
+
+ extension_unlink(extension);
+
+ pa_xfree(extension->name);
+ pa_xfree(extension);
+}
+
+void pa_extension_context_state_changed(pa_extension *extension, unsigned phase) {
+ pa_assert(extension);
+ pa_assert(phase == 1 || phase == 2);
+
+ if (extension->context_state_changed)
+ extension->context_state_changed(extension, phase);
+}
+
+void pa_extension_kill(pa_extension *extension) {
+ pa_assert(extension);
+
+ if (extension->unlinked)
+ return;
+
+ extension->kill(extension);
+}
+
+void pa_extension_process_command(pa_extension *extension, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct) {
+ pa_assert(extension);
+ pa_assert(tagstruct);
+
+ if (extension->process_command)
+ extension->process_command(extension, command, tag, tagstruct);
+ else {
+ pa_log("Unexpected command for extension %s: %u", extension->name, command);
+ pa_context_fail(extension->context, PA_ERR_PROTOCOL);
+ }
+}
--- /dev/null
+#ifndef fooextensionhfoo
+#define fooextensionhfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2014 Intel Corporation
+
+ 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.1 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.
+***/
+
+#include <pulse/context.h>
+
+#include <pulsecore/tagstruct.h>
+
+#include <stdbool.h>
+
+typedef struct pa_extension pa_extension;
+
+struct pa_extension {
+ pa_context *context;
+ char *name;
+ bool unlinked;
+
+ /* This is called when the context state changes. The callback is called
+ * twice for each state change, first with phase = 1 and then with
+ * phase = 2. In the first phase the extension should update its internal
+ * state without calling any application callbacks. In the second phase it
+ * should call the application callbacks (if any). May be NULL. */
+ void (*context_state_changed)(pa_extension *extension, unsigned phase);
+
+ /* Called from pa_extension_kill(). May not be NULL. */
+ void (*kill)(pa_extension *extension);
+
+ /* Called from pa_extension_process_command(). May be NULL, if the
+ * extension doesn't expect any commands from the server. */
+ void (*process_command)(pa_extension *extension, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct);
+
+ void *userdata;
+};
+
+pa_extension *pa_extension_new(pa_context *context, const char *name);
+void pa_extension_put(pa_extension *extension);
+void pa_extension_free(pa_extension *extension);
+
+void pa_extension_context_state_changed(pa_extension *extension, unsigned phase);
+void pa_extension_kill(pa_extension *extension);
+void pa_extension_process_command(pa_extension *extension, uint32_t command, uint32_t tag, pa_tagstruct *tagstruct);
+
+#endif
USA.
***/
+#include <pulse/extension.h>
#include <pulse/mainloop-api.h>
#include <pulse/context.h>
#include <pulse/stream.h>
uint32_t client_index;
+ pa_hashmap *extensions; /* extension name -> pa_extension */
+
/* Extension specific data */
struct {
pa_ext_device_manager_subscribe_cb_t callback;
void pa_context_set_state(pa_context *c, pa_context_state_t st);
int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, bool fail);
pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata);
+pa_extension *pa_context_get_extension(pa_context *context, const char *name);
+void pa_context_add_extension(pa_context *context, pa_extension *extension);
+int pa_context_remove_extension(pa_context *context, pa_extension *extension);
void pa_stream_set_state(pa_stream *s, pa_stream_state_t st);