summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-07-25 16:50:57 +0200
committerLennart Poettering <lennart@poettering.net>2008-07-25 16:50:57 +0200
commit571e728fb0e3982881589c8bb7a54052c5b6acde (patch)
treecda08cbcd56204ef794f9bf5bcdd35dd002a1e03
parentdd008275f922fea7076aa19479905400946e6707 (diff)
parent38d9db9575547ac9354944bd307db752e37601f6 (diff)
Merge branch 'gst'
-rw-r--r--src/Makefile.am21
-rw-r--r--src/alsa.c5
-rw-r--r--src/common.c10
-rw-r--r--src/driver-order.c39
-rw-r--r--src/driver-order.h26
-rw-r--r--src/driver.h1
-rw-r--r--src/dso.c16
-rw-r--r--src/macro.h2
-rw-r--r--src/multi.c327
-rw-r--r--src/null.c2
-rw-r--r--src/pulse.c2
-rw-r--r--src/sound-theme-spec.c18
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
diff --git a/src/alsa.c b/src/alsa.c
index 14156f3..15c34ed 100644
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -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
diff --git a/src/dso.c b/src/dso.c
index 31db543..aacec71 100644
--- a/src/dso.c
+++ b/src/dso.c
@@ -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;
+}
diff --git a/src/null.c b/src/null.c
index dd33808..2412786 100644
--- a/src/null.c
+++ b/src/null.c
@@ -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)