Bug Summary

File:alsa.c
Warning:line 306, column 21
the computation of the size of the memory allocation may overflow

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name alsa.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -D driver_open=alsa_driver_open -D driver_destroy=alsa_driver_destroy -D driver_change_device=alsa_driver_change_device -D driver_change_props=alsa_driver_change_props -D driver_play=alsa_driver_play -D driver_cancel=alsa_driver_cancel -D driver_cache=alsa_driver_cache -D PIC -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-04-17-150046-19626-1 -x c alsa.c
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 <errno(*__errno_location ()).h>
28#include <stdlib.h>
29#include <pthread.h>
30#include <semaphore.h>
31
32#include <alsa/asoundlib.h>
33
34#include "kanberra.h"
35#include "common.h"
36#include "driver.h"
37#include "llist.h"
38#include "read-sound-file.h"
39#include "sound-theme-spec.h"
40#include "malloc.h"
41
42struct private;
43
44struct outstanding {
45 KA_LLIST_FIELDS(struct outstanding)struct outstanding *next, *prev;
46 ka_bool_t dead;
47 uint32_t id;
48 ka_finish_callback_t callback;
49 void *userdata;
50 ka_sound_file *file;
51 snd_pcm_t *pcm;
52 int pipe_fd[2];
53 ka_context *context;
54};
55
56struct private {
57 ka_theme_data *theme;
58 ka_mutex *outstanding_mutex;
59 ka_bool_t signal_semaphore;
60 sem_t semaphore;
61 ka_bool_t semaphore_allocated;
62 KA_LLIST_HEAD(struct outstanding, outstanding)struct outstanding *outstanding;
63};
64
65#define PRIVATE(c)((struct private *) ((c)->private)) ((struct private *) ((c)->private))
66
67static void outstanding_free(struct outstanding *o) {
68 ka_assert(o)do { if ((__builtin_expect((!(o)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "o" , "alsa.c", 68, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
69
70 if (o->pipe_fd[1] >= 0)
71 close(o->pipe_fd[1]);
72
73 if (o->pipe_fd[0] >= 0)
74 close(o->pipe_fd[0]);
75
76 if (o->file)
77 ka_sound_file_close(o->file);
78
79 if (o->pcm)
80 snd_pcm_close(o->pcm);
81
82 ka_freefree(o);
83}
84
85int driver_openalsa_driver_open(ka_context *c) {
86 struct private *p;
87
88 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"
, "alsa.c", 88, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
89 ka_return_val_if_fail(!c->driver || ka_streq(c->driver, "alsa"), KA_ERROR_NODRIVER)do { if ((__builtin_expect((!(!c->driver || (strcmp((c->
driver),("alsa")) == 0))),0))) { if (ka_debug()) fprintf(stderr
, "Assertion '%s' failed at %s:%u, function %s().\n", "!c->driver || ka_streq(c->driver, \"alsa\")"
, "alsa.c", 89, __PRETTY_FUNCTION__); return (KA_ERROR_NODRIVER
); } } while((0))
;
90 ka_return_val_if_fail(!PRIVATE(c), KA_ERROR_STATE)do { if ((__builtin_expect((!(!((struct private *) ((c)->private
)))),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "!PRIVATE(c)" , "alsa.c", 90, __PRETTY_FUNCTION__); return (
KA_ERROR_STATE); } } while((0))
;
91
92 if (!(c->private = p = ka_new0(struct private, 1)((struct private*) calloc(1, (sizeof(struct private)*(1))))))
93 return KA_ERROR_OOM;
94
95 if (!(p->outstanding_mutex = ka_mutex_new())) {
96 driver_destroyalsa_driver_destroy(c);
97 return KA_ERROR_OOM;
98 }
99
100 if (sem_init(&p->semaphore, 0, 0) < 0) {
101 driver_destroyalsa_driver_destroy(c);
102 return KA_ERROR_OOM;
103 }
104
105 p->semaphore_allocated = TRUE(!(0));
106
107 return KA_SUCCESS;
108}
109
110int driver_destroyalsa_driver_destroy(ka_context *c) {
111 struct private *p;
112 struct outstanding *out;
113
114 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"
, "alsa.c", 114, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
115 ka_return_val_if_fail(c->private, KA_ERROR_STATE)do { if ((__builtin_expect((!(c->private)),0))) { if (ka_debug
()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "c->private" , "alsa.c", 115, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
116
117 p = PRIVATE(c)((struct private *) ((c)->private));
118
119 if (p->outstanding_mutex) {
120 ka_mutex_lock(p->outstanding_mutex);
121
122 /* Tell all player threads to terminate */
123 for (out = p->outstanding; out; out = out->next) {
124
125 if (out->dead)
126 continue;
127
128 out->dead = TRUE(!(0));
129
130 if (out->callback)
131 out->callback(c, out->id, KA_ERROR_DESTROYED, out->userdata);
132
133 /* This will cause the thread to wakeup and terminate */
134 if (out->pipe_fd[1] >= 0) {
135 close(out->pipe_fd[1]);
136 out->pipe_fd[1] = -1;
137 }
138 }
139
140 if (p->semaphore_allocated) {
141 /* Now wait until all players are destroyed */
142 p->signal_semaphore = TRUE(!(0));
143 while (p->outstanding) {
144 ka_mutex_unlock(p->outstanding_mutex);
145 sem_wait(&p->semaphore);
146 ka_mutex_lock(p->outstanding_mutex);
147 }
148 }
149
150 ka_mutex_unlock(p->outstanding_mutex);
151 ka_mutex_free(p->outstanding_mutex);
152 }
153
154 if (p->theme)
155 ka_theme_data_free(p->theme);
156
157 if (p->semaphore_allocated)
158 sem_destroy(&p->semaphore);
159
160 ka_freefree(p);
161
162 c->private = NULL((void*)0);
163
164 snd_config_update_free_global();
165
166 return KA_SUCCESS;
167}
168
169int driver_change_devicealsa_driver_change_device (ka_context *c,
170 const char *device GNUC_UNUSED__attribute__ ((__unused__)))
171{
172 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"
, "alsa.c", 172, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
173 ka_return_val_if_fail(c->private, KA_ERROR_STATE)do { if ((__builtin_expect((!(c->private)),0))) { if (ka_debug
()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "c->private" , "alsa.c", 173, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
174
175 return KA_SUCCESS;
176}
177
178int driver_change_propsalsa_driver_change_props(ka_context *c, ka_proplist *changed, ka_proplist *merged) {
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"
, "alsa.c", 179, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
180 ka_return_val_if_fail(changed, KA_ERROR_INVALID)do { if ((__builtin_expect((!(changed)),0))) { if (ka_debug()
) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "changed" , "alsa.c", 180, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
181 ka_return_val_if_fail(merged, KA_ERROR_INVALID)do { if ((__builtin_expect((!(merged)),0))) { if (ka_debug())
fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "merged" , "alsa.c", 181, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
182
183 return KA_SUCCESS;
184}
185
186int driver_cachealsa_driver_cache(ka_context *c, ka_proplist *proplist) {
187 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"
, "alsa.c", 187, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
188 ka_return_val_if_fail(proplist, KA_ERROR_INVALID)do { if ((__builtin_expect((!(proplist)),0))) { if (ka_debug(
)) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "proplist" , "alsa.c", 188, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
189
190 return KA_ERROR_NOTSUPPORTED;
191}
192
193static int translate_error(int error) {
194
195 switch (error) {
196 case -ENODEV19:
197 case -ENOENT2:
198 return KA_ERROR_NOTFOUND;
199 case -EACCES13:
200 case -EPERM1:
201 return KA_ERROR_ACCESS;
202 case -ENOMEM12:
203 return KA_ERROR_OOM;
204 case -EBUSY16:
205 return KA_ERROR_NOTAVAILABLE;
206 case -EINVAL22:
207 return KA_ERROR_INVALID;
208 case -ENOSYS38:
209 return KA_ERROR_NOTSUPPORTED;
210 default:
211 if (ka_debug())
212 fprintf(stderrstderr, "Got unhandled error from ALSA: %s\n", snd_strerror(error));
213 return KA_ERROR_IO;
214 }
215}
216
217static const snd_pcm_format_t sample_type_table[] = {
218#ifdef WORDS_BIGENDIAN
219 [KA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_BE,
220 [KA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_LE,
221#else
222 [KA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_LE,
223 [KA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_BE,
224#endif
225 [KA_SAMPLE_U8] = SND_PCM_FORMAT_U8
226};
227
228static int open_alsa(ka_context *c, struct outstanding *out) {
229 int ret;
230 snd_pcm_hw_params_t *hwparams;
231 unsigned rate;
232
233 snd_pcm_hw_params_alloca(&hwparams)do { *&hwparams = (snd_pcm_hw_params_t *) __builtin_alloca
(snd_pcm_hw_params_sizeof()); memset(*&hwparams, 0, snd_pcm_hw_params_sizeof
()); } while (0)
;
234
235 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"
, "alsa.c", 235, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
236 ka_return_val_if_fail(c->private, KA_ERROR_STATE)do { if ((__builtin_expect((!(c->private)),0))) { if (ka_debug
()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "c->private" , "alsa.c", 236, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
237 ka_return_val_if_fail(out, KA_ERROR_INVALID)do { if ((__builtin_expect((!(out)),0))) { if (ka_debug()) fprintf
(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "out"
, "alsa.c", 237, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
238
239 /* In ALSA we need to open different devices for doing
240 * multichannel audio. This cnnot be done in a backend-independant
241 * wa, hence we limit ourselves to mono/stereo only. */
242 ka_return_val_if_fail(ka_sound_file_get_nchannels(out->file) <= 2, KA_ERROR_NOTSUPPORTED)do { if ((__builtin_expect((!(ka_sound_file_get_nchannels(out
->file) <= 2)),0))) { if (ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "ka_sound_file_get_nchannels(out->file) <= 2" , "alsa.c"
, 242, __PRETTY_FUNCTION__); return (KA_ERROR_NOTSUPPORTED); }
} while((0))
;
243
244 if ((ret = snd_pcm_open(&out->pcm, c->device ? c->device : "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
245 goto finish;
246
247 if ((ret = snd_pcm_hw_params_any(out->pcm, hwparams)) < 0)
248 goto finish;
249
250 if ((ret = snd_pcm_hw_params_set_access(out->pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
251 goto finish;
252
253 if ((ret = snd_pcm_hw_params_set_format(out->pcm, hwparams, sample_type_table[ka_sound_file_get_sample_type(out->file)])) < 0)
254 goto finish;
255
256 rate = ka_sound_file_get_rate(out->file);
257 if ((ret = snd_pcm_hw_params_set_rate_near(out->pcm, hwparams, &rate, 0)) < 0)
258 goto finish;
259
260 if ((ret = snd_pcm_hw_params_set_channels(out->pcm, hwparams, ka_sound_file_get_nchannels(out->file))) < 0)
261 goto finish;
262
263 if ((ret = snd_pcm_hw_params(out->pcm, hwparams)) < 0)
264 goto finish;
265
266 if ((ret = snd_pcm_prepare(out->pcm)) < 0)
267 goto finish;
268
269 return KA_SUCCESS;
270
271finish:
272
273 return translate_error(ret);
274}
275
276#define BUFSIZE(16*1024) (16*1024)
277
278static void* thread_func(void *userdata) {
279 struct outstanding *out = userdata;
280 int ret;
281 void *data, *d = NULL((void*)0);
282 size_t fs, data_size;
283 size_t nbytes = 0;
284 struct pollfd *pfd = NULL((void*)0);
285 nfds_t n_pfd;
286 struct private *p;
287
288 p = PRIVATE(out->context)((struct private *) ((out->context)->private));
289
290 pthread_detach(pthread_self());
291
292 fs = ka_sound_file_frame_size(out->file);
293 data_size = (BUFSIZE(16*1024)/fs)*fs;
294
295 if (!(data = ka_mallocmalloc(data_size))) {
296 ret = KA_ERROR_OOM;
297 goto finish;
298 }
299
300 if ((ret = snd_pcm_poll_descriptors_count(out->pcm)) < 0) {
301 ret = translate_error(ret);
302 goto finish;
303 }
304
305 n_pfd = (nfds_t) ret + 1;
306 if (!(pfd = ka_new(struct pollfd, n_pfd)((struct pollfd*) malloc(sizeof(struct pollfd)*(n_pfd))))) {
the computation of the size of the memory allocation may overflow
307 ret = KA_ERROR_OOM;
308 goto finish;
309 }
310
311 if ((ret = snd_pcm_poll_descriptors(out->pcm, pfd+1, (unsigned) n_pfd-1)) < 0) {
312 ret = translate_error(ret);
313 goto finish;
314 }
315
316 pfd[0].fd = out->pipe_fd[0];
317 pfd[0].events = POLLIN0x001;
318 pfd[0].revents = 0;
319
320 for (;;) {
321 unsigned short revents;
322 snd_pcm_sframes_t sframes;
323
324 if (out->dead)
325 break;
326
327 if (poll(pfd, n_pfd, -1) < 0) {
328 ret = KA_ERROR_SYSTEM;
329 goto finish;
330 }
331
332 /* We have been asked to shut down */
333 if (pfd[0].revents)
334 break;
335
336 if ((ret = snd_pcm_poll_descriptors_revents(out->pcm, pfd+1, (unsigned) n_pfd-1, &revents)) < 0) {
337 ret = translate_error(ret);
338 goto finish;
339 }
340
341 if (revents != POLLOUT0x004) {
342
343 switch (snd_pcm_state(out->pcm)) {
344
345 case SND_PCM_STATE_XRUN:
346
347 if ((ret = snd_pcm_recover(out->pcm, -EPIPE32, 1)) != 0) {
348 ret = translate_error(ret);
349 goto finish;
350 }
351 break;
352
353 case SND_PCM_STATE_SUSPENDED:
354
355 if ((ret = snd_pcm_recover(out->pcm, -ESTRPIPE86, 1)) != 0) {
356 ret = translate_error(ret);
357 goto finish;
358 }
359 break;
360
361 default:
362
363 snd_pcm_drop(out->pcm);
364
365 if ((ret = snd_pcm_prepare(out->pcm)) < 0) {
366 ret = translate_error(ret);
367 goto finish;
368 }
369 break;
370 }
371
372 continue;
373 }
374
375 if (nbytes <= 0) {
376
377 nbytes = data_size;
378
379 if ((ret = ka_sound_file_read_arbitrary(out->file, data, &nbytes)) < 0)
380 goto finish;
381
382 d = data;
383 }
384
385 if (nbytes <= 0) {
386 snd_pcm_drain(out->pcm);
387 break;
388 }
389
390 if ((sframes = snd_pcm_writei(out->pcm, d, nbytes/fs)) < 0) {
391
392 if ((ret = snd_pcm_recover(out->pcm, (int) sframes, 1)) < 0) {
393 ret = translate_error(ret);
394 goto finish;
395 }
396
397 continue;
398 }
399
400 nbytes -= (size_t) sframes*fs;
401 d = (uint8_t*) d + (size_t) sframes*fs;
402 }
403
404 ret = KA_SUCCESS;
405
406finish:
407
408 ka_freefree(data);
409 ka_freefree(pfd);
410
411 if (!out->dead)
412 if (out->callback)
413 out->callback(out->context, out->id, ret, out->userdata);
414
415 ka_mutex_lock(p->outstanding_mutex);
416
417 KA_LLIST_REMOVE(struct outstanding, p->outstanding, out)do { struct outstanding **_head = &(p->outstanding), *
_item = (out); do { if ((__builtin_expect((!(_item)),0))) { fprintf
(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "_item" , "alsa.c", 417, __PRETTY_FUNCTION__); abort(); } }
while ((0)); if (_item->next) _item->next->prev = _item
->prev; if (_item->prev) _item->prev->next = _item
->next; else { do { if ((__builtin_expect((!(*_head == _item
)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "*_head == _item" , "alsa.c", 417, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
418
419 if (!p->outstanding && p->signal_semaphore)
420 sem_post(&p->semaphore);
421
422 outstanding_free(out);
423
424 ka_mutex_unlock(p->outstanding_mutex);
425
426 return NULL((void*)0);
427}
428
429int driver_playalsa_driver_play(ka_context *c, uint32_t id, ka_proplist *proplist, ka_finish_callback_t cb, void *userdata) {
430 struct private *p;
431 struct outstanding *out = NULL((void*)0);
432 int ret;
433 pthread_t thread;
434
435 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"
, "alsa.c", 435, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
436 ka_return_val_if_fail(proplist, KA_ERROR_INVALID)do { if ((__builtin_expect((!(proplist)),0))) { if (ka_debug(
)) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "proplist" , "alsa.c", 436, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
437 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" , "alsa.c", 437, __PRETTY_FUNCTION__); return
(KA_ERROR_INVALID); } } while((0))
;
438 ka_return_val_if_fail(c->private, KA_ERROR_STATE)do { if ((__builtin_expect((!(c->private)),0))) { if (ka_debug
()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "c->private" , "alsa.c", 438, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
439
440 p = PRIVATE(c)((struct private *) ((c)->private));
441
442 if (!(out = ka_new0(struct outstanding, 1)((struct outstanding*) calloc(1, (sizeof(struct outstanding)*
(1))))
)) {
443 ret = KA_ERROR_OOM;
444 goto finish;
445 }
446
447 out->context = c;
448 out->id = id;
449 out->callback = cb;
450 out->userdata = userdata;
451 out->pipe_fd[0] = out->pipe_fd[1] = -1;
452
453 if (pipe(out->pipe_fd) < 0) {
454 ret = KA_ERROR_SYSTEM;
455 goto finish;
456 }
457
458 if ((ret = ka_lookup_sound(&out->file, NULL((void*)0), &p->theme, c->props, proplist)) < 0)
459 goto finish;
460
461 if ((ret = open_alsa(c, out)) < 0)
462 goto finish;
463
464 /* OK, we're ready to go, so let's add this to our list */
465 ka_mutex_lock(p->outstanding_mutex);
466 KA_LLIST_PREPEND(struct outstanding, p->outstanding, out)do { struct outstanding **_head = &(p->outstanding), *
_item = (out); do { if ((__builtin_expect((!(_item)),0))) { fprintf
(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "_item" , "alsa.c", 466, __PRETTY_FUNCTION__); abort(); } }
while ((0)); if ((_item->next = *_head)) _item->next->
prev = _item; _item->prev = ((void*)0); *_head = _item; } while
(0)
;
467 ka_mutex_unlock(p->outstanding_mutex);
468
469 if (pthread_create(&thread, NULL((void*)0), thread_func, out) < 0) {
470 ret = KA_ERROR_OOM;
471
472 ka_mutex_lock(p->outstanding_mutex);
473 KA_LLIST_REMOVE(struct outstanding, p->outstanding, out)do { struct outstanding **_head = &(p->outstanding), *
_item = (out); do { if ((__builtin_expect((!(_item)),0))) { fprintf
(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "_item" , "alsa.c", 473, __PRETTY_FUNCTION__); abort(); } }
while ((0)); if (_item->next) _item->next->prev = _item
->prev; if (_item->prev) _item->prev->next = _item
->next; else { do { if ((__builtin_expect((!(*_head == _item
)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "*_head == _item" , "alsa.c", 473, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
474 ka_mutex_unlock(p->outstanding_mutex);
475
476 goto finish;
477 }
478
479 ret = KA_SUCCESS;
480
481finish:
482
483 /* We keep the outstanding struct around if we need clean up later to */
484 if (ret != KA_SUCCESS)
485 outstanding_free(out);
486
487 return ret;
488}
489
490int driver_cancelalsa_driver_cancel(ka_context *c, uint32_t id) {
491 struct private *p;
492 struct outstanding *out;
493
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"
, "alsa.c", 494, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
495 ka_return_val_if_fail(c->private, KA_ERROR_STATE)do { if ((__builtin_expect((!(c->private)),0))) { if (ka_debug
()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "c->private" , "alsa.c", 495, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
496
497 p = PRIVATE(c)((struct private *) ((c)->private));
498
499 ka_mutex_lock(p->outstanding_mutex);
500
501 for (out = p->outstanding; out; out = out->next) {
502
503 if (out->id != id)
504 continue;
505
506 if (out->dead)
507 continue;
508
509 out->dead = TRUE(!(0));
510
511 if (out->callback)
512 out->callback(c, out->id, KA_ERROR_CANCELED, out->userdata);
513
514 /* This will cause the thread to wakeup and terminate */
515 if (out->pipe_fd[1] >= 0) {
516 close(out->pipe_fd[1]);
517 out->pipe_fd[1] = -1;
518 }
519 }
520
521 ka_mutex_unlock(p->outstanding_mutex);
522
523 return KA_SUCCESS;
524}
525
526int driver_playing(ka_context *c, uint32_t id, int *playing) {
527 struct private *p;
528 struct outstanding *out;
529
530 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"
, "alsa.c", 530, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
531 ka_return_val_if_fail(c->private, KA_ERROR_STATE)do { if ((__builtin_expect((!(c->private)),0))) { if (ka_debug
()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n"
, "c->private" , "alsa.c", 531, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
532 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" , "alsa.c", 532, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
533
534 p = PRIVATE(c)((struct private *) ((c)->private));
535
536 *playing = 0;
537
538 ka_mutex_lock(p->outstanding_mutex);
539
540 for (out = p->outstanding; out; out = out->next) {
541
542 if (out->dead ||
543 out->id != id)
544 continue;
545
546 *playing = 1;
547 break;
548 }
549
550 ka_mutex_unlock(p->outstanding_mutex);
551
552 return KA_SUCCESS;
553}