File: | alsa.c |
Warning: | line 304, 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, 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 | |
176 | int 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 | |
184 | int 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 | |
191 | static 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 | |
215 | static 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 | |
226 | static 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 | |
269 | finish: |
270 | |
271 | return translate_error(ret); |
272 | } |
273 | |
274 | #define BUFSIZE(16*1024) (16*1024) |
275 | |
276 | static 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 | |
404 | finish: |
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 | |
427 | int 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 | |
479 | finish: |
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 | |
488 | int 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 | |
524 | int 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 | } |