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