File: | pulse.c |
Warning: | line 1228, column 14 Although the value stored to 'ct' is used in the enclosing expression, the value is never actually read from 'ct' |
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 | /* The locking order needs to be strictly followed! First take the |
28 | * mainloop mutex, only then take outstanding_mutex if you need both! |
29 | * Not the other way round, beacause we might then enter a |
30 | * deadlock! */ |
31 | |
32 | #include <errno(*__errno_location ()).h> |
33 | #include <stdlib.h> |
34 | |
35 | #include <pulse/thread-mainloop.h> |
36 | #include <pulse/context.h> |
37 | #include <pulse/scache.h> |
38 | #include <pulse/subscribe.h> |
39 | #include <pulse/introspect.h> |
40 | |
41 | #include "kanberra.h" |
42 | #include "common.h" |
43 | #include "driver.h" |
44 | #include "llist.h" |
45 | #include "read-sound-file.h" |
46 | #include "sound-theme-spec.h" |
47 | #include "malloc.h" |
48 | |
49 | enum outstanding_type { |
50 | OUTSTANDING_SAMPLE, |
51 | OUTSTANDING_STREAM, |
52 | OUTSTANDING_UPLOAD |
53 | }; |
54 | |
55 | struct outstanding { |
56 | KA_LLIST_FIELDS(struct outstanding)struct outstanding *next, *prev; |
57 | enum outstanding_type type; |
58 | ka_context *context; |
59 | uint32_t id; |
60 | uint32_t sink_input; |
61 | pa_stream *stream; |
62 | pa_operation *drain_operation; |
63 | ka_finish_callback_t callback; |
64 | void *userdata; |
65 | ka_sound_file *file; |
66 | int error; |
67 | unsigned clean_up:1; /* Handler needs to clean up the outstanding struct */ |
68 | unsigned finished:1; /* finished playing */ |
69 | }; |
70 | |
71 | struct private { |
72 | pa_threaded_mainloop *mainloop; |
73 | pa_context *context; |
74 | ka_theme_data *theme; |
75 | ka_bool_t subscribed; |
76 | ka_bool_t reconnect; |
77 | |
78 | ka_mutex *outstanding_mutex; |
79 | KA_LLIST_HEAD(struct outstanding, outstanding)struct outstanding *outstanding; |
80 | }; |
81 | |
82 | #define PRIVATE(c)((struct private *) ((c)->private)) ((struct private *) ((c)->private)) |
83 | |
84 | static void context_state_cb(pa_context *pc, void *userdata); |
85 | static void context_subscribe_cb(pa_context *pc, pa_subscription_event_type_t t, uint32_t idx, void *userdata); |
86 | |
87 | static void outstanding_disconnect(struct outstanding *o) { |
88 | ka_assert(o)do { if ((__builtin_expect((!(o)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "o" , "pulse.c", 88, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
89 | |
90 | if (o->stream) { |
91 | if (o->drain_operation) { |
92 | pa_operation_cancel(o->drain_operation); |
93 | pa_operation_unref(o->drain_operation); |
94 | o->drain_operation = NULL((void*)0); |
95 | } |
96 | |
97 | pa_stream_set_write_callback(o->stream, NULL((void*)0), NULL((void*)0)); |
98 | pa_stream_set_state_callback(o->stream, NULL((void*)0), NULL((void*)0)); |
99 | pa_stream_disconnect(o->stream); |
100 | pa_stream_unref(o->stream); |
101 | o->stream = NULL((void*)0); |
102 | } |
103 | } |
104 | |
105 | static void outstanding_free(struct outstanding *o) { |
106 | ka_assert(o)do { if ((__builtin_expect((!(o)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "o" , "pulse.c", 106, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
107 | |
108 | outstanding_disconnect(o); |
109 | |
110 | if (o->file) |
111 | ka_sound_file_close(o->file); |
112 | |
113 | ka_freefree(o); |
114 | } |
115 | |
116 | static int convert_proplist(pa_proplist **_l, ka_proplist *c) { |
117 | pa_proplist *l; |
118 | ka_prop *i; |
119 | |
120 | ka_return_val_if_fail(_l, KA_ERROR_INVALID)do { if ((__builtin_expect((!(_l)),0))) { if (ka_debug()) fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s().\n", "_l" , "pulse.c", 120, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
121 | 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" , "pulse.c", 121, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
122 | |
123 | if (!(l = pa_proplist_new())) |
124 | return KA_ERROR_OOM; |
125 | |
126 | ka_mutex_lock(c->mutex); |
127 | |
128 | for (i = c->first_item; i; i = i->next_item) |
129 | if (pa_proplist_set(l, i->key, KA_PROP_DATA(i)((void*) ((char*) (i) + (ka_align(sizeof(ka_prop))))), i->nbytes) < 0) { |
130 | ka_mutex_unlock(c->mutex); |
131 | pa_proplist_free(l); |
132 | return KA_ERROR_INVALID; |
133 | } |
134 | |
135 | ka_mutex_unlock(c->mutex); |
136 | |
137 | *_l = l; |
138 | |
139 | return KA_SUCCESS; |
140 | } |
141 | |
142 | static pa_proplist *strip_prefix(pa_proplist *l, const char *prefix) { |
143 | const char *key; |
144 | void *state = NULL((void*)0); |
145 | ka_assert(l)do { if ((__builtin_expect((!(l)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "l" , "pulse.c", 145, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
146 | |
147 | while ((key = pa_proplist_iterate(l, &state))) |
148 | if (strncmp(key, prefix, strlen(prefix)) == 0) |
149 | pa_proplist_unset(l, key); |
150 | |
151 | return l; |
152 | } |
153 | |
154 | static void add_common(pa_proplist *l) { |
155 | ka_assert(l)do { if ((__builtin_expect((!(l)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "l" , "pulse.c", 155, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
156 | |
157 | if (!pa_proplist_contains(l, KA_PROP_MEDIA_ROLE"media.role")) |
158 | pa_proplist_sets(l, KA_PROP_MEDIA_ROLE"media.role", "event"); |
159 | |
160 | if (!pa_proplist_contains(l, KA_PROP_MEDIA_NAME"media.name")) { |
161 | const char *t; |
162 | |
163 | if ((t = pa_proplist_gets(l, KA_PROP_EVENT_ID"event.id"))) |
164 | pa_proplist_sets(l, KA_PROP_MEDIA_NAME"media.name", t); |
165 | else if ((t = pa_proplist_gets(l, KA_PROP_MEDIA_FILENAME"media.filename"))) |
166 | pa_proplist_sets(l, KA_PROP_MEDIA_NAME"media.name", t); |
167 | else |
168 | pa_proplist_sets(l, KA_PROP_MEDIA_NAME"media.name", "libkanberra"); |
169 | } |
170 | } |
171 | |
172 | static int translate_error(int error) { |
173 | static const int table[PA_ERR_MAXPA_ERR_MAX] = { |
174 | [PA_OKPA_OK] = KA_SUCCESS, |
175 | [PA_ERR_ACCESSPA_ERR_ACCESS] = KA_ERROR_ACCESS, |
176 | [PA_ERR_COMMANDPA_ERR_COMMAND] = KA_ERROR_IO, |
177 | [PA_ERR_INVALIDPA_ERR_INVALID] = KA_ERROR_INVALID, |
178 | [PA_ERR_EXISTPA_ERR_EXIST] = KA_ERROR_IO, |
179 | [PA_ERR_NOENTITYPA_ERR_NOENTITY] = KA_ERROR_NOTFOUND, |
180 | [PA_ERR_CONNECTIONREFUSEDPA_ERR_CONNECTIONREFUSED] = KA_ERROR_NOTAVAILABLE, |
181 | [PA_ERR_PROTOCOLPA_ERR_PROTOCOL] = KA_ERROR_IO, |
182 | [PA_ERR_TIMEOUTPA_ERR_TIMEOUT] = KA_ERROR_IO, |
183 | [PA_ERR_AUTHKEYPA_ERR_AUTHKEY] = KA_ERROR_ACCESS, |
184 | [PA_ERR_INTERNALPA_ERR_INTERNAL] = KA_ERROR_IO, |
185 | [PA_ERR_CONNECTIONTERMINATEDPA_ERR_CONNECTIONTERMINATED] = KA_ERROR_IO, |
186 | [PA_ERR_KILLEDPA_ERR_KILLED] = KA_ERROR_DESTROYED, |
187 | [PA_ERR_INVALIDSERVERPA_ERR_INVALIDSERVER] = KA_ERROR_INVALID, |
188 | [PA_ERR_MODINITFAILEDPA_ERR_MODINITFAILED] = KA_ERROR_NODRIVER, |
189 | [PA_ERR_BADSTATEPA_ERR_BADSTATE] = KA_ERROR_STATE, |
190 | [PA_ERR_NODATAPA_ERR_NODATA] = KA_ERROR_IO, |
191 | [PA_ERR_VERSIONPA_ERR_VERSION] = KA_ERROR_NOTSUPPORTED, |
192 | [PA_ERR_TOOLARGEPA_ERR_TOOLARGE] = KA_ERROR_TOOBIG, |
193 | #ifdef PA_ERR_NOTSUPPORTEDPA_ERR_NOTSUPPORTED |
194 | [PA_ERR_NOTSUPPORTEDPA_ERR_NOTSUPPORTED] = KA_ERROR_NOTSUPPORTED, |
195 | #endif |
196 | #ifdef PA_ERR_UNKNOWNPA_ERR_UNKNOWN |
197 | [PA_ERR_UNKNOWNPA_ERR_UNKNOWN] = KA_ERROR_IO, |
198 | #endif |
199 | #ifdef PA_ERR_NOEXTENSIONPA_ERR_NOEXTENSION |
200 | [PA_ERR_NOEXTENSIONPA_ERR_NOEXTENSION] = KA_ERROR_NOTSUPPORTED, |
201 | #endif |
202 | #ifdef PA_ERR_OBSOLETEPA_ERR_OBSOLETE |
203 | [PA_ERR_OBSOLETEPA_ERR_OBSOLETE] = KA_ERROR_NOTSUPPORTED, |
204 | #endif |
205 | #ifdef PA_ERR_NOTIMPLEMENTEDPA_ERR_NOTIMPLEMENTED |
206 | [PA_ERR_NOTIMPLEMENTEDPA_ERR_NOTIMPLEMENTED] = KA_ERROR_NOTSUPPORTED |
207 | #endif |
208 | }; |
209 | |
210 | ka_assert(error >= 0)do { if ((__builtin_expect((!(error >= 0)),0))) { fprintf( stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "error >= 0" , "pulse.c", 210, __PRETTY_FUNCTION__); abort (); } } while ((0)); |
211 | |
212 | if (error >= PA_ERR_MAXPA_ERR_MAX || !table[error]) |
213 | return KA_ERROR_IO; |
214 | |
215 | return table[error]; |
216 | } |
217 | |
218 | static int context_connect(ka_context *c, ka_bool_t nofail) { |
219 | pa_proplist *l; |
220 | struct private *p; |
221 | int ret; |
222 | |
223 | 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" , "pulse.c", 223, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
224 | ka_return_val_if_fail(p = c->private, KA_ERROR_STATE)do { if ((__builtin_expect((!(p = c->private)),0))) { if ( ka_debug()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "p = c->private" , "pulse.c", 224, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
225 | ka_return_val_if_fail(p->mainloop, KA_ERROR_STATE)do { if ((__builtin_expect((!(p->mainloop)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "p->mainloop" , "pulse.c", 225, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
226 | ka_return_val_if_fail(!p->context, KA_ERROR_STATE)do { if ((__builtin_expect((!(!p->context)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "!p->context" , "pulse.c", 226, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
227 | |
228 | /* If this immediate attempt fails, don't try to reconnect. */ |
229 | p->reconnect = FALSE(0); |
230 | |
231 | if ((ret = convert_proplist(&l, c->props)) < 0) |
232 | return ret; |
233 | |
234 | strip_prefix(l, "kanberra."); |
235 | |
236 | if (!pa_proplist_contains(l, PA_PROP_APPLICATION_NAME"application.name")) { |
237 | pa_proplist_sets(l, PA_PROP_APPLICATION_NAME"application.name", "libkanberra"); |
238 | pa_proplist_sets(l, PA_PROP_APPLICATION_VERSION"application.version", PACKAGE_VERSION"0.31"); |
239 | |
240 | if (!pa_proplist_contains(l, PA_PROP_APPLICATION_ID"application.id")) |
241 | pa_proplist_sets(l, PA_PROP_APPLICATION_ID"application.id", "org.freedesktop.libkanberra"); |
242 | |
243 | } |
244 | |
245 | if (!(p->context = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(p->mainloop), NULL((void*)0), l))) { |
246 | pa_proplist_free(l); |
247 | return KA_ERROR_OOM; |
248 | } |
249 | |
250 | pa_proplist_free(l); |
251 | |
252 | pa_context_set_state_callback(p->context, context_state_cb, c); |
253 | pa_context_set_subscribe_callback(p->context, context_subscribe_cb, c); |
254 | |
255 | if (pa_context_connect(p->context, NULL((void*)0), nofail ? PA_CONTEXT_NOFAILPA_CONTEXT_NOFAIL : 0, NULL((void*)0)) < 0) { |
256 | ret = translate_error(p->context ? pa_context_errno(p->context) : PA_ERR_CONNECTIONREFUSEDPA_ERR_CONNECTIONREFUSED); |
257 | |
258 | if (p->context) { |
259 | pa_context_disconnect(p->context); |
260 | pa_context_unref(p->context); |
261 | p->context = NULL((void*)0); |
262 | } |
263 | |
264 | return ret; |
265 | } |
266 | |
267 | return KA_SUCCESS; |
268 | } |
269 | |
270 | static void context_state_cb(pa_context *pc, void *userdata) { |
271 | ka_context *c = userdata; |
272 | pa_context_state_t state; |
273 | struct private *p; |
274 | |
275 | ka_assert(pc)do { if ((__builtin_expect((!(pc)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "pc" , "pulse.c", 275, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
276 | ka_assert(c)do { if ((__builtin_expect((!(c)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "c" , "pulse.c", 276, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
277 | |
278 | p = PRIVATE(c)((struct private *) ((c)->private)); |
279 | |
280 | state = pa_context_get_state(pc); |
281 | if (state == PA_CONTEXT_FAILEDPA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATEDPA_CONTEXT_TERMINATED) { |
282 | struct outstanding *out; |
283 | int ret; |
284 | |
285 | if (state == PA_CONTEXT_TERMINATEDPA_CONTEXT_TERMINATED) |
286 | ret = KA_ERROR_DESTROYED; |
287 | else |
288 | ret = translate_error(pa_context_errno(pc)); |
289 | |
290 | ka_mutex_lock(p->outstanding_mutex); |
291 | |
292 | while ((out = p->outstanding)) { |
293 | |
294 | outstanding_disconnect(out); |
295 | 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" , "pulse.c", 295, __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" , "pulse.c", 295, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
296 | |
297 | ka_mutex_unlock(p->outstanding_mutex); |
298 | |
299 | if (out->callback) |
300 | out->callback(c, out->id, ret, out->userdata); |
301 | |
302 | outstanding_free(out); |
303 | |
304 | ka_mutex_lock(p->outstanding_mutex); |
305 | } |
306 | |
307 | ka_mutex_unlock(p->outstanding_mutex); |
308 | |
309 | if (state == PA_CONTEXT_FAILEDPA_CONTEXT_FAILED && p->reconnect) { |
310 | |
311 | if (p->context) { |
312 | pa_context_disconnect(p->context); |
313 | pa_context_unref(p->context); |
314 | p->context = NULL((void*)0); |
315 | } |
316 | |
317 | p->subscribed = FALSE(0); |
318 | |
319 | /* If we managed to connect once, then let's try to |
320 | * reconnect, and pass NOFAIL */ |
321 | context_connect(c, TRUE(!(0))); |
322 | } |
323 | |
324 | } else if (state == PA_CONTEXT_READYPA_CONTEXT_READY) |
325 | /* OK, the connection suceeded once, if it dies now try to |
326 | * reconnect */ |
327 | p->reconnect = TRUE(!(0)); |
328 | |
329 | pa_threaded_mainloop_signal(p->mainloop, FALSE(0)); |
330 | } |
331 | |
332 | static void context_subscribe_cb(pa_context *pc, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { |
333 | struct outstanding *out, *n; |
334 | KA_LLIST_HEAD(struct outstanding, l)struct outstanding *l; |
335 | ka_context *c = userdata; |
336 | struct private *p; |
337 | |
338 | ka_assert(pc)do { if ((__builtin_expect((!(pc)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "pc" , "pulse.c", 338, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
339 | ka_assert(c)do { if ((__builtin_expect((!(c)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "c" , "pulse.c", 339, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
340 | |
341 | if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUTPA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVEPA_SUBSCRIPTION_EVENT_REMOVE)) |
342 | return; |
343 | |
344 | p = PRIVATE(c)((struct private *) ((c)->private)); |
345 | |
346 | KA_LLIST_HEAD_INIT(struct outstanding, l)do { (l) = (struct outstanding*) ((void*)0); } while(0); |
347 | |
348 | ka_mutex_lock(p->outstanding_mutex); |
349 | |
350 | for (out = p->outstanding; out; out = n) { |
351 | n = out->next; |
352 | |
353 | if (!out->clean_up || out->type != OUTSTANDING_SAMPLE || out->sink_input != idx) |
354 | continue; |
355 | |
356 | outstanding_disconnect(out); |
357 | 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" , "pulse.c", 357, __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" , "pulse.c", 357, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
358 | |
359 | KA_LLIST_PREPEND(struct outstanding, l, out)do { struct outstanding **_head = &(l), *_item = (out); do { if ((__builtin_expect((!(_item)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "_item" , "pulse.c", 359, __PRETTY_FUNCTION__); abort(); } } while ((0)); if ((_item->next = *_head)) _item->next-> prev = _item; _item->prev = ((void*)0); *_head = _item; } while (0); |
360 | } |
361 | |
362 | ka_mutex_unlock(p->outstanding_mutex); |
363 | |
364 | while (l) { |
365 | out = l; |
366 | |
367 | KA_LLIST_REMOVE(struct outstanding, l, out)do { struct outstanding **_head = &(l), *_item = (out); do { if ((__builtin_expect((!(_item)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "_item" , "pulse.c", 367, __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" , "pulse.c", 367, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
368 | |
369 | if (out->callback) |
370 | out->callback(c, out->id, KA_SUCCESS, out->userdata); |
371 | |
372 | outstanding_free(out); |
373 | } |
374 | } |
375 | |
376 | int driver_openpulse_driver_open(ka_context *c) { |
377 | struct private *p; |
378 | int ret; |
379 | |
380 | 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" , "pulse.c", 380, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
381 | ka_return_val_if_fail(!c->driver || ka_streq(c->driver, "pulse"), KA_ERROR_NODRIVER)do { if ((__builtin_expect((!(!c->driver || (strcmp((c-> driver),("pulse")) == 0))),0))) { if (ka_debug()) fprintf(stderr , "Assertion '%s' failed at %s:%u, function %s().\n", "!c->driver || ka_streq(c->driver, \"pulse\")" , "pulse.c", 381, __PRETTY_FUNCTION__); return (KA_ERROR_NODRIVER ); } } while((0)); |
382 | 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)" , "pulse.c", 382, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
383 | |
384 | if (!(c->private = p = ka_new0(struct private, 1)((struct private*) calloc(1, (sizeof(struct private)*(1)))))) |
385 | return KA_ERROR_OOM; |
386 | |
387 | if (!(p->outstanding_mutex = ka_mutex_new())) { |
388 | driver_destroypulse_driver_destroy(c); |
389 | return KA_ERROR_OOM; |
390 | } |
391 | |
392 | if (!(p->mainloop = pa_threaded_mainloop_new())) { |
393 | driver_destroypulse_driver_destroy(c); |
394 | return KA_ERROR_OOM; |
395 | } |
396 | |
397 | /* The initial connection is without NOFAIL, since we want to have |
398 | * this call fail cleanly if we cannot connect. */ |
399 | if ((ret = context_connect(c, FALSE(0))) != KA_SUCCESS) { |
400 | driver_destroypulse_driver_destroy(c); |
401 | return ret; |
402 | } |
403 | |
404 | pa_threaded_mainloop_lock(p->mainloop); |
405 | |
406 | if (pa_threaded_mainloop_start(p->mainloop) < 0) { |
407 | pa_threaded_mainloop_unlock(p->mainloop); |
408 | driver_destroypulse_driver_destroy(c); |
409 | return KA_ERROR_OOM; |
410 | } |
411 | |
412 | for (;;) { |
413 | pa_context_state_t state; |
414 | |
415 | if (!p->context) { |
416 | ret = translate_error(PA_ERR_CONNECTIONREFUSEDPA_ERR_CONNECTIONREFUSED); |
417 | pa_threaded_mainloop_unlock(p->mainloop); |
418 | driver_destroypulse_driver_destroy(c); |
419 | return ret; |
420 | } |
421 | |
422 | state = pa_context_get_state(p->context); |
423 | |
424 | if (state == PA_CONTEXT_READYPA_CONTEXT_READY) |
425 | break; |
426 | |
427 | if (state == PA_CONTEXT_FAILEDPA_CONTEXT_FAILED) { |
428 | ret = translate_error(pa_context_errno(p->context)); |
429 | pa_threaded_mainloop_unlock(p->mainloop); |
430 | driver_destroypulse_driver_destroy(c); |
431 | return ret; |
432 | } |
433 | |
434 | ka_assert(state != PA_CONTEXT_TERMINATED)do { if ((__builtin_expect((!(state != PA_CONTEXT_TERMINATED) ),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "state != PA_CONTEXT_TERMINATED" , "pulse.c", 434, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); |
435 | |
436 | pa_threaded_mainloop_wait(p->mainloop); |
437 | } |
438 | |
439 | pa_threaded_mainloop_unlock(p->mainloop); |
440 | |
441 | return KA_SUCCESS; |
442 | } |
443 | |
444 | int driver_destroypulse_driver_destroy(ka_context *c) { |
445 | struct private *p; |
446 | |
447 | 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" , "pulse.c", 447, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
448 | 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" , "pulse.c", 448, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
449 | |
450 | p = PRIVATE(c)((struct private *) ((c)->private)); |
451 | |
452 | if (p->mainloop) |
453 | pa_threaded_mainloop_stop(p->mainloop); |
454 | |
455 | if (p->context) { |
456 | pa_context_disconnect(p->context); |
457 | pa_context_unref(p->context); |
458 | } |
459 | |
460 | while (p->outstanding) { |
461 | struct outstanding *out = p->outstanding; |
462 | 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" , "pulse.c", 462, __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" , "pulse.c", 462, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
463 | |
464 | if (out->callback) |
465 | out->callback(c, out->id, KA_ERROR_DESTROYED, out->userdata); |
466 | |
467 | outstanding_free(out); |
468 | } |
469 | |
470 | if (p->mainloop) |
471 | pa_threaded_mainloop_free(p->mainloop); |
472 | |
473 | if (p->theme) |
474 | ka_theme_data_free(p->theme); |
475 | |
476 | if (p->outstanding_mutex) |
477 | ka_mutex_free(p->outstanding_mutex); |
478 | |
479 | ka_freefree(p); |
480 | |
481 | c->private = NULL((void*)0); |
482 | |
483 | return KA_SUCCESS; |
484 | } |
485 | |
486 | int driver_change_devicepulse_driver_change_device(ka_context *c, const char *device) { |
487 | 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" , "pulse.c", 487, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
488 | 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" , "pulse.c", 488, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
489 | |
490 | /* We're happy with any device change. We might however add code |
491 | * here eventually to move all currently played back event sounds |
492 | * to the new device. */ |
493 | |
494 | return KA_SUCCESS; |
495 | } |
496 | |
497 | int driver_change_propspulse_driver_change_props(ka_context *c, ka_proplist *changed, ka_proplist *merged) { |
498 | struct private *p; |
499 | pa_operation *o; |
500 | pa_proplist *l; |
501 | int ret = KA_SUCCESS; |
502 | |
503 | 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" , "pulse.c", 503, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
504 | 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" , "pulse.c", 504, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
505 | 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" , "pulse.c", 505, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
506 | 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" , "pulse.c", 506, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
507 | |
508 | p = PRIVATE(c)((struct private *) ((c)->private)); |
509 | |
510 | ka_return_val_if_fail(p->mainloop, KA_ERROR_STATE)do { if ((__builtin_expect((!(p->mainloop)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "p->mainloop" , "pulse.c", 510, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
511 | |
512 | pa_threaded_mainloop_lock(p->mainloop); |
513 | |
514 | if (!p->context) { |
515 | pa_threaded_mainloop_unlock(p->mainloop); |
516 | return KA_ERROR_STATE; /* can be silently ignored */ |
517 | } |
518 | |
519 | if ((ret = convert_proplist(&l, changed)) < 0) |
520 | return ret; |
521 | |
522 | strip_prefix(l, "kanberra."); |
523 | |
524 | /* We start these asynchronously and don't care about the return |
525 | * value */ |
526 | |
527 | if (!(o = pa_context_proplist_update(p->context, PA_UPDATE_REPLACEPA_UPDATE_REPLACE, l, NULL((void*)0), NULL((void*)0)))) |
528 | ret = translate_error(pa_context_errno(p->context)); |
529 | else |
530 | pa_operation_unref(o); |
531 | |
532 | pa_threaded_mainloop_unlock(p->mainloop); |
533 | |
534 | pa_proplist_free(l); |
535 | |
536 | return ret; |
537 | } |
538 | |
539 | static int subscribe(ka_context *c) { |
540 | struct private *p; |
541 | pa_operation *o; |
542 | int ret = KA_SUCCESS; |
543 | |
544 | 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" , "pulse.c", 544, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
545 | 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" , "pulse.c", 545, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
546 | p = PRIVATE(c)((struct private *) ((c)->private)); |
547 | |
548 | ka_return_val_if_fail(p->mainloop, KA_ERROR_STATE)do { if ((__builtin_expect((!(p->mainloop)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "p->mainloop" , "pulse.c", 548, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
549 | |
550 | if (p->subscribed) |
551 | return KA_SUCCESS; |
552 | |
553 | pa_threaded_mainloop_lock(p->mainloop); |
554 | |
555 | if (!p->context) { |
556 | pa_threaded_mainloop_unlock(p->mainloop); |
557 | return KA_ERROR_STATE; |
558 | } |
559 | |
560 | /* We start these asynchronously and don't care about the return |
561 | * value */ |
562 | |
563 | if (!(o = pa_context_subscribe(p->context, PA_SUBSCRIPTION_MASK_SINK_INPUTPA_SUBSCRIPTION_MASK_SINK_INPUT, NULL((void*)0), NULL((void*)0)))) |
564 | ret = translate_error(pa_context_errno(p->context)); |
565 | else |
566 | pa_operation_unref(o); |
567 | |
568 | pa_threaded_mainloop_unlock(p->mainloop); |
569 | |
570 | p->subscribed = TRUE(!(0)); |
571 | |
572 | return ret; |
573 | } |
574 | |
575 | static void play_sample_cb(pa_context *c, uint32_t idx, void *userdata) { |
576 | struct private *p; |
577 | struct outstanding *out = userdata; |
578 | |
579 | ka_assert(c)do { if ((__builtin_expect((!(c)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "c" , "pulse.c", 579, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
580 | ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "out" , "pulse.c", 580, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
581 | |
582 | p = PRIVATE(out->context)((struct private *) ((out->context)->private)); |
583 | |
584 | if (idx != PA_INVALID_INDEX((uint32_t) -1)) { |
585 | out->error = KA_SUCCESS; |
586 | out->sink_input = idx; |
587 | } else |
588 | out->error = translate_error(pa_context_errno(c)); |
589 | |
590 | pa_threaded_mainloop_signal(p->mainloop, FALSE(0)); |
591 | } |
592 | |
593 | static void stream_state_cb(pa_stream *s, void *userdata) { |
594 | struct private *p; |
595 | struct outstanding *out = userdata; |
596 | pa_stream_state_t state; |
597 | |
598 | ka_assert(s)do { if ((__builtin_expect((!(s)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "s" , "pulse.c", 598, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
599 | ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "out" , "pulse.c", 599, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
600 | |
601 | p = PRIVATE(out->context)((struct private *) ((out->context)->private)); |
602 | |
603 | state = pa_stream_get_state(s); |
604 | |
605 | switch (state) { |
606 | case PA_STREAM_CREATINGPA_STREAM_CREATING: |
607 | case PA_STREAM_UNCONNECTEDPA_STREAM_UNCONNECTED: |
608 | break; |
609 | |
610 | case PA_STREAM_READYPA_STREAM_READY: |
611 | out->sink_input = pa_stream_get_index(out->stream); |
612 | break; |
613 | |
614 | case PA_STREAM_FAILEDPA_STREAM_FAILED: |
615 | case PA_STREAM_TERMINATEDPA_STREAM_TERMINATED: { |
616 | int err; |
617 | |
618 | err = state == PA_STREAM_FAILEDPA_STREAM_FAILED ? translate_error(pa_context_errno(pa_stream_get_context(s))) : KA_ERROR_DESTROYED; |
619 | |
620 | if (out->clean_up) { |
621 | ka_mutex_lock(p->outstanding_mutex); |
622 | outstanding_disconnect(out); |
623 | 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" , "pulse.c", 623, __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" , "pulse.c", 623, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
624 | ka_mutex_unlock(p->outstanding_mutex); |
625 | |
626 | if (out->callback) |
627 | out->callback(out->context, out->id, out->error, out->userdata); |
628 | |
629 | outstanding_free(out); |
630 | } else { |
631 | out->finished = TRUE(!(0)); |
632 | out->error = err; |
633 | } |
634 | |
635 | break; |
636 | } |
637 | } |
638 | |
639 | pa_threaded_mainloop_signal(p->mainloop, FALSE(0)); |
640 | } |
641 | |
642 | static void stream_drain_cb(pa_stream *s, int success, void *userdata) { |
643 | struct private *p; |
644 | struct outstanding *out = userdata; |
645 | int err; |
646 | |
647 | ka_assert(s)do { if ((__builtin_expect((!(s)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "s" , "pulse.c", 647, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
648 | ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "out" , "pulse.c", 648, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
649 | ka_assert(out->type == OUTSTANDING_STREAM)do { if ((__builtin_expect((!(out->type == OUTSTANDING_STREAM )),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "out->type == OUTSTANDING_STREAM" , "pulse.c", 649, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); |
650 | |
651 | p = PRIVATE(out->context)((struct private *) ((out->context)->private)); |
652 | err = success ? KA_SUCCESS : translate_error(pa_context_errno(p->context)); |
653 | |
654 | if (out->clean_up) { |
655 | ka_mutex_lock(p->outstanding_mutex); |
656 | outstanding_disconnect(out); |
657 | 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" , "pulse.c", 657, __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" , "pulse.c", 657, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
658 | ka_mutex_unlock(p->outstanding_mutex); |
659 | |
660 | if (out->callback) |
661 | out->callback(out->context, out->id, err, out->userdata); |
662 | |
663 | outstanding_free(out); |
664 | |
665 | } else { |
666 | pa_stream_disconnect(s); |
667 | out->error = err; |
668 | out->finished = TRUE(!(0)); |
669 | |
670 | if (out->drain_operation) { |
671 | pa_operation_unref(out->drain_operation); |
672 | out->drain_operation = NULL((void*)0); |
673 | } |
674 | } |
675 | |
676 | pa_threaded_mainloop_signal(p->mainloop, FALSE(0)); |
677 | } |
678 | |
679 | static void stream_write_cb(pa_stream *s, size_t bytes, void *userdata) { |
680 | struct outstanding *out = userdata; |
681 | struct private *p; |
682 | void *data; |
683 | int ret; |
684 | ka_bool_t eof = FALSE(0); |
685 | |
686 | ka_assert(s)do { if ((__builtin_expect((!(s)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "s" , "pulse.c", 686, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
687 | ka_assert(bytes > 0)do { if ((__builtin_expect((!(bytes > 0)),0))) { fprintf(stderr , "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "bytes > 0" , "pulse.c", 687, __PRETTY_FUNCTION__); abort (); } } while ((0)); |
688 | ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "out" , "pulse.c", 688, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
689 | |
690 | p = PRIVATE(out->context)((struct private *) ((out->context)->private)); |
691 | |
692 | while (bytes > 0) { |
693 | size_t rbytes = bytes; |
694 | |
695 | if (!(data = ka_mallocmalloc(rbytes))) { |
696 | ret = KA_ERROR_OOM; |
697 | goto finish; |
698 | } |
699 | |
700 | if ((ret = ka_sound_file_read_arbitrary(out->file, data, &rbytes)) < 0) |
701 | goto finish; |
702 | |
703 | if (rbytes <= 0) { |
704 | eof = TRUE(!(0)); |
705 | break; |
706 | } |
707 | |
708 | ka_assert(rbytes <= bytes)do { if ((__builtin_expect((!(rbytes <= bytes)),0))) { fprintf (stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "rbytes <= bytes" , "pulse.c", 708, __PRETTY_FUNCTION__) ; abort(); } } while ((0)); |
709 | |
710 | if ((ret = pa_stream_write(s, data, rbytes, ka_freefree, 0, PA_SEEK_RELATIVEPA_SEEK_RELATIVE)) < 0) { |
711 | ret = translate_error(ret); |
712 | goto finish; |
713 | } |
714 | |
715 | data = NULL((void*)0); |
716 | |
717 | bytes -= rbytes; |
718 | } |
719 | |
720 | if (eof || ka_sound_file_get_size(out->file) <= 0) { |
721 | |
722 | /* We reached EOF */ |
723 | |
724 | if (out->type == OUTSTANDING_UPLOAD) { |
725 | |
726 | if (pa_stream_finish_upload(s) < 0) { |
727 | ret = translate_error(pa_context_errno(p->context)); |
728 | goto finish; |
729 | } |
730 | |
731 | /* Let's just signal driver_cache() which has been waiting for us */ |
732 | pa_threaded_mainloop_signal(p->mainloop, FALSE(0)); |
733 | |
734 | } else { |
735 | ka_assert(out->type == OUTSTANDING_STREAM)do { if ((__builtin_expect((!(out->type == OUTSTANDING_STREAM )),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "out->type == OUTSTANDING_STREAM" , "pulse.c", 735, __PRETTY_FUNCTION__ ); abort(); } } while ((0)); |
736 | |
737 | if (out->drain_operation) { |
738 | pa_operation_cancel(out->drain_operation); |
739 | pa_operation_unref(out->drain_operation); |
740 | } |
741 | |
742 | if (!(out->drain_operation = pa_stream_drain(s, stream_drain_cb, out))) { |
743 | ret = translate_error(pa_context_errno(p->context)); |
744 | goto finish; |
745 | } |
746 | } |
747 | |
748 | pa_stream_set_write_callback(s, NULL((void*)0), NULL((void*)0)); |
749 | } |
750 | |
751 | ka_freefree(data); |
752 | |
753 | return; |
754 | |
755 | finish: |
756 | |
757 | ka_freefree(data); |
758 | |
759 | if (out->clean_up) { |
760 | ka_mutex_lock(p->outstanding_mutex); |
761 | outstanding_disconnect(out); |
762 | 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" , "pulse.c", 762, __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" , "pulse.c", 762, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
763 | ka_mutex_unlock(p->outstanding_mutex); |
764 | |
765 | if (out->callback) |
766 | out->callback(out->context, out->id, ret, out->userdata); |
767 | |
768 | outstanding_free(out); |
769 | |
770 | } else { |
771 | pa_stream_disconnect(s); |
772 | out->error = ret; |
773 | out->finished = TRUE(!(0)); |
774 | } |
775 | |
776 | pa_threaded_mainloop_signal(p->mainloop, FALSE(0)); |
777 | } |
778 | |
779 | static const pa_sample_format_t sample_type_table[] = { |
780 | [KA_SAMPLE_S16NE] = PA_SAMPLE_S16NEPA_SAMPLE_S16LE, |
781 | [KA_SAMPLE_S16RE] = PA_SAMPLE_S16REPA_SAMPLE_S16BE, |
782 | [KA_SAMPLE_U8] = PA_SAMPLE_U8PA_SAMPLE_U8 |
783 | }; |
784 | |
785 | static const pa_channel_position_t channel_table[_KA_CHANNEL_POSITION_MAX] = { |
786 | [KA_CHANNEL_MONO] = PA_CHANNEL_POSITION_MONOPA_CHANNEL_POSITION_MONO, |
787 | [KA_CHANNEL_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFTPA_CHANNEL_POSITION_FRONT_LEFT, |
788 | [KA_CHANNEL_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHTPA_CHANNEL_POSITION_FRONT_RIGHT, |
789 | [KA_CHANNEL_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTERPA_CHANNEL_POSITION_FRONT_CENTER, |
790 | [KA_CHANNEL_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFTPA_CHANNEL_POSITION_REAR_LEFT, |
791 | [KA_CHANNEL_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHTPA_CHANNEL_POSITION_REAR_RIGHT, |
792 | [KA_CHANNEL_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTERPA_CHANNEL_POSITION_REAR_CENTER, |
793 | [KA_CHANNEL_LFE] = PA_CHANNEL_POSITION_LFEPA_CHANNEL_POSITION_LFE, |
794 | [KA_CHANNEL_FRONT_LEFT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTERPA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, |
795 | [KA_CHANNEL_FRONT_RIGHT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTERPA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, |
796 | [KA_CHANNEL_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFTPA_CHANNEL_POSITION_SIDE_LEFT, |
797 | [KA_CHANNEL_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHTPA_CHANNEL_POSITION_SIDE_RIGHT, |
798 | [KA_CHANNEL_TOP_CENTER] = PA_CHANNEL_POSITION_TOP_CENTERPA_CHANNEL_POSITION_TOP_CENTER, |
799 | [KA_CHANNEL_TOP_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFTPA_CHANNEL_POSITION_FRONT_LEFT, |
800 | [KA_CHANNEL_TOP_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHTPA_CHANNEL_POSITION_FRONT_RIGHT, |
801 | [KA_CHANNEL_TOP_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTERPA_CHANNEL_POSITION_FRONT_CENTER, |
802 | [KA_CHANNEL_TOP_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFTPA_CHANNEL_POSITION_REAR_LEFT, |
803 | [KA_CHANNEL_TOP_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHTPA_CHANNEL_POSITION_REAR_RIGHT, |
804 | [KA_CHANNEL_TOP_REAR_CENTER] = PA_CHANNEL_POSITION_TOP_REAR_CENTERPA_CHANNEL_POSITION_TOP_REAR_CENTER |
805 | }; |
806 | |
807 | static ka_bool_t convert_channel_map(ka_sound_file *f, pa_channel_map *cm) { |
808 | const ka_channel_position_t *positions; |
809 | unsigned c; |
810 | |
811 | ka_assert(f)do { if ((__builtin_expect((!(f)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "f" , "pulse.c", 811, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
812 | ka_assert(cm)do { if ((__builtin_expect((!(cm)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n" , "cm" , "pulse.c", 812, __PRETTY_FUNCTION__); abort(); } } while ((0)); |
813 | |
814 | if (!(positions = ka_sound_file_get_channel_map(f))) |
815 | return FALSE(0); |
816 | |
817 | cm->channels = ka_sound_file_get_nchannels(f); |
818 | for (c = 0; c < cm->channels; c++) |
819 | cm->map[c] = channel_table[positions[c]]; |
820 | |
821 | return TRUE(!(0)); |
822 | } |
823 | |
824 | int driver_playpulse_driver_play(ka_context *c, uint32_t id, ka_proplist *proplist, ka_finish_callback_t cb, void *userdata) { |
825 | struct private *p; |
826 | pa_proplist *l = NULL((void*)0); |
827 | const char *n, *vol, *ct, *channel; |
828 | char *name = NULL((void*)0); |
829 | #if defined(PA_MAJOR16) && ((PA_MAJOR16 > 0) || (PA_MAJOR16 == 0 && PA_MINOR1 > 9) || (PA_MAJOR16 == 0 && PA_MINOR1 == 9 && PA_MICRO0 >= 15)) |
830 | pa_volume_t v = (pa_volume_t) -1; |
831 | #else |
832 | pa_volume_t v = PA_VOLUME_NORM((pa_volume_t) 0x10000U); |
833 | #endif |
834 | ka_bool_t volume_set = FALSE(0); |
835 | pa_cvolume cvol; |
836 | pa_sample_spec ss; |
837 | pa_channel_map cm; |
838 | pa_channel_position_t position = PA_CHANNEL_POSITION_INVALIDPA_CHANNEL_POSITION_INVALID; |
839 | ka_bool_t cm_good; |
840 | ka_cache_control_t cache_control = KA_CACHE_CONTROL_NEVER; |
841 | struct outstanding *out = NULL((void*)0); |
842 | int try = 3; |
843 | int ret; |
844 | pa_operation *o; |
845 | char *sp; |
846 | pa_buffer_attr ba; |
847 | |
848 | 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" , "pulse.c", 848, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
849 | 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" , "pulse.c", 849, __PRETTY_FUNCTION__); return ( KA_ERROR_INVALID); } } while((0)); |
850 | 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" , "pulse.c", 850, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID); } } while((0)); |
851 | 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" , "pulse.c", 851, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
852 | |
853 | p = PRIVATE(c)((struct private *) ((c)->private)); |
854 | |
855 | ka_return_val_if_fail(p->mainloop, KA_ERROR_STATE)do { if ((__builtin_expect((!(p->mainloop)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "p->mainloop" , "pulse.c", 855, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
856 | |
857 | if (!(out = ka_new0(struct outstanding, 1)((struct outstanding*) calloc(1, (sizeof(struct outstanding)* (1)))))) { |
858 | ret = KA_ERROR_OOM; |
859 | goto finish_unlocked; |
860 | } |
861 | |
862 | out->type = OUTSTANDING_SAMPLE; |
863 | out->context = c; |
864 | out->sink_input = PA_INVALID_INDEX((uint32_t) -1); |
865 | out->id = id; |
866 | out->callback = cb; |
867 | out->userdata = userdata; |
868 | |
869 | if ((ret = convert_proplist(&l, proplist)) < 0) |
870 | goto finish_unlocked; |
871 | |
872 | if ((n = pa_proplist_gets(l, KA_PROP_EVENT_ID"event.id"))) |
873 | if (!(name = ka_strdupstrdup(n))) { |
874 | ret = KA_ERROR_OOM; |
875 | goto finish_unlocked; |
876 | } |
877 | |
878 | if ((vol = pa_proplist_gets(l, KA_PROP_KANBERRA_VOLUME"kanberra.volume"))) { |
879 | char *e = NULL((void*)0); |
880 | double dvol; |
881 | |
882 | errno(*__errno_location ()) = 0; |
883 | dvol = strtod(vol, &e); |
884 | if (errno(*__errno_location ()) != 0 || !e || *e) { |
885 | ret = KA_ERROR_INVALID; |
886 | goto finish_unlocked; |
887 | } |
888 | |
889 | v = pa_sw_volume_from_dB(dvol); |
890 | volume_set = TRUE(!(0)); |
891 | } |
892 | |
893 | if ((ct = pa_proplist_gets(l, KA_PROP_KANBERRA_CACHE_CONTROL"kanberra.cache-control"))) |
894 | if ((ret = ka_parse_cache_control(&cache_control, ct)) < 0) { |
895 | ret = KA_ERROR_INVALID; |
896 | goto finish_unlocked; |
897 | } |
898 | |
899 | if ((channel = pa_proplist_gets(l, KA_PROP_KANBERRA_FORCE_CHANNEL"kanberra.force_channel"))) { |
900 | pa_channel_map t; |
901 | |
902 | if (!pa_channel_map_parse(&t, channel) || |
903 | t.channels != 1) { |
904 | ret = KA_ERROR_INVALID; |
905 | goto finish_unlocked; |
906 | } |
907 | |
908 | position = t.map[0]; |
909 | |
910 | /* We cannot remap cached samples, so let's fail when cacheing |
911 | * shall be used */ |
912 | if (cache_control != KA_CACHE_CONTROL_NEVER) { |
913 | ret = KA_ERROR_NOTSUPPORTED; |
914 | goto finish_unlocked; |
915 | } |
916 | } |
917 | |
918 | strip_prefix(l, "kanberra."); |
919 | add_common(l); |
920 | |
921 | if ((ret = subscribe(c)) < 0) |
922 | goto finish_unlocked; |
923 | |
924 | if (name && cache_control != KA_CACHE_CONTROL_NEVER) { |
925 | |
926 | /* Ok, this sample has an event id, let's try to play it from the cache */ |
927 | |
928 | for (;;) { |
929 | ka_bool_t canceled; |
930 | |
931 | pa_threaded_mainloop_lock(p->mainloop); |
932 | |
933 | if (!p->context) { |
934 | ret = KA_ERROR_STATE; |
935 | goto finish_locked; |
936 | } |
937 | |
938 | /* Let's try to play the sample */ |
939 | if (!(o = pa_context_play_sample_with_proplist(p->context, name, c->device, v, l, play_sample_cb, out))) { |
940 | ret = translate_error(pa_context_errno(p->context)); |
941 | goto finish_locked; |
942 | } |
943 | |
944 | for (;;) { |
945 | pa_operation_state_t state = pa_operation_get_state(o); |
946 | |
947 | if (state == PA_OPERATION_DONEPA_OPERATION_DONE) { |
948 | canceled = FALSE(0); |
949 | break; |
950 | } else if (state == PA_OPERATION_CANCELEDPA_OPERATION_CANCELLED) { |
951 | canceled = TRUE(!(0)); |
952 | break; |
953 | } |
954 | |
955 | pa_threaded_mainloop_wait(p->mainloop); |
956 | } |
957 | |
958 | pa_operation_unref(o); |
959 | |
960 | if (!canceled && p->context && out->error == KA_SUCCESS) { |
961 | ret = KA_SUCCESS; |
962 | goto finish_locked; |
963 | } |
964 | |
965 | pa_threaded_mainloop_unlock(p->mainloop); |
966 | |
967 | /* The operation might have been canceled due to connection termination */ |
968 | if (canceled || !p->context) { |
969 | ret = KA_ERROR_DISCONNECTED; |
970 | goto finish_unlocked; |
971 | } |
972 | |
973 | /* Did some other error occur? */ |
974 | if (out->error != KA_ERROR_NOTFOUND) { |
975 | ret = out->error; |
976 | goto finish_unlocked; |
977 | } |
978 | |
979 | /* Hmm, we need to play it directly */ |
980 | if (cache_control != KA_CACHE_CONTROL_PERMANENT) |
981 | break; |
982 | |
983 | /* Don't loop forever */ |
984 | if (--try <= 0) |
985 | break; |
986 | |
987 | /* Let's upload the sample and retry playing */ |
988 | if ((ret = driver_cachepulse_driver_cache(c, proplist)) < 0) |
989 | goto finish_unlocked; |
990 | } |
991 | } |
992 | |
993 | out->type = OUTSTANDING_STREAM; |
994 | |
995 | /* Let's stream the sample directly */ |
996 | if ((ret = ka_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0) |
997 | goto finish_unlocked; |
998 | |
999 | if (sp) |
1000 | if (!pa_proplist_contains(l, KA_PROP_MEDIA_FILENAME"media.filename")) |
1001 | pa_proplist_sets(l, KA_PROP_MEDIA_FILENAME"media.filename", sp); |
1002 | |
1003 | ka_freefree(sp); |
1004 | |
1005 | ss.format = sample_type_table[ka_sound_file_get_sample_type(out->file)]; |
1006 | ss.channels = (uint8_t) ka_sound_file_get_nchannels(out->file); |
1007 | ss.rate = ka_sound_file_get_rate(out->file); |
1008 | |
1009 | if (position != PA_CHANNEL_POSITION_INVALIDPA_CHANNEL_POSITION_INVALID) { |
1010 | unsigned u; |
1011 | /* Apply kanberra.force_channel */ |
1012 | |
1013 | cm.channels = ss.channels; |
1014 | for (u = 0; u < cm.channels; u++) |
1015 | cm.map[u] = position; |
1016 | |
1017 | cm_good = TRUE(!(0)); |
1018 | } else |
1019 | cm_good = convert_channel_map(out->file, &cm); |
1020 | |
1021 | pa_threaded_mainloop_lock(p->mainloop); |
1022 | |
1023 | if (!p->context) { |
1024 | ret = KA_ERROR_STATE; |
1025 | goto finish_locked; |
1026 | } |
1027 | |
1028 | if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL((void*)0), &ss, cm_good ? &cm : NULL((void*)0), l))) { |
1029 | ret = translate_error(pa_context_errno(p->context)); |
1030 | goto finish_locked; |
1031 | } |
1032 | |
1033 | pa_stream_set_state_callback(out->stream, stream_state_cb, out); |
1034 | pa_stream_set_write_callback(out->stream, stream_write_cb, out); |
1035 | |
1036 | if (volume_set) |
1037 | pa_cvolume_set(&cvol, ss.channels, v); |
1038 | |
1039 | /* Make sure we get the longest latency possible, to minimize CPU |
1040 | * consumption */ |
1041 | ba.maxlength = (uint32_t) -1; |
1042 | ba.tlength = (uint32_t) -1; |
1043 | ba.prebuf = (uint32_t) -1; |
1044 | ba.minreq = (uint32_t) -1; |
1045 | ba.fragsize = (uint32_t) -1; |
1046 | |
1047 | if (pa_stream_connect_playback(out->stream, c->device, &ba, |
1048 | #ifdef PA_STREAM_FAIL_ON_SUSPENDPA_STREAM_FAIL_ON_SUSPEND |
1049 | PA_STREAM_FAIL_ON_SUSPENDPA_STREAM_FAIL_ON_SUSPEND |
1050 | #else |
1051 | 0 |
1052 | #endif |
1053 | | (position != PA_CHANNEL_POSITION_INVALIDPA_CHANNEL_POSITION_INVALID ? PA_STREAM_NO_REMIX_CHANNELSPA_STREAM_NO_REMIX_CHANNELS : 0) |
1054 | , volume_set ? &cvol : NULL((void*)0), NULL((void*)0)) < 0) { |
1055 | ret = translate_error(pa_context_errno(p->context)); |
1056 | goto finish_locked; |
1057 | } |
1058 | |
1059 | for (;;) { |
1060 | pa_stream_state_t state; |
1061 | |
1062 | if (!p->context || !out->stream) { |
1063 | ret = KA_ERROR_STATE; |
1064 | goto finish_locked; |
1065 | } |
1066 | |
1067 | state = pa_stream_get_state(out->stream); |
1068 | |
1069 | /* Stream sucessfully created */ |
1070 | if (state == PA_STREAM_READYPA_STREAM_READY) |
1071 | break; |
1072 | |
1073 | /* Check for failure */ |
1074 | if (state == PA_STREAM_FAILEDPA_STREAM_FAILED) { |
1075 | ret = translate_error(pa_context_errno(p->context)); |
1076 | goto finish_locked; |
1077 | } |
1078 | |
1079 | /* Prematurely ended */ |
1080 | if (state == PA_STREAM_TERMINATEDPA_STREAM_TERMINATED) { |
1081 | ret = out->error; |
1082 | goto finish_locked; |
1083 | } |
1084 | |
1085 | pa_threaded_mainloop_wait(p->mainloop); |
1086 | } |
1087 | |
1088 | ret = KA_SUCCESS; |
1089 | |
1090 | finish_locked: |
1091 | |
1092 | /* We keep the outstanding struct around to clean up later if the sound din't finish yet*/ |
1093 | if (ret == KA_SUCCESS && !out->finished) { |
1094 | out->clean_up = TRUE(!(0)); |
1095 | |
1096 | ka_mutex_lock(p->outstanding_mutex); |
1097 | 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" , "pulse.c", 1097, __PRETTY_FUNCTION__); abort(); } } while ((0)); if ((_item->next = *_head)) _item->next ->prev = _item; _item->prev = ((void*)0); *_head = _item ; } while (0); |
1098 | ka_mutex_unlock(p->outstanding_mutex); |
1099 | } else |
1100 | outstanding_free(out); |
1101 | |
1102 | out = NULL((void*)0); |
1103 | |
1104 | pa_threaded_mainloop_unlock(p->mainloop); |
1105 | |
1106 | finish_unlocked: |
1107 | |
1108 | if (out) |
1109 | outstanding_free(out); |
1110 | |
1111 | if (l) |
1112 | pa_proplist_free(l); |
1113 | |
1114 | ka_freefree(name); |
1115 | |
1116 | return ret; |
1117 | } |
1118 | |
1119 | int driver_cancelpulse_driver_cancel(ka_context *c, uint32_t id) { |
1120 | struct private *p; |
1121 | pa_operation *o; |
1122 | int ret = KA_SUCCESS; |
1123 | struct outstanding *out, *n; |
1124 | |
1125 | 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" , "pulse.c", 1125, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
1126 | 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" , "pulse.c", 1126, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
1127 | |
1128 | p = PRIVATE(c)((struct private *) ((c)->private)); |
1129 | |
1130 | ka_return_val_if_fail(p->mainloop, KA_ERROR_STATE)do { if ((__builtin_expect((!(p->mainloop)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "p->mainloop" , "pulse.c", 1130, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
1131 | |
1132 | pa_threaded_mainloop_lock(p->mainloop); |
1133 | |
1134 | if (!p->context) { |
1135 | pa_threaded_mainloop_unlock(p->mainloop); |
1136 | return KA_ERROR_STATE; |
1137 | } |
1138 | |
1139 | ka_mutex_lock(p->outstanding_mutex); |
1140 | |
1141 | /* We start these asynchronously and don't care about the return |
1142 | * value */ |
1143 | |
1144 | for (out = p->outstanding; out; out = n) { |
1145 | int ret2 = KA_SUCCESS; |
1146 | n = out->next; |
1147 | |
1148 | if (out->type == OUTSTANDING_UPLOAD || |
1149 | out->id != id || |
1150 | out->sink_input == PA_INVALID_INDEX((uint32_t) -1)) |
1151 | continue; |
1152 | |
1153 | if (!(o = pa_context_kill_sink_input(p->context, out->sink_input, NULL((void*)0), NULL((void*)0)))) |
1154 | ret2 = translate_error(pa_context_errno(p->context)); |
1155 | else |
1156 | pa_operation_unref(o); |
1157 | |
1158 | /* We make sure here to kill all streams identified by the id |
1159 | * here. However, we will return only the first error we |
1160 | * encounter */ |
1161 | |
1162 | if (ret2 && ret == KA_SUCCESS) |
1163 | ret = ret2; |
1164 | |
1165 | if (out->callback) |
1166 | out->callback(c, out->id, KA_ERROR_CANCELED, out->userdata); |
1167 | |
1168 | outstanding_disconnect(out); |
1169 | 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" , "pulse.c", 1169, __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" , "pulse.c", 1169, __PRETTY_FUNCTION__); abort (); } } while ((0)); *_head = _item->next; } _item->next = _item->prev = ((void*)0); } while(0); |
1170 | outstanding_free(out); |
1171 | } |
1172 | |
1173 | ka_mutex_unlock(p->outstanding_mutex); |
1174 | |
1175 | pa_threaded_mainloop_unlock(p->mainloop); |
1176 | |
1177 | return ret; |
1178 | } |
1179 | |
1180 | int driver_cachepulse_driver_cache(ka_context *c, ka_proplist *proplist) { |
1181 | struct private *p; |
1182 | pa_proplist *l = NULL((void*)0); |
1183 | const char *n, *ct; |
1184 | pa_sample_spec ss; |
1185 | pa_channel_map cm; |
1186 | ka_bool_t cm_good; |
1187 | ka_cache_control_t cache_control = KA_CACHE_CONTROL_PERMANENT; |
1188 | struct outstanding *out; |
1189 | int ret; |
1190 | char *sp; |
1191 | |
1192 | 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" , "pulse.c", 1192, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
1193 | 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" , "pulse.c", 1193, __PRETTY_FUNCTION__); return ( KA_ERROR_INVALID); } } while((0)); |
1194 | 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" , "pulse.c", 1194, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
1195 | |
1196 | p = PRIVATE(c)((struct private *) ((c)->private)); |
1197 | |
1198 | ka_return_val_if_fail(p->mainloop, KA_ERROR_STATE)do { if ((__builtin_expect((!(p->mainloop)),0))) { if (ka_debug ()) fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n" , "p->mainloop" , "pulse.c", 1198, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
1199 | |
1200 | if (!(out = ka_new0(struct outstanding, 1)((struct outstanding*) calloc(1, (sizeof(struct outstanding)* (1)))))) { |
1201 | ret = KA_ERROR_OOM; |
1202 | goto finish_unlocked; |
1203 | } |
1204 | |
1205 | out->type = OUTSTANDING_UPLOAD; |
1206 | out->context = c; |
1207 | out->sink_input = PA_INVALID_INDEX((uint32_t) -1); |
1208 | |
1209 | if ((ret = convert_proplist(&l, proplist)) < 0) |
1210 | goto finish_unlocked; |
1211 | |
1212 | if (!(n = pa_proplist_gets(l, KA_PROP_EVENT_ID"event.id"))) { |
1213 | ret = KA_ERROR_INVALID; |
1214 | goto finish_unlocked; |
1215 | } |
1216 | |
1217 | if ((ct = pa_proplist_gets(l, KA_PROP_KANBERRA_CACHE_CONTROL"kanberra.cache-control"))) |
1218 | if ((ret = ka_parse_cache_control(&cache_control, ct)) < 0) { |
1219 | ret = KA_ERROR_INVALID; |
1220 | goto finish_unlocked; |
1221 | } |
1222 | |
1223 | if (cache_control != KA_CACHE_CONTROL_PERMANENT) { |
1224 | ret = KA_ERROR_INVALID; |
1225 | goto finish_unlocked; |
1226 | } |
1227 | |
1228 | if ((ct = pa_proplist_gets(l, KA_PROP_KANBERRA_FORCE_CHANNEL"kanberra.force_channel"))) { |
Although the value stored to 'ct' is used in the enclosing expression, the value is never actually read from 'ct' | |
1229 | ret = KA_ERROR_NOTSUPPORTED; |
1230 | goto finish_unlocked; |
1231 | } |
1232 | |
1233 | strip_prefix(l, "kanberra."); |
1234 | strip_prefix(l, "event.mouse."); |
1235 | strip_prefix(l, "window."); |
1236 | add_common(l); |
1237 | |
1238 | /* Let's stream the sample directly */ |
1239 | if ((ret = ka_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0) |
1240 | goto finish_unlocked; |
1241 | |
1242 | if (sp) |
1243 | if (!pa_proplist_contains(l, KA_PROP_MEDIA_FILENAME"media.filename")) |
1244 | pa_proplist_sets(l, KA_PROP_MEDIA_FILENAME"media.filename", sp); |
1245 | |
1246 | ka_freefree(sp); |
1247 | |
1248 | ss.format = sample_type_table[ka_sound_file_get_sample_type(out->file)]; |
1249 | ss.channels = (uint8_t) ka_sound_file_get_nchannels(out->file); |
1250 | ss.rate = ka_sound_file_get_rate(out->file); |
1251 | |
1252 | cm_good = convert_channel_map(out->file, &cm); |
1253 | |
1254 | pa_threaded_mainloop_lock(p->mainloop); |
1255 | |
1256 | if (!p->context) { |
1257 | ret = KA_ERROR_STATE; |
1258 | goto finish_locked; |
1259 | } |
1260 | |
1261 | if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL((void*)0), &ss, cm_good ? &cm : NULL((void*)0), l))) { |
1262 | ret = translate_error(pa_context_errno(p->context)); |
1263 | goto finish_locked; |
1264 | } |
1265 | |
1266 | pa_stream_set_state_callback(out->stream, stream_state_cb, out); |
1267 | pa_stream_set_write_callback(out->stream, stream_write_cb, out); |
1268 | |
1269 | if (pa_stream_connect_upload(out->stream, (size_t) ka_sound_file_get_size(out->file)) < 0) { |
1270 | ret = translate_error(pa_context_errno(p->context)); |
1271 | goto finish_locked; |
1272 | } |
1273 | |
1274 | for (;;) { |
1275 | pa_stream_state_t state; |
1276 | |
1277 | if (!p->context || !out->stream) { |
1278 | ret = KA_ERROR_STATE; |
1279 | goto finish_locked; |
1280 | } |
1281 | |
1282 | state = pa_stream_get_state(out->stream); |
1283 | |
1284 | /* Stream sucessfully created and uploaded */ |
1285 | if (state == PA_STREAM_TERMINATEDPA_STREAM_TERMINATED) |
1286 | break; |
1287 | |
1288 | /* Check for failure */ |
1289 | if (state == PA_STREAM_FAILEDPA_STREAM_FAILED) { |
1290 | ret = translate_error(pa_context_errno(p->context)); |
1291 | goto finish_locked; |
1292 | } |
1293 | |
1294 | pa_threaded_mainloop_wait(p->mainloop); |
1295 | } |
1296 | |
1297 | ret = KA_SUCCESS; |
1298 | |
1299 | finish_locked: |
1300 | outstanding_free(out); |
1301 | out = NULL((void*)0); |
1302 | |
1303 | pa_threaded_mainloop_unlock(p->mainloop); |
1304 | |
1305 | finish_unlocked: |
1306 | |
1307 | if (out) |
1308 | outstanding_free(out); |
1309 | |
1310 | if (l) |
1311 | pa_proplist_free(l); |
1312 | |
1313 | return ret; |
1314 | } |
1315 | |
1316 | int driver_playing(ka_context *c, uint32_t id, int *playing) { |
1317 | struct private *p; |
1318 | struct outstanding *out; |
1319 | |
1320 | 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" , "pulse.c", 1320, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID ); } } while((0)); |
1321 | 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" , "pulse.c", 1321, __PRETTY_FUNCTION__); return (KA_ERROR_STATE); } } while((0)); |
1322 | 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" , "pulse.c", 1322, __PRETTY_FUNCTION__); return ( KA_ERROR_INVALID); } } while((0)); |
1323 | |
1324 | p = PRIVATE(c)((struct private *) ((c)->private)); |
1325 | |
1326 | *playing = 0; |
1327 | |
1328 | ka_mutex_lock(p->outstanding_mutex); |
1329 | |
1330 | for (out = p->outstanding; out; out = out->next) { |
1331 | |
1332 | if (out->type == OUTSTANDING_UPLOAD || |
1333 | out->id != id || |
1334 | out->sink_input == PA_INVALID_INDEX((uint32_t) -1)) |
1335 | continue; |
1336 | |
1337 | *playing = 1; |
1338 | break; |
1339 | } |
1340 | |
1341 | ka_mutex_unlock(p->outstanding_mutex); |
1342 | |
1343 | return KA_SUCCESS; |
1344 | } |