diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 21 | ||||
-rw-r--r-- | src/alsa.c | 5 | ||||
-rw-r--r-- | src/common.c | 10 | ||||
-rw-r--r-- | src/driver-order.c | 39 | ||||
-rw-r--r-- | src/driver-order.h | 26 | ||||
-rw-r--r-- | src/driver.h | 1 | ||||
-rw-r--r-- | src/dso.c | 16 | ||||
-rw-r--r-- | src/macro.h | 2 | ||||
-rw-r--r-- | src/multi.c | 327 | ||||
-rw-r--r-- | src/null.c | 2 | ||||
-rw-r--r-- | src/pulse.c | 2 | ||||
-rw-r--r-- | src/sound-theme-spec.c | 18 |
12 files changed, 436 insertions, 33 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 0f26587..74bf88c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,11 +64,30 @@ plugin_LTLIBRARIES = if BUILTIN_DSO libcanberra_la_SOURCES += \ - dso.c + dso.c \ + driver-order.c driver-order.h libcanberra_la_CFLAGS += \ $(LTDLINCL) libcanberra_la_LIBADD += \ $(LIBLTDL) + +plugin_LTLIBRARIES += \ + libcanberra-multi.la + +libcanberra_multi_la_SOURCES = \ + multi.c +libcanberra_multi_la_CFLAGS = \ + -Ddriver_open=multi_driver_open \ + -Ddriver_destroy=multi_driver_destroy \ + -Ddriver_change_device=multi_driver_change_device \ + -Ddriver_change_props=multi_driver_change_props \ + -Ddriver_play=multi_driver_play \ + -Ddriver_cancel=multi_driver_cancel \ + -Ddriver_cache=multi_driver_cache +libcanberra_multi_la_LIBADD = \ + libcanberra.la +libcanberra_multi_la_LDFLAGS = \ + -avoid-version -module -export-dynamic endif if HAVE_PULSE @@ -84,7 +84,7 @@ int driver_open(ca_context *c) { struct private *p; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(!c->driver || streq(c->driver, "alsa"), CA_ERROR_NODRIVER); + ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "alsa"), CA_ERROR_NODRIVER); ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE); if (!(c->private = p = ca_new0(struct private, 1))) @@ -180,6 +180,9 @@ int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged } int driver_cache(ca_context *c, ca_proplist *proplist) { + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + return CA_ERROR_NOTSUPPORTED; } diff --git a/src/common.c b/src/common.c index 71b887a..260c461 100644 --- a/src/common.c +++ b/src/common.c @@ -532,12 +532,12 @@ int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_c ca_mutex_lock(c->props->mutex); if ((t = ca_proplist_gets_unlocked(c->props, CA_PROP_CANBERRA_ENABLE))) - enabled = !streq(t, "0"); + enabled = !ca_streq(t, "0"); ca_mutex_unlock(c->props->mutex); ca_mutex_lock(p->mutex); if ((t = ca_proplist_gets_unlocked(p, CA_PROP_CANBERRA_ENABLE))) - enabled = !streq(t, "0"); + enabled = !ca_streq(t, "0"); ca_mutex_unlock(p->mutex); ca_return_val_if_fail_unlock(enabled, CA_ERROR_DISABLED, c->mutex); @@ -703,11 +703,11 @@ int ca_parse_cache_control(ca_cache_control_t *control, const char *c) { ca_return_val_if_fail(control, CA_ERROR_INVALID); ca_return_val_if_fail(c, CA_ERROR_INVALID); - if (streq(c, "never")) + if (ca_streq(c, "never")) *control = CA_CACHE_CONTROL_NEVER; - else if (streq(c, "permanent")) + else if (ca_streq(c, "permanent")) *control = CA_CACHE_CONTROL_PERMANENT; - else if (streq(c, "volatile")) + else if (ca_streq(c, "volatile")) *control = CA_CACHE_CONTROL_VOLATILE; else return CA_ERROR_INVALID; diff --git a/src/driver-order.c b/src/driver-order.c new file mode 100644 index 0000000..d97c0e1 --- /dev/null +++ b/src/driver-order.c @@ -0,0 +1,39 @@ +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra 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. + + libcanberra 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, If not, see + <http://www.gnu.org/licenses/>. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> + +#include "canberra.h" +#include "driver-order.h" + +const char* const ca_driver_order[] = { +#ifdef HAVE_PULSE + "pulse", +#endif +#ifdef HAVE_ALSA + "alsa", +#endif + /* ... */ + NULL +}; diff --git a/src/driver-order.h b/src/driver-order.h new file mode 100644 index 0000000..23e0783 --- /dev/null +++ b/src/driver-order.h @@ -0,0 +1,26 @@ +#ifndef foocanberradriverorderhfoo +#define foocanberradriverorderhfoo + +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra 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. + + libcanberra 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, If not, see + <http://www.gnu.org/licenses/>. +***/ + +extern const char* const ca_driver_order[]; + +#endif diff --git a/src/driver.h b/src/driver.h index 4f56a30..06acf3c 100644 --- a/src/driver.h +++ b/src/driver.h @@ -33,5 +33,4 @@ int driver_play(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t int driver_cancel(ca_context *c, uint32_t id); int driver_cache(ca_context *c, ca_proplist *p); - #endif @@ -29,6 +29,7 @@ #include "driver.h" #include "common.h" #include "malloc.h" +#include "driver-order.h" struct private_dso { lt_dlhandle module; @@ -45,17 +46,6 @@ struct private_dso { #define PRIVATE_DSO(c) ((struct private_dso *) ((c)->private_dso)) -static const char* const driver_order[] = { -#ifdef HAVE_PULSE - "pulse", -#endif -#ifdef HAVE_ALSA - "alsa", -#endif - /* ... */ - NULL -}; - static int ca_error_from_lt_error(int code) { static const int table[] = { @@ -106,7 +96,7 @@ static int lt_error_from_string(const char *t) { const struct lt_error_code *c; for (c = lt_error_codes; c->text; c++) - if (streq(t, c->text)) + if (ca_streq(t, c->text)) return c->code; return -1; @@ -214,7 +204,7 @@ int driver_open(ca_context *c) { } else { const char *const * e; - for (e = driver_order; *e; e++) { + for (e = ca_driver_order; *e; e++) { if ((ret = try_open(c, *e)) == CA_SUCCESS) break; diff --git a/src/macro.h b/src/macro.h index 582ba2b..db8affe 100644 --- a/src/macro.h +++ b/src/macro.h @@ -245,6 +245,6 @@ typedef void (*ca_free_cb_t)(void *); #define PA_UINT32_TO_BE(x) PA_UINT32_SWAP(x) #endif -#define streq(a, b) (strcmp((a),(b)) == 0) +#define ca_streq(a, b) (strcmp((a),(b)) == 0) #endif diff --git a/src/multi.c b/src/multi.c new file mode 100644 index 0000000..f6448d6 --- /dev/null +++ b/src/multi.c @@ -0,0 +1,327 @@ +/*** + This file is part of libcanberra. + + Copyright 2008 Lennart Poettering + + libcanberra 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. + + libcanberra 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with libcanberra. If not, If not, see + <http://www.gnu.org/licenses/>. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "driver.h" +#include "llist.h" +#include "malloc.h" +#include "common.h" +#include "driver-order.h" + +struct backend { + CA_LLIST_FIELDS(struct backend); + ca_context *context; +}; + +struct private { + ca_context *context; + CA_LLIST_HEAD(struct backend, backends); +}; + +#define PRIVATE(c) ((struct private *) ((c)->private)) + +static int add_backend(struct private *p, const char *name) { + struct backend *b; + int ret; + + ca_assert(p); + ca_assert(b); + + if (ca_streq(name, "multi")) + return CA_ERROR_NOTAVAILABLE; + + for (b = p->backends; b; b = b->next) + if (ca_streq(b->context->driver, name)) + return CA_ERROR_NOTAVAILABLE; + + if (!(b = ca_new0(struct backend, 1))) + return CA_ERROR_OOM; + + if ((ret = ca_context_create(&b->context)) < 0) + goto fail; + + if ((ret = ca_context_change_props_full(b->context, p->context->props)) < 0) + goto fail; + + if ((ret = ca_context_set_driver(b->context, name)) < 0) + goto fail; + + if ((ret = ca_context_open(b->context)) < 0) + goto fail; + + CA_LLIST_PREPEND(struct backend, p->backends, b); + + return CA_SUCCESS; + +fail: + + if (b->context) + ca_context_destroy(b->context); + + ca_free(b); + + return ret; +} + +static int remove_backend(struct private *p, struct backend *b) { + int ret; + + ca_assert(p); + ca_assert(b); + + ret = ca_context_destroy(b->context); + CA_LLIST_REMOVE(struct backend, p->backends, b); + ca_free(b); + + return ret; +} + +int driver_open(ca_context *c) { + struct private *p; + int ret = CA_SUCCESS; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "multi"), CA_ERROR_NODRIVER); + ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE); + + if (!(c->private = p = ca_new0(struct private, 1))) + return CA_ERROR_OOM; + + p->context = c; + + if (c->driver) { + char *e, *k; + + if (!(e = ca_strdup(c->driver))) { + driver_destroy(c); + return CA_ERROR_OOM; + } + + k = e; + for (;;) { + size_t n; + ca_bool_t last; + + n = strcspn(k, ":"); + last = k[n] == 0; + k[n] = 0; + + if (n > 0) { + int r; + + r = add_backend(p, k); + + if (ret == CA_SUCCESS) + ret = r; + } + + if (last) + break; + + k += n+1 ; + } + + ca_free(e); + + } else { + + const char *const *e; + + for (e = ca_driver_order; *e; e++) { + int r; + + r = add_backend(p, *e); + + /* We return the error code of the first module that fails only */ + if (ret == CA_SUCCESS) + ret = r; + } + } + + if (!p->backends) { + driver_destroy(c); + return ret == CA_SUCCESS ? CA_ERROR_NODRIVER : ret; + } + + return CA_SUCCESS; +} + + +int driver_destroy(ca_context *c) { + int ret = CA_SUCCESS; + struct private *p; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + while (p->backends) { + int r; + + r = remove_backend(p, p->backends); + + if (ret == CA_SUCCESS) + ret = r; + } + + ca_free(p); + + c->private = NULL; + + return ret; +} + +int driver_change_device(ca_context *c, char *device) { + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + return CA_ERROR_NOTSUPPORTED; +} + +int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(changed, CA_ERROR_INVALID); + ca_return_val_if_fail(merged, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + for (b = p->backends; b; b = b->next) { + int r; + + r = ca_context_change_props_full(b->context, changed); + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + return ret; +} + +struct closure { + ca_context *context; + ca_finish_callback_t callback; + void *userdata; +}; + +static void call_closure(ca_context *c, uint32_t id, int error_code, void *userdata) { + struct closure *closure = userdata; + + closure->callback(closure->context, id, error_code, closure->userdata); + ca_free(closure); +} + +int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + struct closure *closure; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + if (cb) { + if (!(closure = ca_new(struct closure, 1))) + return CA_ERROR_OOM; + + closure->context = c; + closure->callback = cb; + closure->userdata = userdata; + } else + closure = NULL; + + /* The first backend that can play this, takes it */ + for (b = p->backends; b; b = b->next) { + int r; + + if ((r = ca_context_play_full(b->context, id, proplist, closure ? call_closure : NULL, closure)) == CA_SUCCESS) + return r; + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + ca_free(closure); + + return ret; +} + +int driver_cancel(ca_context *c, uint32_t id) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + for (b = p->backends; b; b = b->next) { + int r; + + r = ca_context_cancel(b->context, id); + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + return ret; +} + +int driver_cache(ca_context *c, ca_proplist *proplist) { + int ret = CA_SUCCESS; + struct private *p; + struct backend *b; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(proplist, CA_ERROR_INVALID); + ca_return_val_if_fail(c->private, CA_ERROR_STATE); + + p = PRIVATE(c); + + /* The first backend that can cache this, takes it */ + for (b = p->backends; b; b = b->next) { + int r; + + if ((r = ca_context_cache_full(b->context, proplist)) == CA_SUCCESS) + return r; + + /* We only return the first failure */ + if (ret == CA_SUCCESS) + ret = r; + } + + return ret; +} @@ -30,7 +30,7 @@ int driver_open(ca_context *c) { ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(!c->driver || streq(c->driver, "null"), CA_ERROR_NODRIVER); + ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "null"), CA_ERROR_NODRIVER); return CA_SUCCESS; } diff --git a/src/pulse.c b/src/pulse.c index 1d64c86..785c967 100644 --- a/src/pulse.c +++ b/src/pulse.c @@ -248,7 +248,7 @@ int driver_open(ca_context *c) { int ret; ca_return_val_if_fail(c, CA_ERROR_INVALID); - ca_return_val_if_fail(!c->driver || streq(c->driver, "pulse"), CA_ERROR_NODRIVER); + ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "pulse"), CA_ERROR_NODRIVER); ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE); if (!(c->private = p = ca_new0(struct private, 1))) diff --git a/src/sound-theme-spec.c b/src/sound-theme-spec.c index 49282db..611b008 100644 --- a/src/sound-theme-spec.c +++ b/src/sound-theme-spec.c @@ -87,7 +87,7 @@ static ca_bool_t data_dir_matches(ca_data_dir *d, const char*output_profile) { if (!d->output_profile) return TRUE; - return streq(d->output_profile, output_profile); + return ca_streq(d->output_profile, output_profile); } static ca_data_dir* find_data_dir(ca_theme_data *t, const char *name) { @@ -97,7 +97,7 @@ static ca_data_dir* find_data_dir(ca_theme_data *t, const char *name) { ca_assert(name); for (d = t->data_dirs; d; d = d->next) - if (streq(d->name, name)) + if (ca_streq(d->name, name)) return d; return NULL; @@ -171,7 +171,7 @@ static int load_theme_path(ca_theme_data *t, const char *prefix, const char *nam if (!ln[0]) continue; - if (streq(ln, "[Sound Theme]")) { + if (ca_streq(ln, "[Sound Theme]")) { in_sound_theme_section = TRUE; current_data_dir = NULL; continue; @@ -248,7 +248,7 @@ static int load_theme_path(ca_theme_data *t, const char *prefix, const char *nam if (!strncmp(ln, "OutputProfile=", 14)) { - if (current_data_dir->output_profile && !streq(current_data_dir->output_profile, ln+14)) { + if (current_data_dir->output_profile && !ca_streq(current_data_dir->output_profile, ln+14)) { ret = CA_ERROR_CORRUPT; goto fail; } @@ -314,7 +314,7 @@ static int load_theme_dir(ca_theme_data *t, const char *name) { if ((ret = get_data_home(&e)) < 0) return ret; - if (streq(name, FALLBACK_THEME)) + if (ca_streq(name, FALLBACK_THEME)) t->loaded_fallback_theme = TRUE; if (e) { @@ -363,7 +363,7 @@ static int load_theme_data(ca_theme_data **_t, const char *name) { ca_return_val_if_fail(name, CA_ERROR_INVALID); if (*_t) - if (streq((*_t)->name, name)) + if (ca_streq((*_t)->name, name)) return CA_SUCCESS; if (!(t = ca_new0(ca_theme_data, 1))) @@ -424,7 +424,7 @@ static int find_sound_for_suffix( name, suffix))) return CA_ERROR_OOM; - if (streq(suffix, ".disabled")) { + if (ca_streq(suffix, ".disabled")) { if (access(fn, F_OK) == 0) ret = CA_ERROR_DISABLED; @@ -665,7 +665,7 @@ static int find_sound_in_theme( return ret; /* Then, fall back to stereo */ - if (!streq(profile, DEFAULT_OUTPUT_PROFILE)) + if (!ca_streq(profile, DEFAULT_OUTPUT_PROFILE)) if ((ret = find_sound_in_profile(f, t, name, locale, DEFAULT_OUTPUT_PROFILE)) != CA_ERROR_NOTFOUND) return ret; } @@ -693,7 +693,7 @@ static int find_sound_for_theme( /* First, try in the theme itself, and if that fails the fallback theme */ if ((ret = load_theme_data(t, theme)) == CA_ERROR_NOTFOUND) - if (!streq(theme, FALLBACK_THEME)) + if (!ca_streq(theme, FALLBACK_THEME)) ret = load_theme_data(t, FALLBACK_THEME); if (ret == CA_SUCCESS) |