| File: | common.c |
| Warning: | line 141, column 17 Potential leak of memory pointed to by 'c' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ | |||
| 2 | ||||
| 3 | /*** | |||
| 4 | This file is part of libkanberra. | |||
| 5 | ||||
| 6 | Copyright 2008 Lennart Poettering | |||
| 7 | ||||
| 8 | libkanberra is free software; you can redistribute it and/or modify | |||
| 9 | it under the terms of the GNU Lesser General Public License as | |||
| 10 | published by the Free Software Foundation, either version 2.1 of the | |||
| 11 | License, or (at your option) any later version. | |||
| 12 | ||||
| 13 | libkanberra is distributed in the hope that it will be useful, but | |||
| 14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 16 | Lesser General Public License for more details. | |||
| 17 | ||||
| 18 | You should have received a copy of the GNU Lesser General Public | |||
| 19 | License along with libkanberra. If not, see | |||
| 20 | <http://www.gnu.org/licenses/>. | |||
| 21 | ***/ | |||
| 22 | ||||
| 23 | #ifdef HAVE_CONFIG_H1 | |||
| 24 | #include <config.h> | |||
| 25 | #endif | |||
| 26 | ||||
| 27 | #include <stdarg.h> | |||
| 28 | ||||
| 29 | #include "kanberra.h" | |||
| 30 | #include "common.h" | |||
| 31 | #include "malloc.h" | |||
| 32 | #include "driver.h" | |||
| 33 | #include "proplist.h" | |||
| 34 | #include "macro.h" | |||
| 35 | #include "fork-detect.h" | |||
| 36 | ||||
| 37 | /** | |||
| 38 | * SECTION:kanberra | |||
| 39 | * @short_description: General libkanberra API | |||
| 40 | * | |||
| 41 | * libkanberra defines a simple abstract interface for playing event sounds. | |||
| 42 | * | |||
| 43 | * libkanberra relies on the XDG sound naming specification for | |||
| 44 | * identifying event sounds. On Unix/Linux the right sound to play is | |||
| 45 | * found via the mechanisms defined in the XDG sound themeing | |||
| 46 | * specification. On other systems the XDG sound name is translated to | |||
| 47 | * the native sound id for the operating system. | |||
| 48 | * | |||
| 49 | * An event sound is triggered via libkanberra by calling the | |||
| 50 | * ka_context_play() function on a previously created ka_context | |||
| 51 | * object. The ka_context_play() takes a list of key-value pairs that | |||
| 52 | * describe the event sound to generate as closely as possible. The | |||
| 53 | * most important property is %KA_PROP_EVENT_ID which defines the XDG | |||
| 54 | * sound name for the sound to play. | |||
| 55 | * | |||
| 56 | * libkanberra is not a generic event abstraction system. It's only | |||
| 57 | * purpose is playing sounds -- however in a very elaborate way. As | |||
| 58 | * much information about the context the sound is triggered from | |||
| 59 | * shall be supplied to the sound system as possible, so that it can | |||
| 60 | * replace the sound with some other kind of feedback for a11y | |||
| 61 | * cases. Also this additional information can be used to enhance user | |||
| 62 | * experience (e.g. by positioning sounds in space depending on the | |||
| 63 | * place on the screen the sound was triggered from, and similar | |||
| 64 | * uses). | |||
| 65 | * | |||
| 66 | * The set of properties defined for event sounds is extensible and | |||
| 67 | * shared with other audio systems, such as PulseAudio. Some of | |||
| 68 | * the properties that may be set are specific to an application, to a | |||
| 69 | * window, to an input event or to the media being played back. | |||
| 70 | * | |||
| 71 | * The user can attach a set of properties to the context itself, | |||
| 72 | * which is than automatically inherited by each sample being played | |||
| 73 | * back. (ka_context_change_props()). | |||
| 74 | * | |||
| 75 | * Some of the properties can be filled in by libkanberra or one of | |||
| 76 | * its backends automatically and thus need not be be filled in by the | |||
| 77 | * application (such as %KA_PROP_APPLICATION_PROCESS_ID and | |||
| 78 | * friends). However the application can always overwrite any of these | |||
| 79 | * implicit properties. | |||
| 80 | * | |||
| 81 | * libkanberra is thread-safe and OOM-safe (as far as the backend | |||
| 82 | * allows this). It is not async-signal safe. | |||
| 83 | * | |||
| 84 | * Most libkanberra functions return an integer that indicates success | |||
| 85 | * when 0 (%KA_SUCCESS) or an error when negative. In the latter case | |||
| 86 | * ka_strerror() can be used to convert this code into a human | |||
| 87 | * readable string. | |||
| 88 | * | |||
| 89 | * libkanberra property names need to be in 7bit ASCII, string | |||
| 90 | * property values UTF8. | |||
| 91 | * | |||
| 92 | * Optionally a libkanberra backend can support caching of sounds in a | |||
| 93 | * sound system. If this functionality is used, the latencies for | |||
| 94 | * event sound playback can be much smaller and fewer resources are | |||
| 95 | * needed to start playback. If a backend does not support cacheing, | |||
| 96 | * the respective functions will return an error code of | |||
| 97 | * %KA_ERROR_NOTSUPPORTED. | |||
| 98 | * | |||
| 99 | * It is highly recommended that the application sets the | |||
| 100 | * %KA_PROP_APPLICATION_NAME, %KA_PROP_APPLICATION_ID, | |||
| 101 | * %KA_PROP_APPLICATION_ICON_NAME/%KA_PROP_APPLICATION_ICON properties | |||
| 102 | * immediately after creating the ka_context, before calling | |||
| 103 | * ka_context_open() or ka_context_play(). | |||
| 104 | * | |||
| 105 | * Its is highly recommended to pass at least %KA_PROP_EVENT_ID, | |||
| 106 | * %KA_PROP_EVENT_DESCRIPTION to ka_context_play() for each event | |||
| 107 | * sound generated. For sound events based on mouse inputs events | |||
| 108 | * %KA_PROP_EVENT_MOUSE_X, %KA_PROP_EVENT_MOUSE_Y, %KA_PROP_EVENT_MOUSE_HPOS, | |||
| 109 | * %KA_PROP_EVENT_MOUSE_VPOS, %KA_PROP_EVENT_MOUSE_BUTTON should be | |||
| 110 | * passed. For sound events attached to a widget on the screen, the | |||
| 111 | * %KA_PROP_WINDOW_xxx properties should be set. | |||
| 112 | * | |||
| 113 | * | |||
| 114 | */ | |||
| 115 | ||||
| 116 | /** | |||
| 117 | * ka_context_create: | |||
| 118 | * @c: A pointer wheere to fill in the newly created context object. | |||
| 119 | * | |||
| 120 | * Create an (unconnected) context object. This call will not connect | |||
| 121 | * to the sound system, calling this function might even suceed if no | |||
| 122 | * working driver backend is available. To find out if one is | |||
| 123 | * available call ka_context_open(). | |||
| 124 | * | |||
| 125 | * Returns: 0 on success, negative error code on error. | |||
| 126 | */ | |||
| 127 | ||||
| 128 | int ka_context_create(ka_context **_c) { | |||
| 129 | ka_context *c; | |||
| 130 | int ret; | |||
| 131 | const char *d; | |||
| 132 | ||||
| 133 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 133, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| ||||
| 134 | ka_return_val_if_fail(_c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(_c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "_c" , "common.c", 134, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 135 | ||||
| 136 | if (!(c = ka_new0(ka_context, 1)((ka_context*) calloc(1, (sizeof(ka_context)*(1)))))) | |||
| 137 | return KA_ERROR_OOM; | |||
| 138 | ||||
| 139 | if (!(c->mutex = ka_mutex_new())) { | |||
| 140 | ka_context_destroy(c); | |||
| 141 | return KA_ERROR_OOM; | |||
| ||||
| 142 | } | |||
| 143 | ||||
| 144 | if ((ret = ka_proplist_create(&c->props)) < 0) { | |||
| 145 | ka_context_destroy(c); | |||
| 146 | return ret; | |||
| 147 | } | |||
| 148 | ||||
| 149 | if ((d = getenv("KANBERRA_DRIVER"))) { | |||
| 150 | if ((ret = ka_context_set_driver(c, d)) < 0) { | |||
| 151 | ka_context_destroy(c); | |||
| 152 | return ret; | |||
| 153 | } | |||
| 154 | } | |||
| 155 | ||||
| 156 | if ((d = getenv("KANBERRA_DEVICE"))) { | |||
| 157 | if ((ret = ka_context_change_device(c, d)) < 0) { | |||
| 158 | ka_context_destroy(c); | |||
| 159 | return ret; | |||
| 160 | } | |||
| 161 | } | |||
| 162 | ||||
| 163 | *_c = c; | |||
| 164 | return KA_SUCCESS; | |||
| 165 | } | |||
| 166 | ||||
| 167 | /** | |||
| 168 | * ka_context_destroy: | |||
| 169 | * @c: the context to destroy. | |||
| 170 | * | |||
| 171 | * Destroy a (connected or unconnected) context object. | |||
| 172 | * | |||
| 173 | * Returns: 0 on success, negative error code on error. | |||
| 174 | */ | |||
| 175 | int ka_context_destroy(ka_context *c) { | |||
| 176 | int ret = KA_SUCCESS; | |||
| 177 | ||||
| 178 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 178, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 179 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 179, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 180 | ||||
| 181 | /* There's no locking necessary here, because the application is | |||
| 182 | * broken anyway if it destructs this object in one thread and | |||
| 183 | * still is calling a method of it in another. */ | |||
| 184 | ||||
| 185 | if (c->opened) | |||
| 186 | ret = driver_destroy(c); | |||
| 187 | ||||
| 188 | if (c->props) | |||
| 189 | ka_assert_se(ka_proplist_destroy(c->props) == KA_SUCCESS)do { if ((__builtin_expect((!(ka_proplist_destroy(c->props ) == KA_SUCCESS)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "ka_proplist_destroy(c->props) == KA_SUCCESS" , "common.c" , 189, __PRETTY_FUNCTION__); abort(); } } while ((0)); | |||
| 190 | ||||
| 191 | if (c->mutex) | |||
| 192 | ka_mutex_free(c->mutex); | |||
| 193 | ||||
| 194 | ka_freefree(c->driver); | |||
| 195 | ka_freefree(c->device); | |||
| 196 | ka_freefree(c); | |||
| 197 | ||||
| 198 | return ret; | |||
| 199 | } | |||
| 200 | ||||
| 201 | /** | |||
| 202 | * ka_context_set_driver: | |||
| 203 | * @c: the context to change the backend driver for | |||
| 204 | * @driver: the backend driver to use (e.g. "alsa", "pulse", "null", ...) | |||
| 205 | * | |||
| 206 | * Specify the backend driver used. This function may not be called again after | |||
| 207 | * ka_context_open() suceeded. This function might suceed even when | |||
| 208 | * the specified driver backend is not available. Use | |||
| 209 | * ka_context_open() to find out whether the backend is available. | |||
| 210 | * | |||
| 211 | * Returns: 0 on success, negative error code on error. | |||
| 212 | */ | |||
| 213 | int ka_context_set_driver(ka_context *c, const char *driver) { | |||
| 214 | char *n; | |||
| 215 | int ret; | |||
| 216 | ||||
| 217 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 217, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 218 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 218, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 219 | ka_mutex_lock(c->mutex); | |||
| 220 | ka_return_val_if_fail_unlock(!c->opened, KA_ERROR_STATE, c->mutex)do { if ((__builtin_expect((!(!c->opened)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!c->opened" , "common.c", 220, __PRETTY_FUNCTION__); ka_mutex_unlock (c->mutex); return (KA_ERROR_STATE); } } while((0)); | |||
| 221 | ||||
| 222 | if (!driver) | |||
| 223 | n = NULL((void*)0); | |||
| 224 | else if (!(n = ka_strdupstrdup(driver))) { | |||
| 225 | ret = KA_ERROR_OOM; | |||
| 226 | goto fail; | |||
| 227 | } | |||
| 228 | ||||
| 229 | ka_freefree(c->driver); | |||
| 230 | c->driver = n; | |||
| 231 | ||||
| 232 | ret = KA_SUCCESS; | |||
| 233 | ||||
| 234 | fail: | |||
| 235 | ka_mutex_unlock(c->mutex); | |||
| 236 | ||||
| 237 | return ret; | |||
| 238 | } | |||
| 239 | ||||
| 240 | /** | |||
| 241 | * ka_context_change_device: | |||
| 242 | * @c: the context to change the backend device for | |||
| 243 | * @device: the backend device to use, in a format that is specific to the backend. | |||
| 244 | * | |||
| 245 | * Specify the backend device to use. This function may be called not be called after | |||
| 246 | * ka_context_open() suceeded. This function might suceed even when | |||
| 247 | * the specified driver backend is not available. Use | |||
| 248 | * ka_context_open() to find out whether the backend is available | |||
| 249 | * | |||
| 250 | * Depending on the backend use this might or might not cause all | |||
| 251 | * currently playing event sounds to be moved to the new device.. | |||
| 252 | * | |||
| 253 | * Returns: 0 on success, negative error code on error. | |||
| 254 | */ | |||
| 255 | int ka_context_change_device(ka_context *c, const char *device) { | |||
| 256 | char *n; | |||
| 257 | int ret; | |||
| 258 | ||||
| 259 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 259, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 260 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 260, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 261 | ka_mutex_lock(c->mutex); | |||
| 262 | ||||
| 263 | if (!device) | |||
| 264 | n = NULL((void*)0); | |||
| 265 | else if (!(n = ka_strdupstrdup(device))) { | |||
| 266 | ret = KA_ERROR_OOM; | |||
| 267 | goto fail; | |||
| 268 | } | |||
| 269 | ||||
| 270 | ret = c->opened ? driver_change_device(c, n) : KA_SUCCESS; | |||
| 271 | ||||
| 272 | if (ret == KA_SUCCESS) { | |||
| 273 | ka_freefree(c->device); | |||
| 274 | c->device = n; | |||
| 275 | } else | |||
| 276 | ka_freefree(n); | |||
| 277 | ||||
| 278 | fail: | |||
| 279 | ka_mutex_unlock(c->mutex); | |||
| 280 | ||||
| 281 | return ret; | |||
| 282 | } | |||
| 283 | ||||
| 284 | static int context_open_unlocked(ka_context *c) { | |||
| 285 | int ret; | |||
| 286 | ||||
| 287 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 287, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 288 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 288, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 289 | ||||
| 290 | if (c->opened) | |||
| 291 | return KA_SUCCESS; | |||
| 292 | ||||
| 293 | if ((ret = driver_open(c)) == KA_SUCCESS) | |||
| 294 | c->opened = TRUE(!(0)); | |||
| 295 | ||||
| 296 | return ret; | |||
| 297 | } | |||
| 298 | ||||
| 299 | /** | |||
| 300 | * ka_context_open: | |||
| 301 | * @c: the context to connect. | |||
| 302 | * | |||
| 303 | * Connect the context to the sound system. This call is implicitly | |||
| 304 | * called in ka_context_play() or ka_context_cache() if not called | |||
| 305 | * explicitly. It is recommended to initialize application properties | |||
| 306 | * with ka_context_change_props() before calling this function. | |||
| 307 | * | |||
| 308 | * Returns: 0 on success, negative error code on error. | |||
| 309 | */ | |||
| 310 | int ka_context_open(ka_context *c) { | |||
| 311 | int ret; | |||
| 312 | ||||
| 313 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 313, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 314 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 314, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 315 | ka_mutex_lock(c->mutex); | |||
| 316 | ka_return_val_if_fail_unlock(!c->opened, KA_ERROR_STATE, c->mutex)do { if ((__builtin_expect((!(!c->opened)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!c->opened" , "common.c", 316, __PRETTY_FUNCTION__); ka_mutex_unlock (c->mutex); return (KA_ERROR_STATE); } } while((0)); | |||
| 317 | ||||
| 318 | ret = context_open_unlocked(c); | |||
| 319 | ||||
| 320 | ka_mutex_unlock(c->mutex); | |||
| 321 | ||||
| 322 | return ret; | |||
| 323 | } | |||
| 324 | ||||
| 325 | /** | |||
| 326 | * ka_context_change_props: | |||
| 327 | * @c: the context to set the properties on. | |||
| 328 | * @...: the list of string pairs for the properties. Needs to be a NULL terminated list. | |||
| 329 | * | |||
| 330 | * Write one or more string properties to the context object. Requires | |||
| 331 | * final NULL sentinel. Properties set like this will be attached to | |||
| 332 | * both the client object of the sound server and to all event sounds | |||
| 333 | * played or cached. It is recommended to call this function at least | |||
| 334 | * once before calling ka_context_open(), so that the initial | |||
| 335 | * application properties are set properly before the initial | |||
| 336 | * connection to the sound system. This function can be called both | |||
| 337 | * before and after the ka_context_open() call. Properties that have | |||
| 338 | * already been set before will be overwritten. | |||
| 339 | * | |||
| 340 | * Returns: 0 on success, negative error code on error. | |||
| 341 | */ | |||
| 342 | ||||
| 343 | int ka_context_change_props(ka_context *c, ...) { | |||
| 344 | va_list ap; | |||
| 345 | int ret; | |||
| 346 | ka_proplist *p = NULL((void*)0); | |||
| 347 | ||||
| 348 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 348, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 349 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 349, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 350 | ||||
| 351 | va_start(ap, c)__builtin_va_start(ap, c); | |||
| 352 | ret = ka_proplist_from_ap(&p, ap); | |||
| 353 | va_end(ap)__builtin_va_end(ap); | |||
| 354 | ||||
| 355 | if (ret < 0) | |||
| 356 | return ret; | |||
| 357 | ||||
| 358 | ret = ka_context_change_props_full(c, p); | |||
| 359 | ||||
| 360 | ka_assert_se(ka_proplist_destroy(p) == 0)do { if ((__builtin_expect((!(ka_proplist_destroy(p) == 0)),0 ))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "ka_proplist_destroy(p) == 0" , "common.c", 360, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); | |||
| 361 | ||||
| 362 | return ret; | |||
| 363 | } | |||
| 364 | ||||
| 365 | /** | |||
| 366 | * ka_context_change_props_full: | |||
| 367 | * @c: the context to set the properties on. | |||
| 368 | * @p: the property list to set. | |||
| 369 | * | |||
| 370 | * Similar to ka_context_change_props(), but takes a ka_proplist | |||
| 371 | * instead of a variable list of properties. Can be used to set binary | |||
| 372 | * properties such as %KA_PROP_APPLICATION_ICON. | |||
| 373 | * | |||
| 374 | * Returns: 0 on success, negative error code on error. | |||
| 375 | */ | |||
| 376 | ||||
| 377 | int ka_context_change_props_full(ka_context *c, ka_proplist *p) { | |||
| 378 | int ret; | |||
| 379 | ka_proplist *merged; | |||
| 380 | ||||
| 381 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 381, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 382 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 382, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 383 | ka_return_val_if_fail(p, KA_ERROR_INVALID)do { if ((__builtin_expect((!(p)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "p" , "common.c", 383, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 384 | ||||
| 385 | ka_mutex_lock(c->mutex); | |||
| 386 | ||||
| 387 | if ((ret = ka_proplist_merge(&merged, c->props, p)) < 0) | |||
| 388 | goto finish; | |||
| 389 | ||||
| 390 | ret = c->opened ? driver_change_props(c, p, merged) : KA_SUCCESS; | |||
| 391 | ||||
| 392 | if (ret == KA_SUCCESS) { | |||
| 393 | ka_assert_se(ka_proplist_destroy(c->props) == KA_SUCCESS)do { if ((__builtin_expect((!(ka_proplist_destroy(c->props ) == KA_SUCCESS)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "ka_proplist_destroy(c->props) == KA_SUCCESS" , "common.c" , 393, __PRETTY_FUNCTION__); abort(); } } while ((0)); | |||
| 394 | c->props = merged; | |||
| 395 | } else | |||
| 396 | ka_assert_se(ka_proplist_destroy(merged) == KA_SUCCESS)do { if ((__builtin_expect((!(ka_proplist_destroy(merged) == KA_SUCCESS )),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "ka_proplist_destroy(merged) == KA_SUCCESS" , "common.c", 396 , __PRETTY_FUNCTION__); abort(); } } while ((0)); | |||
| 397 | ||||
| 398 | finish: | |||
| 399 | ||||
| 400 | ka_mutex_unlock(c->mutex); | |||
| 401 | ||||
| 402 | return ret; | |||
| 403 | } | |||
| 404 | ||||
| 405 | /** | |||
| 406 | * ka_context_play: | |||
| 407 | * @c: the context to play the event sound on | |||
| 408 | * @id: an integer id this sound can later be identified with when calling ka_context_cancel() | |||
| 409 | * @...: additional properties for this sound event. | |||
| 410 | * | |||
| 411 | * Play one event sound. id can be any numeric value which later can | |||
| 412 | * be used to cancel an event sound that is currently being | |||
| 413 | * played. You may use the same id twice or more times if you want to | |||
| 414 | * cancel multiple event sounds with a single ka_context_cancel() call | |||
| 415 | * at once. It is recommended to pass 0 for the id if the event sound | |||
| 416 | * shall never be canceled. If the requested sound is not cached in | |||
| 417 | * the server yet this call might result in the sample being uploaded | |||
| 418 | * temporarily or permanently (this may be controlled with %KA_PROP_KANBERRA_CACHE_CONTROL). This function will start playback | |||
| 419 | * in the background. It will not wait until playback | |||
| 420 | * completed. Depending on the backend used a sound that is started | |||
| 421 | * shortly before your application terminates might or might not continue to | |||
| 422 | * play after your application terminated. If you want to make sure | |||
| 423 | * that all sounds finish to play you need to wait synchronously for | |||
| 424 | * the callback function of ka_context_play_full() to be called before you | |||
| 425 | * terminate your application. | |||
| 426 | * | |||
| 427 | * The sample to play is identified by the %KA_PROP_EVENT_ID | |||
| 428 | * property. If it is already cached in the server the cached version | |||
| 429 | * is played. The properties passed in this call are merged with the | |||
| 430 | * properties supplied when the sample was cached (if applicable) | |||
| 431 | * and the context properties as set with ka_context_change_props(). | |||
| 432 | * | |||
| 433 | * If %KA_PROP_EVENT_ID is not defined the sound file passed in the | |||
| 434 | * %KA_PROP_MEDIA_FILENAME is played. | |||
| 435 | * | |||
| 436 | * On Linux/Unix the right sound to play is determined according to | |||
| 437 | * %KA_PROP_EVENT_ID, | |||
| 438 | * %KA_PROP_APPLICATION_LANGUAGE/%KA_PROP_MEDIA_LANGUAGE, the system | |||
| 439 | * locale, %KA_PROP_KANBERRA_XDG_THEME_NAME and | |||
| 440 | * %KA_PROP_KANBERRA_XDG_THEME_OUTPUT_PROFILE, following the XDG Sound | |||
| 441 | * Theming Specification. On non-Unix systems the native event sound | |||
| 442 | * that matches the XDG sound name in %KA_PROP_EVENT_ID is played. | |||
| 443 | * | |||
| 444 | * Returns: 0 on success, negative error code on error. | |||
| 445 | */ | |||
| 446 | ||||
| 447 | int ka_context_play(ka_context *c, uint32_t id, ...) { | |||
| 448 | int ret; | |||
| 449 | va_list ap; | |||
| 450 | ka_proplist *p = NULL((void*)0); | |||
| 451 | ||||
| 452 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 452, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 453 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 453, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 454 | ||||
| 455 | va_start(ap, id)__builtin_va_start(ap, id); | |||
| 456 | ret = ka_proplist_from_ap(&p, ap); | |||
| 457 | va_end(ap)__builtin_va_end(ap); | |||
| 458 | ||||
| 459 | if (ret < 0) | |||
| 460 | return ret; | |||
| 461 | ||||
| 462 | ret = ka_context_play_full(c, id, p, NULL((void*)0), NULL((void*)0)); | |||
| 463 | ||||
| 464 | ka_assert_se(ka_proplist_destroy(p) == 0)do { if ((__builtin_expect((!(ka_proplist_destroy(p) == 0)),0 ))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "ka_proplist_destroy(p) == 0" , "common.c", 464, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); | |||
| 465 | ||||
| 466 | return ret; | |||
| 467 | } | |||
| 468 | ||||
| 469 | /** | |||
| 470 | * ka_context_play_full: | |||
| 471 | * @c: the context to play the event sound on | |||
| 472 | * @id: an integer id this sound can be later be identified with when calling ka_context_cancel() or when the callback is called. | |||
| 473 | * @p: A property list of properties for this event sound | |||
| 474 | * @cb: A callback to call when this sound event sucessfully finished playing or when an error occured during playback. | |||
| 475 | * | |||
| 476 | * Play one event sound, and call the specified callback function when | |||
| 477 | * completed. See ka_finish_callback_t for the semantics the callback | |||
| 478 | * is called in. Also see ka_context_play(). | |||
| 479 | * | |||
| 480 | * It is guaranteed that the callback is called exactly once if | |||
| 481 | * ka_context_play_full() returns KA_SUCCESS. You thus may safely pass | |||
| 482 | * allocated memory to the callback and assume that it is freed | |||
| 483 | * properly. | |||
| 484 | * | |||
| 485 | * Returns: 0 on success, negative error code on error. | |||
| 486 | */ | |||
| 487 | ||||
| 488 | int ka_context_play_full(ka_context *c, uint32_t id, ka_proplist *p, ka_finish_callback_t cb, void *userdata) { | |||
| 489 | int ret; | |||
| 490 | const char *t; | |||
| 491 | ka_bool_t enabled = TRUE(!(0)); | |||
| 492 | ||||
| 493 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 493, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 494 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 494, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 495 | ka_return_val_if_fail(p, KA_ERROR_INVALID)do { if ((__builtin_expect((!(p)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "p" , "common.c", 495, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 496 | ka_return_val_if_fail(!userdata || cb, KA_ERROR_INVALID)do { if ((__builtin_expect((!(!userdata || cb)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!userdata || cb" , "common.c", 496, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); | |||
| 497 | ||||
| 498 | ka_mutex_lock(c->mutex); | |||
| 499 | ||||
| 500 | ka_return_val_if_fail_unlock(ka_proplist_contains(p, KA_PROP_EVENT_ID) ||do { if ((__builtin_expect((!(ka_proplist_contains(p, "event.id" ) || ka_proplist_contains(c->props, "event.id") || ka_proplist_contains (p, "media.filename") || ka_proplist_contains(c->props, "media.filename" ))),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "ka_proplist_contains(p, KA_PROP_EVENT_ID) || ka_proplist_contains(c->props, KA_PROP_EVENT_ID) || ka_proplist_contains(p, KA_PROP_MEDIA_FILENAME) || ka_proplist_contains(c->props, KA_PROP_MEDIA_FILENAME)" , "common.c", 503, __PRETTY_FUNCTION__); ka_mutex_unlock(c-> mutex); return (KA_ERROR_INVALID); } } while((0)) | |||
| 501 | ka_proplist_contains(c->props, KA_PROP_EVENT_ID) ||do { if ((__builtin_expect((!(ka_proplist_contains(p, "event.id" ) || ka_proplist_contains(c->props, "event.id") || ka_proplist_contains (p, "media.filename") || ka_proplist_contains(c->props, "media.filename" ))),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "ka_proplist_contains(p, KA_PROP_EVENT_ID) || ka_proplist_contains(c->props, KA_PROP_EVENT_ID) || ka_proplist_contains(p, KA_PROP_MEDIA_FILENAME) || ka_proplist_contains(c->props, KA_PROP_MEDIA_FILENAME)" , "common.c", 503, __PRETTY_FUNCTION__); ka_mutex_unlock(c-> mutex); return (KA_ERROR_INVALID); } } while((0)) | |||
| 502 | ka_proplist_contains(p, KA_PROP_MEDIA_FILENAME) ||do { if ((__builtin_expect((!(ka_proplist_contains(p, "event.id" ) || ka_proplist_contains(c->props, "event.id") || ka_proplist_contains (p, "media.filename") || ka_proplist_contains(c->props, "media.filename" ))),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "ka_proplist_contains(p, KA_PROP_EVENT_ID) || ka_proplist_contains(c->props, KA_PROP_EVENT_ID) || ka_proplist_contains(p, KA_PROP_MEDIA_FILENAME) || ka_proplist_contains(c->props, KA_PROP_MEDIA_FILENAME)" , "common.c", 503, __PRETTY_FUNCTION__); ka_mutex_unlock(c-> mutex); return (KA_ERROR_INVALID); } } while((0)) | |||
| 503 | ka_proplist_contains(c->props, KA_PROP_MEDIA_FILENAME), KA_ERROR_INVALID, c->mutex)do { if ((__builtin_expect((!(ka_proplist_contains(p, "event.id" ) || ka_proplist_contains(c->props, "event.id") || ka_proplist_contains (p, "media.filename") || ka_proplist_contains(c->props, "media.filename" ))),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "ka_proplist_contains(p, KA_PROP_EVENT_ID) || ka_proplist_contains(c->props, KA_PROP_EVENT_ID) || ka_proplist_contains(p, KA_PROP_MEDIA_FILENAME) || ka_proplist_contains(c->props, KA_PROP_MEDIA_FILENAME)" , "common.c", 503, __PRETTY_FUNCTION__); ka_mutex_unlock(c-> mutex); return (KA_ERROR_INVALID); } } while((0)); | |||
| 504 | ||||
| 505 | ka_mutex_lock(c->props->mutex); | |||
| 506 | if ((t = ka_proplist_gets_unlocked(c->props, KA_PROP_KANBERRA_ENABLE"kanberra.enable"))) | |||
| 507 | enabled = !ka_streq(t, "0")(strcmp((t),("0")) == 0); | |||
| 508 | ka_mutex_unlock(c->props->mutex); | |||
| 509 | ||||
| 510 | ka_mutex_lock(p->mutex); | |||
| 511 | if ((t = ka_proplist_gets_unlocked(p, KA_PROP_KANBERRA_ENABLE"kanberra.enable"))) | |||
| 512 | enabled = !ka_streq(t, "0")(strcmp((t),("0")) == 0); | |||
| 513 | ka_mutex_unlock(p->mutex); | |||
| 514 | ||||
| 515 | ka_return_val_if_fail_unlock(enabled, KA_ERROR_DISABLED, c->mutex)do { if ((__builtin_expect((!(enabled)),0))) { if (ka_debug() ) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "enabled" , "common.c", 515, __PRETTY_FUNCTION__); ka_mutex_unlock (c->mutex); return (KA_ERROR_DISABLED); } } while((0)); | |||
| 516 | ||||
| 517 | if ((ret = context_open_unlocked(c)) < 0) | |||
| 518 | goto finish; | |||
| 519 | ||||
| 520 | ka_assert(c->opened)do { if ((__builtin_expect((!(c->opened)),0))) { fprintf(stderr , "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "c->opened" , "common.c", 520, __PRETTY_FUNCTION__); abort (); } } while ((0)); | |||
| 521 | ||||
| 522 | ret = driver_play(c, id, p, cb, userdata); | |||
| 523 | ||||
| 524 | finish: | |||
| 525 | ||||
| 526 | ka_mutex_unlock(c->mutex); | |||
| 527 | ||||
| 528 | return ret; | |||
| 529 | } | |||
| 530 | ||||
| 531 | /** | |||
| 532 | * | |||
| 533 | * ka_context_cancel: | |||
| 534 | * @c: the context to cancel the sounds on | |||
| 535 | * @id: the id that identify the sounds to cancel. | |||
| 536 | * | |||
| 537 | * Cancel one or more event sounds that have been started via | |||
| 538 | * ka_context_play(). If the sound was started with | |||
| 539 | * ka_context_play_full() and a callback function was passed this | |||
| 540 | * might cause this function to be called with %KA_ERROR_CANCELED as | |||
| 541 | * error code. | |||
| 542 | * | |||
| 543 | * Returns: 0 on success, negative error code on error. | |||
| 544 | */ | |||
| 545 | int ka_context_cancel(ka_context *c, uint32_t id) { | |||
| 546 | int ret; | |||
| 547 | ||||
| 548 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 548, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 549 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 549, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 550 | ka_mutex_lock(c->mutex); | |||
| 551 | ka_return_val_if_fail_unlock(c->opened, KA_ERROR_STATE, c->mutex)do { if ((__builtin_expect((!(c->opened)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "c->opened" , "common.c", 551, __PRETTY_FUNCTION__); ka_mutex_unlock (c->mutex); return (KA_ERROR_STATE); } } while((0)); | |||
| 552 | ||||
| 553 | ret = driver_cancel(c, id); | |||
| 554 | ||||
| 555 | ka_mutex_unlock(c->mutex); | |||
| 556 | ||||
| 557 | return ret; | |||
| 558 | } | |||
| 559 | ||||
| 560 | /** | |||
| 561 | * ka_context_cache: | |||
| 562 | * @c: The context to use for uploading. | |||
| 563 | * @...: The properties for this event sound. Terminated with NULL. | |||
| 564 | * | |||
| 565 | * Upload the specified sample into the audio server and attach the | |||
| 566 | * specified properties to it. This function will only return after | |||
| 567 | * the sample upload was finished. | |||
| 568 | * | |||
| 569 | * The sound to cache is found with the same algorithm that is used to | |||
| 570 | * find the sounds for ka_context_play(). | |||
| 571 | * | |||
| 572 | * If the backend doesn't support caching sound samples this function | |||
| 573 | * will return %KA_ERROR_NOTSUPPORTED. | |||
| 574 | * | |||
| 575 | * Returns: 0 on success, negative error code on error. | |||
| 576 | */ | |||
| 577 | ||||
| 578 | int ka_context_cache(ka_context *c, ...) { | |||
| 579 | int ret; | |||
| 580 | va_list ap; | |||
| 581 | ka_proplist *p = NULL((void*)0); | |||
| 582 | ||||
| 583 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 583, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 584 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 584, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 585 | ||||
| 586 | va_start(ap, c)__builtin_va_start(ap, c); | |||
| 587 | ret = ka_proplist_from_ap(&p, ap); | |||
| 588 | va_end(ap)__builtin_va_end(ap); | |||
| 589 | ||||
| 590 | if (ret < 0) | |||
| 591 | return ret; | |||
| 592 | ||||
| 593 | ret = ka_context_cache_full(c, p); | |||
| 594 | ||||
| 595 | ka_assert_se(ka_proplist_destroy(p) == 0)do { if ((__builtin_expect((!(ka_proplist_destroy(p) == 0)),0 ))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "ka_proplist_destroy(p) == 0" , "common.c", 595, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); | |||
| 596 | ||||
| 597 | return ret; | |||
| 598 | } | |||
| 599 | ||||
| 600 | /** | |||
| 601 | * ka_context_cache_full: | |||
| 602 | * @c: The context to use for uploading. | |||
| 603 | * @p: The property list for this event sound. | |||
| 604 | * | |||
| 605 | * Upload the specified sample into the server and attach the | |||
| 606 | * specified properties to it. Similar to ka_context_cache() but takes | |||
| 607 | * a ka_proplist instead of a variable number of arguments. | |||
| 608 | * | |||
| 609 | * If the backend doesn't support caching sound samples this function | |||
| 610 | * will return KA_ERROR_NOTSUPPORTED. | |||
| 611 | * | |||
| 612 | * Returns: 0 on success, negative error code on error. | |||
| 613 | */ | |||
| 614 | int ka_context_cache_full(ka_context *c, ka_proplist *p) { | |||
| 615 | int ret; | |||
| 616 | ||||
| 617 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 617, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 618 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 618, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 619 | ka_return_val_if_fail(p, KA_ERROR_INVALID)do { if ((__builtin_expect((!(p)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "p" , "common.c", 619, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 620 | ||||
| 621 | ka_mutex_lock(c->mutex); | |||
| 622 | ||||
| 623 | ka_return_val_if_fail_unlock(ka_proplist_contains(p, KA_PROP_EVENT_ID) ||do { if ((__builtin_expect((!(ka_proplist_contains(p, "event.id" ) || ka_proplist_contains(c->props, "event.id"))),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "ka_proplist_contains(p, KA_PROP_EVENT_ID) || ka_proplist_contains(c->props, KA_PROP_EVENT_ID)" , "common.c", 624, __PRETTY_FUNCTION__); ka_mutex_unlock(c-> mutex); return (KA_ERROR_INVALID); } } while((0)) | |||
| 624 | ka_proplist_contains(c->props, KA_PROP_EVENT_ID), KA_ERROR_INVALID, c->mutex)do { if ((__builtin_expect((!(ka_proplist_contains(p, "event.id" ) || ka_proplist_contains(c->props, "event.id"))),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "ka_proplist_contains(p, KA_PROP_EVENT_ID) || ka_proplist_contains(c->props, KA_PROP_EVENT_ID)" , "common.c", 624, __PRETTY_FUNCTION__); ka_mutex_unlock(c-> mutex); return (KA_ERROR_INVALID); } } while((0)); | |||
| 625 | ||||
| 626 | if ((ret = context_open_unlocked(c)) < 0) | |||
| 627 | goto finish; | |||
| 628 | ||||
| 629 | ka_assert(c->opened)do { if ((__builtin_expect((!(c->opened)),0))) { fprintf(stderr , "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "c->opened" , "common.c", 629, __PRETTY_FUNCTION__); abort (); } } while ((0)); | |||
| 630 | ||||
| 631 | ret = driver_cache(c, p); | |||
| 632 | ||||
| 633 | finish: | |||
| 634 | ||||
| 635 | ka_mutex_unlock(c->mutex); | |||
| 636 | ||||
| 637 | return ret; | |||
| 638 | } | |||
| 639 | ||||
| 640 | /** | |||
| 641 | * ka_strerror: | |||
| 642 | * @code: Numerical error code as returned by a libkanberra API function | |||
| 643 | * | |||
| 644 | * Converts a numerical error code as returned by most libkanberra API functions into a human readable error string. | |||
| 645 | * | |||
| 646 | * Returns: a human readable error string. | |||
| 647 | */ | |||
| 648 | const char *ka_strerror(int code) { | |||
| 649 | ||||
| 650 | const char * const error_table[-_KA_ERROR_MAX] = { | |||
| 651 | [-KA_SUCCESS] = "Success", | |||
| 652 | [-KA_ERROR_NOTSUPPORTED] = "Operation not supported", | |||
| 653 | [-KA_ERROR_INVALID] = "Invalid argument", | |||
| 654 | [-KA_ERROR_STATE] = "Invalid state", | |||
| 655 | [-KA_ERROR_OOM] = "Out of memory", | |||
| 656 | [-KA_ERROR_NODRIVER] = "No such driver", | |||
| 657 | [-KA_ERROR_SYSTEM] = "System error", | |||
| 658 | [-KA_ERROR_CORRUPT] = "File or data corrupt", | |||
| 659 | [-KA_ERROR_TOOBIG] = "File or data too large", | |||
| 660 | [-KA_ERROR_NOTFOUND] = "File or data not found", | |||
| 661 | [-KA_ERROR_DESTROYED] = "Destroyed", | |||
| 662 | [-KA_ERROR_CANCELED] = "Canceled", | |||
| 663 | [-KA_ERROR_NOTAVAILABLE] = "Not available", | |||
| 664 | [-KA_ERROR_ACCESS] = "Access forbidden", | |||
| 665 | [-KA_ERROR_IO] = "IO error", | |||
| 666 | [-KA_ERROR_INTERNAL] = "Internal error", | |||
| 667 | [-KA_ERROR_DISABLED] = "Sound disabled", | |||
| 668 | [-KA_ERROR_FORKED] = "Process forked", | |||
| 669 | [-KA_ERROR_DISCONNECTED] = "Disconnected" | |||
| 670 | }; | |||
| 671 | ||||
| 672 | ka_return_val_if_fail(code <= 0, NULL)do { if ((__builtin_expect((!(code <= 0)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "code <= 0" , "common.c", 672, __PRETTY_FUNCTION__); return (((void*)0)); } } while((0)); | |||
| 673 | ka_return_val_if_fail(code > _KA_ERROR_MAX, NULL)do { if ((__builtin_expect((!(code > _KA_ERROR_MAX)),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "code > _KA_ERROR_MAX" , "common.c", 673, __PRETTY_FUNCTION__ ); return (((void*)0)); } } while((0)); | |||
| 674 | ||||
| 675 | return error_table[-code]; | |||
| 676 | } | |||
| 677 | ||||
| 678 | /* Not exported */ | |||
| 679 | int ka_parse_cache_control(ka_cache_control_t *control, const char *c) { | |||
| 680 | ka_return_val_if_fail(control, KA_ERROR_INVALID)do { if ((__builtin_expect((!(control)),0))) { if (ka_debug() ) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "control" , "common.c", 680, __PRETTY_FUNCTION__); return ( KA_ERROR_INVALID); } } while((0)); | |||
| 681 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 681, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 682 | ||||
| 683 | if (ka_streq(c, "never")(strcmp((c),("never")) == 0)) | |||
| 684 | *control = KA_CACHE_CONTROL_NEVER; | |||
| 685 | else if (ka_streq(c, "permanent")(strcmp((c),("permanent")) == 0)) | |||
| 686 | *control = KA_CACHE_CONTROL_PERMANENT; | |||
| 687 | else if (ka_streq(c, "volatile")(strcmp((c),("volatile")) == 0)) | |||
| 688 | *control = KA_CACHE_CONTROL_VOLATILE; | |||
| 689 | else | |||
| 690 | return KA_ERROR_INVALID; | |||
| 691 | ||||
| 692 | return KA_SUCCESS; | |||
| 693 | } | |||
| 694 | ||||
| 695 | /** | |||
| 696 | * ka_context_playing: | |||
| 697 | * @c: the context to check if sound is still playing | |||
| 698 | * @id: the id that identify the sounds to check | |||
| 699 | * @playing: a pointer to a boolean that will be updated with the play status | |||
| 700 | * | |||
| 701 | * Check if at least one sound with the specified id is still | |||
| 702 | * playing. Returns 0 in *playing if no sound with this id is playing | |||
| 703 | * anymore or non-zero if there is at least one playing. | |||
| 704 | * | |||
| 705 | * Returns: 0 on success, negative error code on error. | |||
| 706 | * Since: 0.16 | |||
| 707 | */ | |||
| 708 | int ka_context_playing(ka_context *c, uint32_t id, int *playing) { | |||
| 709 | int ret; | |||
| 710 | ||||
| 711 | ka_return_val_if_fail(!ka_detect_fork(), KA_ERROR_FORKED)do { if ((__builtin_expect((!(!ka_detect_fork())),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!ka_detect_fork()" , "common.c", 711, __PRETTY_FUNCTION__) ; return (KA_ERROR_FORKED); } } while((0)); | |||
| 712 | ka_return_val_if_fail(c, KA_ERROR_INVALID)do { if ((__builtin_expect((!(c)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "c" , "common.c", 712, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); | |||
| 713 | ka_return_val_if_fail(playing, KA_ERROR_INVALID)do { if ((__builtin_expect((!(playing)),0))) { if (ka_debug() ) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "playing" , "common.c", 713, __PRETTY_FUNCTION__); return ( KA_ERROR_INVALID); } } while((0)); | |||
| 714 | ka_mutex_lock(c->mutex); | |||
| 715 | ka_return_val_if_fail_unlock(c->opened, KA_ERROR_STATE, c->mutex)do { if ((__builtin_expect((!(c->opened)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "c->opened" , "common.c", 715, __PRETTY_FUNCTION__); ka_mutex_unlock (c->mutex); return (KA_ERROR_STATE); } } while((0)); | |||
| 716 | ||||
| 717 | ret = driver_playing(c, id, playing); | |||
| 718 | ||||
| 719 | ka_mutex_unlock(c->mutex); | |||
| 720 | ||||
| 721 | return ret; | |||
| 722 | } |