File: | alsa.c |
Warning: | line 306, column 21 the computation of the size of the memory allocation may overflow |
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 <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 | |
42 | struct private; |
43 | |
44 | struct 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 | |
56 | struct 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 | |
67 | static 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 | |
85 | int 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 | |
110 | int 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 | |
169 | int 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 | |
178 | int 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 | |
186 | int 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 | |
193 | static 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 | |
217 | static 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 | |
228 | static 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 | |
271 | finish: |
272 | |
273 | return translate_error(ret); |
274 | } |
275 | |
276 | #define BUFSIZE(16*1024) (16*1024) |
277 | |
278 | static 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 | |
406 | finish: |
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 | |
429 | int 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 | |
481 | finish: |
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 | |
490 | int 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 | |
526 | int 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 | } |