Bug Summary

File:alsa.c
Warning:line 304, 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-store=region -analyzer-opt-analyze-nested-blocks -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 -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -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-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -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.core.SizeofPtr -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/2022-12-24-113535-18449-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, const char *device) {
170 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", 170, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
171 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", 171, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
172
173 return KA_SUCCESS;
174}
175
176int driver_change_propsalsa_driver_change_props(ka_context *c, ka_proplist *changed, ka_proplist *merged) {
177 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", 177, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
178 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", 178, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
179 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", 179, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
180
181 return KA_SUCCESS;
182}
183
184int driver_cachealsa_driver_cache(ka_context *c, ka_proplist *proplist) {
185 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", 185, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
186 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", 186, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
187
188 return KA_ERROR_NOTSUPPORTED;
189}
190
191static int translate_error(int error) {
192
193 switch (error) {
194 case -ENODEV19:
195 case -ENOENT2:
196 return KA_ERROR_NOTFOUND;
197 case -EACCES13:
198 case -EPERM1:
199 return KA_ERROR_ACCESS;
200 case -ENOMEM12:
201 return KA_ERROR_OOM;
202 case -EBUSY16:
203 return KA_ERROR_NOTAVAILABLE;
204 case -EINVAL22:
205 return KA_ERROR_INVALID;
206 case -ENOSYS38:
207 return KA_ERROR_NOTSUPPORTED;
208 default:
209 if (ka_debug())
210 fprintf(stderrstderr, "Got unhandled error from ALSA: %s\n", snd_strerror(error));
211 return KA_ERROR_IO;
212 }
213}
214
215static const snd_pcm_format_t sample_type_table[] = {
216#ifdef WORDS_BIGENDIAN
217 [KA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_BE,
218 [KA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_LE,
219#else
220 [KA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_LE,
221 [KA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_BE,
222#endif
223 [KA_SAMPLE_U8] = SND_PCM_FORMAT_U8
224};
225
226static int open_alsa(ka_context *c, struct outstanding *out) {
227 int ret;
228 snd_pcm_hw_params_t *hwparams;
229 unsigned rate;
230
231 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)
;
232
233 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", 233, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
234 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", 234, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
235 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", 235, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
236
237 /* In ALSA we need to open different devices for doing
238 * multichannel audio. This cnnot be done in a backend-independant
239 * wa, hence we limit ourselves to mono/stereo only. */
240 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"
, 240, __PRETTY_FUNCTION__); return (KA_ERROR_NOTSUPPORTED); }
} while((0))
;
241
242 if ((ret = snd_pcm_open(&out->pcm, c->device ? c->device : "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
243 goto finish;
244
245 if ((ret = snd_pcm_hw_params_any(out->pcm, hwparams)) < 0)
246 goto finish;
247
248 if ((ret = snd_pcm_hw_params_set_access(out->pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
249 goto finish;
250
251 if ((ret = snd_pcm_hw_params_set_format(out->pcm, hwparams, sample_type_table[ka_sound_file_get_sample_type(out->file)])) < 0)
252 goto finish;
253
254 rate = ka_sound_file_get_rate(out->file);
255 if ((ret = snd_pcm_hw_params_set_rate_near(out->pcm, hwparams, &rate, 0)) < 0)
256 goto finish;
257
258 if ((ret = snd_pcm_hw_params_set_channels(out->pcm, hwparams, ka_sound_file_get_nchannels(out->file))) < 0)
259 goto finish;
260
261 if ((ret = snd_pcm_hw_params(out->pcm, hwparams)) < 0)
262 goto finish;
263
264 if ((ret = snd_pcm_prepare(out->pcm)) < 0)
265 goto finish;
266
267 return KA_SUCCESS;
268
269finish:
270
271 return translate_error(ret);
272}
273
274#define BUFSIZE(16*1024) (16*1024)
275
276static void* thread_func(void *userdata) {
277 struct outstanding *out = userdata;
278 int ret;
279 void *data, *d = NULL((void*)0);
280 size_t fs, data_size;
281 size_t nbytes = 0;
282 struct pollfd *pfd = NULL((void*)0);
283 nfds_t n_pfd;
284 struct private *p;
285
286 p = PRIVATE(out->context)((struct private *) ((out->context)->private));
287
288 pthread_detach(pthread_self());
289
290 fs = ka_sound_file_frame_size(out->file);
291 data_size = (BUFSIZE(16*1024)/fs)*fs;
292
293 if (!(data = ka_mallocmalloc(data_size))) {
294 ret = KA_ERROR_OOM;
295 goto finish;
296 }
297
298 if ((ret = snd_pcm_poll_descriptors_count(out->pcm)) < 0) {
299 ret = translate_error(ret);
300 goto finish;
301 }
302
303 n_pfd = (nfds_t) ret + 1;
304 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
305 ret = KA_ERROR_OOM;
306 goto finish;
307 }
308
309 if ((ret = snd_pcm_poll_descriptors(out->pcm, pfd+1, (unsigned) n_pfd-1)) < 0) {
310 ret = translate_error(ret);
311 goto finish;
312 }
313
314 pfd[0].fd = out->pipe_fd[0];
315 pfd[0].events = POLLIN0x001;
316 pfd[0].revents = 0;
317
318 for (;;) {
319 unsigned short revents;
320 snd_pcm_sframes_t sframes;
321
322 if (out->dead)
323 break;
324
325 if (poll(pfd, n_pfd, -1) < 0) {
326 ret = KA_ERROR_SYSTEM;
327 goto finish;
328 }
329
330 /* We have been asked to shut down */
331 if (pfd[0].revents)
332 break;
333
334 if ((ret = snd_pcm_poll_descriptors_revents(out->pcm, pfd+1, (unsigned) n_pfd-1, &revents)) < 0) {
335 ret = translate_error(ret);
336 goto finish;
337 }
338
339 if (revents != POLLOUT0x004) {
340
341 switch (snd_pcm_state(out->pcm)) {
342
343 case SND_PCM_STATE_XRUN:
344
345 if ((ret = snd_pcm_recover(out->pcm, -EPIPE32, 1)) != 0) {
346 ret = translate_error(ret);
347 goto finish;
348 }
349 break;
350
351 case SND_PCM_STATE_SUSPENDED:
352
353 if ((ret = snd_pcm_recover(out->pcm, -ESTRPIPE86, 1)) != 0) {
354 ret = translate_error(ret);
355 goto finish;
356 }
357 break;
358
359 default:
360
361 snd_pcm_drop(out->pcm);
362
363 if ((ret = snd_pcm_prepare(out->pcm)) < 0) {
364 ret = translate_error(ret);
365 goto finish;
366 }
367 break;
368 }
369
370 continue;
371 }
372
373 if (nbytes <= 0) {
374
375 nbytes = data_size;
376
377 if ((ret = ka_sound_file_read_arbitrary(out->file, data, &nbytes)) < 0)
378 goto finish;
379
380 d = data;
381 }
382
383 if (nbytes <= 0) {
384 snd_pcm_drain(out->pcm);
385 break;
386 }
387
388 if ((sframes = snd_pcm_writei(out->pcm, d, nbytes/fs)) < 0) {
389
390 if ((ret = snd_pcm_recover(out->pcm, (int) sframes, 1)) < 0) {
391 ret = translate_error(ret);
392 goto finish;
393 }
394
395 continue;
396 }
397
398 nbytes -= (size_t) sframes*fs;
399 d = (uint8_t*) d + (size_t) sframes*fs;
400 }
401
402 ret = KA_SUCCESS;
403
404finish:
405
406 ka_freefree(data);
407 ka_freefree(pfd);
408
409 if (!out->dead)
410 if (out->callback)
411 out->callback(out->context, out->id, ret, out->userdata);
412
413 ka_mutex_lock(p->outstanding_mutex);
414
415 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", 415, __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", 415, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
416
417 if (!p->outstanding && p->signal_semaphore)
418 sem_post(&p->semaphore);
419
420 outstanding_free(out);
421
422 ka_mutex_unlock(p->outstanding_mutex);
423
424 return NULL((void*)0);
425}
426
427int driver_playalsa_driver_play(ka_context *c, uint32_t id, ka_proplist *proplist, ka_finish_callback_t cb, void *userdata) {
428 struct private *p;
429 struct outstanding *out = NULL((void*)0);
430 int ret;
431 pthread_t thread;
432
433 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", 433, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
434 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", 434, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
435 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", 435, __PRETTY_FUNCTION__); return
(KA_ERROR_INVALID); } } while((0))
;
436 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", 436, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
437
438 p = PRIVATE(c)((struct private *) ((c)->private));
439
440 if (!(out = ka_new0(struct outstanding, 1)((struct outstanding*) calloc(1, (sizeof(struct outstanding)*
(1))))
)) {
441 ret = KA_ERROR_OOM;
442 goto finish;
443 }
444
445 out->context = c;
446 out->id = id;
447 out->callback = cb;
448 out->userdata = userdata;
449 out->pipe_fd[0] = out->pipe_fd[1] = -1;
450
451 if (pipe(out->pipe_fd) < 0) {
452 ret = KA_ERROR_SYSTEM;
453 goto finish;
454 }
455
456 if ((ret = ka_lookup_sound(&out->file, NULL((void*)0), &p->theme, c->props, proplist)) < 0)
457 goto finish;
458
459 if ((ret = open_alsa(c, out)) < 0)
460 goto finish;
461
462 /* OK, we're ready to go, so let's add this to our list */
463 ka_mutex_lock(p->outstanding_mutex);
464 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", 464, __PRETTY_FUNCTION__); abort(); } }
while ((0)); if ((_item->next = *_head)) _item->next->
prev = _item; _item->prev = ((void*)0); *_head = _item; } while
(0)
;
465 ka_mutex_unlock(p->outstanding_mutex);
466
467 if (pthread_create(&thread, NULL((void*)0), thread_func, out) < 0) {
468 ret = KA_ERROR_OOM;
469
470 ka_mutex_lock(p->outstanding_mutex);
471 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", 471, __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", 471, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
472 ka_mutex_unlock(p->outstanding_mutex);
473
474 goto finish;
475 }
476
477 ret = KA_SUCCESS;
478
479finish:
480
481 /* We keep the outstanding struct around if we need clean up later to */
482 if (ret != KA_SUCCESS)
483 outstanding_free(out);
484
485 return ret;
486}
487
488int driver_cancelalsa_driver_cancel(ka_context *c, uint32_t id) {
489 struct private *p;
490 struct outstanding *out;
491
492 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", 492, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
493 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", 493, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
494
495 p = PRIVATE(c)((struct private *) ((c)->private));
496
497 ka_mutex_lock(p->outstanding_mutex);
498
499 for (out = p->outstanding; out; out = out->next) {
500
501 if (out->id != id)
502 continue;
503
504 if (out->dead)
505 continue;
506
507 out->dead = TRUE(!(0));
508
509 if (out->callback)
510 out->callback(c, out->id, KA_ERROR_CANCELED, out->userdata);
511
512 /* This will cause the thread to wakeup and terminate */
513 if (out->pipe_fd[1] >= 0) {
514 close(out->pipe_fd[1]);
515 out->pipe_fd[1] = -1;
516 }
517 }
518
519 ka_mutex_unlock(p->outstanding_mutex);
520
521 return KA_SUCCESS;
522}
523
524int driver_playing(ka_context *c, uint32_t id, int *playing) {
525 struct private *p;
526 struct outstanding *out;
527
528 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", 528, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
529 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", 529, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
530 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", 530, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
531
532 p = PRIVATE(c)((struct private *) ((c)->private));
533
534 *playing = 0;
535
536 ka_mutex_lock(p->outstanding_mutex);
537
538 for (out = p->outstanding; out; out = out->next) {
539
540 if (out->dead ||
541 out->id != id)
542 continue;
543
544 *playing = 1;
545 break;
546 }
547
548 ka_mutex_unlock(p->outstanding_mutex);
549
550 return KA_SUCCESS;
551}