diff options
author | Lennart Poettering <lennart@poettering.net> | 2008-05-26 22:00:19 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2008-05-26 22:00:19 +0000 |
commit | d7fd6a45e50475cddf0b8bad8baab01b33cf3c1f (patch) | |
tree | 4f210adb96478280df083b6d4802053f93b59192 /src/common.c | |
parent | 48178a5e2813546b61706d1f97fab761934a97f0 (diff) |
move sources to src/ subdir
git-svn-id: file:///home/lennart/svn/public/libcanberra/trunk@12 01b60673-d06a-42c0-afdd-89cb8e0f78ac
Diffstat (limited to 'src/common.c')
-rw-r--r-- | src/common.c | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..bf11450 --- /dev/null +++ b/src/common.c @@ -0,0 +1,380 @@ +/* $Id$ */ + +/*** + 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/>. +***/ + +#include <stdarg.h> + +#include "canberra.h" +#include "common.h" +#include "malloc.h" +#include "driver.h" +#include "proplist.h" + +int ca_context_create(ca_context **_c) { + ca_context *c; + int ret; + + ca_return_val_if_fail(_c, CA_ERROR_INVALID); + + if (!(c = ca_new0(ca_context, 1))) + return CA_ERROR_OOM; + + if (!(c->mutex = ca_mutex_new())) { + ca_free(c); + return CA_ERROR_OOM; + } + + if ((ret = ca_proplist_create(&c->props)) < 0) { + ca_mutex_free(c->mutex); + ca_free(c); + return ret; + } + + *_c = c; + return CA_SUCCESS; +} + +int ca_context_destroy(ca_context *c) { + int ret = CA_SUCCESS; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + /* There's no locking necessary here, because the application is + * broken anyway if it destructs this object in one thread and + * still is calling a method of it in another. */ + + if (c->opened) + ret = driver_destroy(c); + + if (c->props) + ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); + + ca_mutex_free(c->mutex); + ca_free(c->driver); + ca_free(c->device); + ca_free(c); + + return ret; +} + +int ca_context_set_driver(ca_context *c, char *driver) { + char *n; + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex); + + if (!(n = ca_strdup(driver))) { + ret = CA_ERROR_OOM; + goto fail; + } + + ca_free(c->driver); + c->driver = n; + + ret = CA_SUCCESS; + +fail: + ca_mutex_unlock(c->mutex); + + return ret; +} + +int ca_context_change_device(ca_context *c, char *device) { + char *n; + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + + if (!(n = ca_strdup(device))) { + ret = CA_ERROR_OOM; + goto fail; + } + + ret = c->opened ? driver_change_device(c, n) : CA_SUCCESS; + + if (ret == CA_SUCCESS) { + ca_free(c->device); + c->device = n; + } else + ca_free(n); + +fail: + ca_mutex_unlock(c->mutex); + + return ret; +} + +static int context_open_unlocked(ca_context *c) { + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + if (c->opened) + return CA_SUCCESS; + + if ((ret = driver_open(c)) == CA_SUCCESS) + c->opened = TRUE; + + return ret; +} + +int ca_context_open(ca_context *c) { + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex); + + ret = context_open_unlocked(c); + + ca_mutex_unlock(c->mutex); + + return ret; +} + +static int ca_proplist_from_ap(ca_proplist **_p, va_list ap) { + int ret; + ca_proplist *p; + + ca_assert(_p); + + if ((ret = ca_proplist_create(&p)) < 0) + return ret; + + for (;;) { + const char *key, *value; + int ret; + + if (!(key = va_arg(ap, const char*))) + break; + + if (!(value = va_arg(ap, const char*))) { + ret = CA_ERROR_INVALID; + goto fail; + } + + if ((ret = ca_proplist_sets(p, key, value)) < 0) + goto fail; + } + + *_p = p; + + return CA_SUCCESS; + +fail: + ca_assert_se(ca_proplist_destroy(p) == CA_SUCCESS); + + return ret; +} + +int ca_context_change_props(ca_context *c, ...) { + va_list ap; + int ret; + ca_proplist *p = NULL; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + va_start(ap, c); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); + + if (ret < 0) + return ret; + + ret = ca_context_change_props_full(c, p); + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +int ca_context_change_props_full(ca_context *c, ca_proplist *p) { + int ret; + ca_proplist *merged; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); + + ca_mutex_lock(c->mutex); + + if ((ret = ca_proplist_merge(&merged, c->props, p)) < 0) + goto finish; + + ret = c->opened ? driver_change_props(c, p, merged) : CA_SUCCESS; + + if (ret == CA_SUCCESS) { + ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS); + c->props = merged; + } else + ca_assert_se(ca_proplist_destroy(merged) == CA_SUCCESS); + +finish: + + ca_mutex_unlock(c->mutex); + + return ret; +} + +int ca_context_play(ca_context *c, uint32_t id, ...) { + int ret; + va_list ap; + ca_proplist *p = NULL; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + va_start(ap, id); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); + + if (ret < 0) + return ret; + + ret = ca_context_play_full(c, id, p, NULL, NULL); + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata) { + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); + ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID); + + ca_mutex_lock(c->mutex); + + ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || + ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex); + + if ((ret = context_open_unlocked(c)) < 0) + goto finish; + + ca_assert(c->opened); + + ret = driver_play(c, id, p, cb, userdata); + +finish: + + ca_mutex_unlock(c->mutex); + + return ret; +} + +int ca_context_cancel(ca_context *c, uint32_t id) { + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_mutex_lock(c->mutex); + ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex); + + ret = driver_cancel(c, id); + + ca_mutex_unlock(c->mutex); + + return ret; +} + +int ca_context_cache(ca_context *c, ...) { + int ret; + va_list ap; + ca_proplist *p = NULL; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + + va_start(ap, c); + ret = ca_proplist_from_ap(&p, ap); + va_end(ap); + + if (ret < 0) + return ret; + + ret = ca_context_cache_full(c, p); + + ca_assert_se(ca_proplist_destroy(p) == 0); + + return ret; +} + +int ca_context_cache_full(ca_context *c, ca_proplist *p) { + int ret; + + ca_return_val_if_fail(c, CA_ERROR_INVALID); + ca_return_val_if_fail(p, CA_ERROR_INVALID); + + ca_mutex_lock(c->mutex); + + ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) || + ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex); + + if ((ret = context_open_unlocked(c)) < 0) + goto finish; + + ca_assert(c->opened); + + ret = driver_cache(c, p); + +finish: + + ca_mutex_unlock(c->mutex); + + return ret; +} + +/** Return a human readable error */ +const char *ca_strerror(int code) { + + const char * const error_table[-_CA_ERROR_MAX] = { + [-CA_SUCCESS] = "Success", + [-CA_ERROR_NOT_SUPPORTED] = "Operation not supported", + [-CA_ERROR_INVALID] = "Invalid argument", + [-CA_ERROR_STATE] = "Invalid state", + [-CA_ERROR_OOM] = "Out of memory", + [-CA_ERROR_NO_DRIVER] = "No such driver", + [-CA_ERROR_SYSTEM] = "System error" + }; + + ca_return_val_if_fail(code <= 0, NULL); + ca_return_val_if_fail(code > _CA_ERROR_MAX, NULL); + + return error_table[-code]; +} + +/* Not exported */ +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(control, "never")) + *control = CA_CACHE_CONTROL_NEVER; + else if (streq(control, "permanent")) + *control = CA_CACHE_CONTROL_PERMANENT; + else if (streq(control, "volatile")) + *control = CA_CACHE_CONTROL_VOLATILE; + else + return CA_ERROR_INVALID; + + return CA_SUCCESS; +} |