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) | 
