Bug Summary

File:pulse.c
Warning:line 1214, column 15
Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name pulse.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -D _REENTRANT -D driver_open=pulse_driver_open -D driver_destroy=pulse_driver_destroy -D driver_change_device=pulse_driver_change_device -D driver_change_props=pulse_driver_change_props -D driver_play=pulse_driver_play -D driver_cancel=pulse_driver_cancel -D driver_cache=pulse_driver_cache -D PIC -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-04-17-151222-19626-1 -x c pulse.c
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3/***
4 This file is part of libkanberra.
5
6 Copyright 2008 Lennart Poettering
7
8 libkanberra is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation, either version 2.1 of the
11 License, or (at your option) any later version.
12
13 libkanberra is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with libkanberra. If not, see
20 <http://www.gnu.org/licenses/>.
21***/
22
23#ifdef HAVE_CONFIG_H1
24#include <config.h>
25#endif
26
27/* 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
49enum outstanding_type {
50 OUTSTANDING_SAMPLE,
51 OUTSTANDING_STREAM,
52 OUTSTANDING_UPLOAD
53};
54
55struct 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
71struct 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
84static void context_state_cb(pa_context *pc, void *userdata);
85static void context_subscribe_cb(pa_context *pc, pa_subscription_event_type_t t, uint32_t idx, void *userdata);
86
87static 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
105static 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
116static 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
142static 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
154static 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
172static 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
218static 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"1.0");
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
270static 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
332static 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
376int 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
444int 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
486int driver_change_devicepulse_driver_change_device (ka_context *c,
487 const char *device GNUC_UNUSED__attribute__ ((__unused__)))
488{
489 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", 489, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
490 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", 490, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
491
492 /* We're happy with any device change. We might however add code
493 * here eventually to move all currently played back event sounds
494 * to the new device. */
495
496 return KA_SUCCESS;
497}
498
499int driver_change_propspulse_driver_change_props(ka_context *c, ka_proplist *changed, ka_proplist *merged) {
500 struct private *p;
501 pa_operation *o;
502 pa_proplist *l;
503 int ret = KA_SUCCESS;
504
505 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", 505, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
506 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", 506, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
507 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", 507, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
508 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", 508, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
509
510 p = PRIVATE(c)((struct private *) ((c)->private));
511
512 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", 512, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
513
514 pa_threaded_mainloop_lock(p->mainloop);
515
516 if (!p->context) {
517 pa_threaded_mainloop_unlock(p->mainloop);
518 return KA_ERROR_STATE; /* can be silently ignored */
519 }
520
521 if ((ret = convert_proplist(&l, changed)) < 0)
522 return ret;
523
524 strip_prefix(l, "kanberra.");
525
526 /* We start these asynchronously and don't care about the return
527 * value */
528
529 if (!(o = pa_context_proplist_update(p->context, PA_UPDATE_REPLACEPA_UPDATE_REPLACE, l, NULL((void*)0), NULL((void*)0))))
530 ret = translate_error(pa_context_errno(p->context));
531 else
532 pa_operation_unref(o);
533
534 pa_threaded_mainloop_unlock(p->mainloop);
535
536 pa_proplist_free(l);
537
538 return ret;
539}
540
541static int subscribe(ka_context *c) {
542 struct private *p;
543 pa_operation *o;
544 int ret = KA_SUCCESS;
545
546 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", 546, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
547 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", 547, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
548 p = PRIVATE(c)((struct private *) ((c)->private));
549
550 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", 550, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
551
552 if (p->subscribed)
553 return KA_SUCCESS;
554
555 pa_threaded_mainloop_lock(p->mainloop);
556
557 if (!p->context) {
558 pa_threaded_mainloop_unlock(p->mainloop);
559 return KA_ERROR_STATE;
560 }
561
562 /* We start these asynchronously and don't care about the return
563 * value */
564
565 if (!(o = pa_context_subscribe(p->context, PA_SUBSCRIPTION_MASK_SINK_INPUTPA_SUBSCRIPTION_MASK_SINK_INPUT, NULL((void*)0), NULL((void*)0))))
566 ret = translate_error(pa_context_errno(p->context));
567 else
568 pa_operation_unref(o);
569
570 pa_threaded_mainloop_unlock(p->mainloop);
571
572 p->subscribed = TRUE(!(0));
573
574 return ret;
575}
576
577static void play_sample_cb(pa_context *c, uint32_t idx, void *userdata) {
578 struct private *p;
579 struct outstanding *out = userdata;
580
581 ka_assert(c)do { if ((__builtin_expect((!(c)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "c" , "pulse.c", 581, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
582 ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "out" , "pulse.c", 582, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
583
584 p = PRIVATE(out->context)((struct private *) ((out->context)->private));
585
586 if (idx != PA_INVALID_INDEX((uint32_t) -1)) {
587 out->error = KA_SUCCESS;
588 out->sink_input = idx;
589 } else
590 out->error = translate_error(pa_context_errno(c));
591
592 pa_threaded_mainloop_signal(p->mainloop, FALSE(0));
593}
594
595static void stream_state_cb(pa_stream *s, void *userdata) {
596 struct private *p;
597 struct outstanding *out = userdata;
598 pa_stream_state_t state;
599
600 ka_assert(s)do { if ((__builtin_expect((!(s)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "s" , "pulse.c", 600, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
601 ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "out" , "pulse.c", 601, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
602
603 p = PRIVATE(out->context)((struct private *) ((out->context)->private));
604
605 state = pa_stream_get_state(s);
606
607 switch (state) {
608 case PA_STREAM_CREATINGPA_STREAM_CREATING:
609 case PA_STREAM_UNCONNECTEDPA_STREAM_UNCONNECTED:
610 break;
611
612 case PA_STREAM_READYPA_STREAM_READY:
613 out->sink_input = pa_stream_get_index(out->stream);
614 break;
615
616 case PA_STREAM_FAILEDPA_STREAM_FAILED:
617 case PA_STREAM_TERMINATEDPA_STREAM_TERMINATED: {
618 int err;
619
620 err = state == PA_STREAM_FAILEDPA_STREAM_FAILED ? translate_error(pa_context_errno(pa_stream_get_context(s))) : KA_ERROR_DESTROYED;
621
622 if (out->clean_up) {
623 ka_mutex_lock(p->outstanding_mutex);
624 outstanding_disconnect(out);
625 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", 625, __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", 625, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
626 ka_mutex_unlock(p->outstanding_mutex);
627
628 if (out->callback)
629 out->callback(out->context, out->id, out->error, out->userdata);
630
631 outstanding_free(out);
632 } else {
633 out->finished = TRUE(!(0));
634 out->error = err;
635 }
636
637 break;
638 }
639 }
640
641 pa_threaded_mainloop_signal(p->mainloop, FALSE(0));
642}
643
644static void stream_drain_cb(pa_stream *s, int success, void *userdata) {
645 struct private *p;
646 struct outstanding *out = userdata;
647 int err;
648
649 ka_assert(s)do { if ((__builtin_expect((!(s)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "s" , "pulse.c", 649, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
650 ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "out" , "pulse.c", 650, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
651 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", 651, __PRETTY_FUNCTION__
); abort(); } } while ((0))
;
652
653 p = PRIVATE(out->context)((struct private *) ((out->context)->private));
654 err = success ? KA_SUCCESS : translate_error(pa_context_errno(p->context));
655
656 if (out->clean_up) {
657 ka_mutex_lock(p->outstanding_mutex);
658 outstanding_disconnect(out);
659 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", 659, __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", 659, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
660 ka_mutex_unlock(p->outstanding_mutex);
661
662 if (out->callback)
663 out->callback(out->context, out->id, err, out->userdata);
664
665 outstanding_free(out);
666
667 } else {
668 pa_stream_disconnect(s);
669 out->error = err;
670 out->finished = TRUE(!(0));
671
672 if (out->drain_operation) {
673 pa_operation_unref(out->drain_operation);
674 out->drain_operation = NULL((void*)0);
675 }
676 }
677
678 pa_threaded_mainloop_signal(p->mainloop, FALSE(0));
679}
680
681static void stream_write_cb(pa_stream *s, size_t bytes, void *userdata) {
682 struct outstanding *out = userdata;
683 struct private *p;
684 void *data;
685 int ret;
686 ka_bool_t eof = FALSE(0);
687
688 ka_assert(s)do { if ((__builtin_expect((!(s)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "s" , "pulse.c", 688, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
689 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", 689, __PRETTY_FUNCTION__); abort
(); } } while ((0))
;
690 ka_assert(out)do { if ((__builtin_expect((!(out)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "out" , "pulse.c", 690, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
691
692 p = PRIVATE(out->context)((struct private *) ((out->context)->private));
693
694 while (bytes > 0) {
695 size_t rbytes = bytes;
696
697 if (!(data = ka_mallocmalloc(rbytes))) {
698 ret = KA_ERROR_OOM;
699 goto finish;
700 }
701
702 if ((ret = ka_sound_file_read_arbitrary(out->file, data, &rbytes)) < 0)
703 goto finish;
704
705 if (rbytes <= 0) {
706 eof = TRUE(!(0));
707 break;
708 }
709
710 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", 710, __PRETTY_FUNCTION__)
; abort(); } } while ((0))
;
711
712 if ((ret = pa_stream_write(s, data, rbytes, ka_freefree, 0, PA_SEEK_RELATIVEPA_SEEK_RELATIVE)) < 0) {
713 ret = translate_error(ret);
714 goto finish;
715 }
716
717 data = NULL((void*)0);
718
719 bytes -= rbytes;
720 }
721
722 if (eof || ka_sound_file_get_size(out->file) <= 0) {
723
724 /* We reached EOF */
725
726 if (out->type == OUTSTANDING_UPLOAD) {
727
728 if (pa_stream_finish_upload(s) < 0) {
729 ret = translate_error(pa_context_errno(p->context));
730 goto finish;
731 }
732
733 /* Let's just signal driver_cache() which has been waiting for us */
734 pa_threaded_mainloop_signal(p->mainloop, FALSE(0));
735
736 } else {
737 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", 737, __PRETTY_FUNCTION__
); abort(); } } while ((0))
;
738
739 if (out->drain_operation) {
740 pa_operation_cancel(out->drain_operation);
741 pa_operation_unref(out->drain_operation);
742 }
743
744 if (!(out->drain_operation = pa_stream_drain(s, stream_drain_cb, out))) {
745 ret = translate_error(pa_context_errno(p->context));
746 goto finish;
747 }
748 }
749
750 pa_stream_set_write_callback(s, NULL((void*)0), NULL((void*)0));
751 }
752
753 ka_freefree(data);
754
755 return;
756
757finish:
758
759 ka_freefree(data);
760
761 if (out->clean_up) {
762 ka_mutex_lock(p->outstanding_mutex);
763 outstanding_disconnect(out);
764 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", 764, __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", 764, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
765 ka_mutex_unlock(p->outstanding_mutex);
766
767 if (out->callback)
768 out->callback(out->context, out->id, ret, out->userdata);
769
770 outstanding_free(out);
771
772 } else {
773 pa_stream_disconnect(s);
774 out->error = ret;
775 out->finished = TRUE(!(0));
776 }
777
778 pa_threaded_mainloop_signal(p->mainloop, FALSE(0));
779}
780
781static const pa_sample_format_t sample_type_table[] = {
782 [KA_SAMPLE_S16NE] = PA_SAMPLE_S16NEPA_SAMPLE_S16LE,
783 [KA_SAMPLE_S16RE] = PA_SAMPLE_S16REPA_SAMPLE_S16BE,
784 [KA_SAMPLE_U8] = PA_SAMPLE_U8PA_SAMPLE_U8
785};
786
787static const pa_channel_position_t channel_table[_KA_CHANNEL_POSITION_MAX] = {
788 [KA_CHANNEL_MONO] = PA_CHANNEL_POSITION_MONOPA_CHANNEL_POSITION_MONO,
789 [KA_CHANNEL_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFTPA_CHANNEL_POSITION_FRONT_LEFT,
790 [KA_CHANNEL_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHTPA_CHANNEL_POSITION_FRONT_RIGHT,
791 [KA_CHANNEL_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTERPA_CHANNEL_POSITION_FRONT_CENTER,
792 [KA_CHANNEL_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFTPA_CHANNEL_POSITION_REAR_LEFT,
793 [KA_CHANNEL_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHTPA_CHANNEL_POSITION_REAR_RIGHT,
794 [KA_CHANNEL_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTERPA_CHANNEL_POSITION_REAR_CENTER,
795 [KA_CHANNEL_LFE] = PA_CHANNEL_POSITION_LFEPA_CHANNEL_POSITION_LFE,
796 [KA_CHANNEL_FRONT_LEFT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTERPA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
797 [KA_CHANNEL_FRONT_RIGHT_OF_CENTER] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTERPA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
798 [KA_CHANNEL_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFTPA_CHANNEL_POSITION_SIDE_LEFT,
799 [KA_CHANNEL_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHTPA_CHANNEL_POSITION_SIDE_RIGHT,
800 [KA_CHANNEL_TOP_CENTER] = PA_CHANNEL_POSITION_TOP_CENTERPA_CHANNEL_POSITION_TOP_CENTER,
801 [KA_CHANNEL_TOP_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFTPA_CHANNEL_POSITION_FRONT_LEFT,
802 [KA_CHANNEL_TOP_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHTPA_CHANNEL_POSITION_FRONT_RIGHT,
803 [KA_CHANNEL_TOP_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTERPA_CHANNEL_POSITION_FRONT_CENTER,
804 [KA_CHANNEL_TOP_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFTPA_CHANNEL_POSITION_REAR_LEFT,
805 [KA_CHANNEL_TOP_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHTPA_CHANNEL_POSITION_REAR_RIGHT,
806 [KA_CHANNEL_TOP_REAR_CENTER] = PA_CHANNEL_POSITION_TOP_REAR_CENTERPA_CHANNEL_POSITION_TOP_REAR_CENTER
807};
808
809static ka_bool_t convert_channel_map(ka_sound_file *f, pa_channel_map *cm) {
810 const ka_channel_position_t *positions;
811 unsigned c;
812
813 ka_assert(f)do { if ((__builtin_expect((!(f)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "f" , "pulse.c", 813, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
814 ka_assert(cm)do { if ((__builtin_expect((!(cm)),0))) { fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n"
, "cm" , "pulse.c", 814, __PRETTY_FUNCTION__); abort(); } } while
((0))
;
815
816 if (!(positions = ka_sound_file_get_channel_map(f)))
817 return FALSE(0);
818
819 cm->channels = ka_sound_file_get_nchannels(f);
820 for (c = 0; c < cm->channels; c++)
821 cm->map[c] = channel_table[positions[c]];
822
823 return TRUE(!(0));
824}
825
826int driver_playpulse_driver_play(ka_context *c, uint32_t id, ka_proplist *proplist, ka_finish_callback_t cb, void *userdata) {
827 struct private *p;
828 pa_proplist *l = NULL((void*)0);
829 const char *n, *vol, *ct, *channel;
830 char *name = NULL((void*)0);
831#if defined(PA_MAJOR17) && ((PA_MAJOR17 > 0) || (PA_MAJOR17 == 0 && PA_MINOR0 > 9) || (PA_MAJOR17 == 0 && PA_MINOR0 == 9 && PA_MICRO0 >= 15))
832 pa_volume_t v = (pa_volume_t) -1;
833#else
834 pa_volume_t v = PA_VOLUME_NORM((pa_volume_t) 0x10000U);
835#endif
836 ka_bool_t volume_set = FALSE(0);
837 pa_cvolume cvol;
838 pa_sample_spec ss;
839 pa_channel_map cm;
840 pa_channel_position_t position = PA_CHANNEL_POSITION_INVALIDPA_CHANNEL_POSITION_INVALID;
841 ka_bool_t cm_good;
842 ka_cache_control_t cache_control = KA_CACHE_CONTROL_NEVER;
843 struct outstanding *out = NULL((void*)0);
844 int try = 3;
845 int ret;
846 pa_operation *o;
847 char *sp;
848 pa_buffer_attr ba;
849
850 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", 850, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
851 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", 851, __PRETTY_FUNCTION__); return (
KA_ERROR_INVALID); } } while((0))
;
852 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", 852, __PRETTY_FUNCTION__); return
(KA_ERROR_INVALID); } } while((0))
;
853 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", 853, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
854
855 p = PRIVATE(c)((struct private *) ((c)->private));
856
857 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", 857, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
858
859 if (!(out = ka_new0(struct outstanding, 1)((struct outstanding*) calloc(1, (sizeof(struct outstanding)*
(1))))
)) {
860 ret = KA_ERROR_OOM;
861 goto finish_unlocked;
862 }
863
864 out->type = OUTSTANDING_SAMPLE;
865 out->context = c;
866 out->sink_input = PA_INVALID_INDEX((uint32_t) -1);
867 out->id = id;
868 out->callback = cb;
869 out->userdata = userdata;
870
871 if ((ret = convert_proplist(&l, proplist)) < 0)
872 goto finish_unlocked;
873
874 if ((n = pa_proplist_gets(l, KA_PROP_EVENT_ID"event.id")))
875 if (!(name = ka_strdupstrdup(n))) {
876 ret = KA_ERROR_OOM;
877 goto finish_unlocked;
878 }
879
880 if ((vol = pa_proplist_gets(l, KA_PROP_KANBERRA_VOLUME"kanberra.volume"))) {
881 char *e = NULL((void*)0);
882 double dvol;
883
884 errno(*__errno_location ()) = 0;
885 dvol = strtod(vol, &e);
886 if (errno(*__errno_location ()) != 0 || !e || *e) {
887 ret = KA_ERROR_INVALID;
888 goto finish_unlocked;
889 }
890
891 v = pa_sw_volume_from_dB(dvol);
892 volume_set = TRUE(!(0));
893 }
894
895 if ((ct = pa_proplist_gets(l, KA_PROP_KANBERRA_CACHE_CONTROL"kanberra.cache-control")))
896 if ((ret = ka_parse_cache_control(&cache_control, ct)) < 0) {
897 ret = KA_ERROR_INVALID;
898 goto finish_unlocked;
899 }
900
901 if ((channel = pa_proplist_gets(l, KA_PROP_KANBERRA_FORCE_CHANNEL"kanberra.force_channel"))) {
902 pa_channel_map t;
903
904 if (!pa_channel_map_parse(&t, channel) ||
905 t.channels != 1) {
906 ret = KA_ERROR_INVALID;
907 goto finish_unlocked;
908 }
909
910 position = t.map[0];
911
912 /* We cannot remap cached samples, so let's fail when cacheing
913 * shall be used */
914 if (cache_control != KA_CACHE_CONTROL_NEVER) {
915 ret = KA_ERROR_NOTSUPPORTED;
916 goto finish_unlocked;
917 }
918 }
919
920 strip_prefix(l, "kanberra.");
921 add_common(l);
922
923 if ((ret = subscribe(c)) < 0)
924 goto finish_unlocked;
925
926 if (name && cache_control != KA_CACHE_CONTROL_NEVER) {
927
928 /* Ok, this sample has an event id, let's try to play it from the cache */
929
930 for (;;) {
931 ka_bool_t canceled;
932
933 pa_threaded_mainloop_lock(p->mainloop);
934
935 if (!p->context) {
936 ret = KA_ERROR_STATE;
937 goto finish_locked;
938 }
939
940 /* Let's try to play the sample */
941 if (!(o = pa_context_play_sample_with_proplist(p->context, name, c->device, v, l, play_sample_cb, out))) {
942 ret = translate_error(pa_context_errno(p->context));
943 goto finish_locked;
944 }
945
946 for (;;) {
947 pa_operation_state_t state = pa_operation_get_state(o);
948
949 if (state == PA_OPERATION_DONEPA_OPERATION_DONE) {
950 canceled = FALSE(0);
951 break;
952 } else if (state == PA_OPERATION_CANCELEDPA_OPERATION_CANCELLED) {
953 canceled = TRUE(!(0));
954 break;
955 }
956
957 pa_threaded_mainloop_wait(p->mainloop);
958 }
959
960 pa_operation_unref(o);
961
962 if (!canceled && p->context && out->error == KA_SUCCESS) {
963 ret = KA_SUCCESS;
964 goto finish_locked;
965 }
966
967 pa_threaded_mainloop_unlock(p->mainloop);
968
969 /* The operation might have been canceled due to connection termination */
970 if (canceled || !p->context) {
971 ret = KA_ERROR_DISCONNECTED;
972 goto finish_unlocked;
973 }
974
975 /* Did some other error occur? */
976 if (out->error != KA_ERROR_NOTFOUND) {
977 ret = out->error;
978 goto finish_unlocked;
979 }
980
981 /* Hmm, we need to play it directly */
982 if (cache_control != KA_CACHE_CONTROL_PERMANENT)
983 break;
984
985 /* Don't loop forever */
986 if (--try <= 0)
987 break;
988
989 /* Let's upload the sample and retry playing */
990 if ((ret = driver_cachepulse_driver_cache(c, proplist)) < 0)
991 goto finish_unlocked;
992 }
993 }
994
995 out->type = OUTSTANDING_STREAM;
996
997 /* Let's stream the sample directly */
998 if ((ret = ka_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0)
999 goto finish_unlocked;
1000
1001 if (sp)
1002 if (!pa_proplist_contains(l, KA_PROP_MEDIA_FILENAME"media.filename"))
1003 pa_proplist_sets(l, KA_PROP_MEDIA_FILENAME"media.filename", sp);
1004
1005 ka_freefree(sp);
1006
1007 ss.format = sample_type_table[ka_sound_file_get_sample_type(out->file)];
1008 ss.channels = (uint8_t) ka_sound_file_get_nchannels(out->file);
1009 ss.rate = ka_sound_file_get_rate(out->file);
1010
1011 if (position != PA_CHANNEL_POSITION_INVALIDPA_CHANNEL_POSITION_INVALID) {
1012 unsigned u;
1013 /* Apply kanberra.force_channel */
1014
1015 cm.channels = ss.channels;
1016 for (u = 0; u < cm.channels; u++)
1017 cm.map[u] = position;
1018
1019 cm_good = TRUE(!(0));
1020 } else
1021 cm_good = convert_channel_map(out->file, &cm);
1022
1023 pa_threaded_mainloop_lock(p->mainloop);
1024
1025 if (!p->context) {
1026 ret = KA_ERROR_STATE;
1027 goto finish_locked;
1028 }
1029
1030 if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL((void*)0), &ss, cm_good ? &cm : NULL((void*)0), l))) {
1031 ret = translate_error(pa_context_errno(p->context));
1032 goto finish_locked;
1033 }
1034
1035 pa_stream_set_state_callback(out->stream, stream_state_cb, out);
1036 pa_stream_set_write_callback(out->stream, stream_write_cb, out);
1037
1038 if (volume_set)
1039 pa_cvolume_set(&cvol, ss.channels, v);
1040
1041 /* Make sure we get the longest latency possible, to minimize CPU
1042 * consumption */
1043 ba.maxlength = (uint32_t) -1;
1044 ba.tlength = (uint32_t) -1;
1045 ba.prebuf = (uint32_t) -1;
1046 ba.minreq = (uint32_t) -1;
1047 ba.fragsize = (uint32_t) -1;
1048
1049 if (pa_stream_connect_playback(out->stream, c->device, &ba,
1050#ifdef PA_STREAM_FAIL_ON_SUSPENDPA_STREAM_FAIL_ON_SUSPEND
1051 PA_STREAM_FAIL_ON_SUSPENDPA_STREAM_FAIL_ON_SUSPEND
1052#else
1053 0
1054#endif
1055 | (position != PA_CHANNEL_POSITION_INVALIDPA_CHANNEL_POSITION_INVALID ? PA_STREAM_NO_REMIX_CHANNELSPA_STREAM_NO_REMIX_CHANNELS : 0)
1056 , volume_set ? &cvol : NULL((void*)0), NULL((void*)0)) < 0) {
1057 ret = translate_error(pa_context_errno(p->context));
1058 goto finish_locked;
1059 }
1060
1061 for (;;) {
1062 pa_stream_state_t state;
1063
1064 if (!p->context || !out->stream) {
1065 ret = KA_ERROR_STATE;
1066 goto finish_locked;
1067 }
1068
1069 state = pa_stream_get_state(out->stream);
1070
1071 /* Stream sucessfully created */
1072 if (state == PA_STREAM_READYPA_STREAM_READY)
1073 break;
1074
1075 /* Check for failure */
1076 if (state == PA_STREAM_FAILEDPA_STREAM_FAILED) {
1077 ret = translate_error(pa_context_errno(p->context));
1078 goto finish_locked;
1079 }
1080
1081 /* Prematurely ended */
1082 if (state == PA_STREAM_TERMINATEDPA_STREAM_TERMINATED) {
1083 ret = out->error;
1084 goto finish_locked;
1085 }
1086
1087 pa_threaded_mainloop_wait(p->mainloop);
1088 }
1089
1090 ret = KA_SUCCESS;
1091
1092finish_locked:
1093
1094 /* We keep the outstanding struct around to clean up later if the sound din't finish yet*/
1095 if (ret == KA_SUCCESS && !out->finished) {
1096 out->clean_up = TRUE(!(0));
1097
1098 ka_mutex_lock(p->outstanding_mutex);
1099 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", 1099, __PRETTY_FUNCTION__); abort(); }
} while ((0)); if ((_item->next = *_head)) _item->next
->prev = _item; _item->prev = ((void*)0); *_head = _item
; } while (0)
;
1100 ka_mutex_unlock(p->outstanding_mutex);
1101 } else
1102 outstanding_free(out);
1103
1104 out = NULL((void*)0);
1105
1106 pa_threaded_mainloop_unlock(p->mainloop);
1107
1108finish_unlocked:
1109
1110 if (out)
1111 outstanding_free(out);
1112
1113 if (l)
1114 pa_proplist_free(l);
1115
1116 ka_freefree(name);
1117
1118 return ret;
1119}
1120
1121int driver_cancelpulse_driver_cancel(ka_context *c, uint32_t id) {
1122 struct private *p;
1123 pa_operation *o;
1124 int ret = KA_SUCCESS;
1125 struct outstanding *out, *n;
1126
1127 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", 1127, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
1128 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", 1128, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
1129
1130 p = PRIVATE(c)((struct private *) ((c)->private));
1131
1132 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", 1132, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
1133
1134 pa_threaded_mainloop_lock(p->mainloop);
1135
1136 if (!p->context) {
1137 pa_threaded_mainloop_unlock(p->mainloop);
1138 return KA_ERROR_STATE;
1139 }
1140
1141 ka_mutex_lock(p->outstanding_mutex);
1142
1143 /* We start these asynchronously and don't care about the return
1144 * value */
1145
1146 for (out = p->outstanding; out; out = n) {
1147 int ret2 = KA_SUCCESS;
1148 n = out->next;
1149
1150 if (out->type == OUTSTANDING_UPLOAD ||
1151 out->id != id ||
1152 out->sink_input == PA_INVALID_INDEX((uint32_t) -1))
1153 continue;
1154
1155 if (!(o = pa_context_kill_sink_input(p->context, out->sink_input, NULL((void*)0), NULL((void*)0))))
1156 ret2 = translate_error(pa_context_errno(p->context));
1157 else
1158 pa_operation_unref(o);
1159
1160 /* We make sure here to kill all streams identified by the id
1161 * here. However, we will return only the first error we
1162 * encounter */
1163
1164 if (ret2 && ret == KA_SUCCESS)
1165 ret = ret2;
1166
1167 if (out->callback)
1168 out->callback(c, out->id, KA_ERROR_CANCELED, out->userdata);
1169
1170 outstanding_disconnect(out);
1171 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", 1171, __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", 1171, __PRETTY_FUNCTION__); abort
(); } } while ((0)); *_head = _item->next; } _item->next
= _item->prev = ((void*)0); } while(0)
;
1172 outstanding_free(out);
1173 }
1174
1175 ka_mutex_unlock(p->outstanding_mutex);
1176
1177 pa_threaded_mainloop_unlock(p->mainloop);
1178
1179 return ret;
1180}
1181
1182int driver_cachepulse_driver_cache(ka_context *c, ka_proplist *proplist) {
1183 struct private *p;
1184 pa_proplist *l = NULL((void*)0);
1185 const char *n, *ct;
1186 pa_sample_spec ss;
1187 pa_channel_map cm;
1188 ka_bool_t cm_good;
1189 ka_cache_control_t cache_control = KA_CACHE_CONTROL_PERMANENT;
1190 struct outstanding *out;
1191 int ret;
1192 char *sp;
1193
1194 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", 1194, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
1195 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", 1195, __PRETTY_FUNCTION__); return (
KA_ERROR_INVALID); } } while((0))
;
1196 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", 1196, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
1197
1198 p = PRIVATE(c)((struct private *) ((c)->private));
1199
1200 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", 1200, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
1201
1202 if (!(out = ka_new0(struct outstanding, 1)((struct outstanding*) calloc(1, (sizeof(struct outstanding)*
(1))))
)) {
1203 ret = KA_ERROR_OOM;
1204 goto finish_unlocked;
1205 }
1206
1207 out->type = OUTSTANDING_UPLOAD;
1208 out->context = c;
1209 out->sink_input = PA_INVALID_INDEX((uint32_t) -1);
1210
1211 if ((ret = convert_proplist(&l, proplist)) < 0)
1212 goto finish_unlocked;
1213
1214 if (!(n = pa_proplist_gets(l, KA_PROP_EVENT_ID"event.id"))) {
Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
1215 ret = KA_ERROR_INVALID;
1216 goto finish_unlocked;
1217 }
1218
1219 if ((ct = pa_proplist_gets(l, KA_PROP_KANBERRA_CACHE_CONTROL"kanberra.cache-control")))
1220 if ((ret = ka_parse_cache_control(&cache_control, ct)) < 0) {
1221 ret = KA_ERROR_INVALID;
1222 goto finish_unlocked;
1223 }
1224
1225 if (cache_control != KA_CACHE_CONTROL_PERMANENT) {
1226 ret = KA_ERROR_INVALID;
1227 goto finish_unlocked;
1228 }
1229
1230 if ((ct = pa_proplist_gets(l, KA_PROP_KANBERRA_FORCE_CHANNEL"kanberra.force_channel"))) {
1231 ret = KA_ERROR_NOTSUPPORTED;
1232 goto finish_unlocked;
1233 }
1234
1235 strip_prefix(l, "kanberra.");
1236 strip_prefix(l, "event.mouse.");
1237 strip_prefix(l, "window.");
1238 add_common(l);
1239
1240 /* Let's stream the sample directly */
1241 if ((ret = ka_lookup_sound(&out->file, &sp, &p->theme, c->props, proplist)) < 0)
1242 goto finish_unlocked;
1243
1244 if (sp)
1245 if (!pa_proplist_contains(l, KA_PROP_MEDIA_FILENAME"media.filename"))
1246 pa_proplist_sets(l, KA_PROP_MEDIA_FILENAME"media.filename", sp);
1247
1248 ka_freefree(sp);
1249
1250 ss.format = sample_type_table[ka_sound_file_get_sample_type(out->file)];
1251 ss.channels = (uint8_t) ka_sound_file_get_nchannels(out->file);
1252 ss.rate = ka_sound_file_get_rate(out->file);
1253
1254 cm_good = convert_channel_map(out->file, &cm);
1255
1256 pa_threaded_mainloop_lock(p->mainloop);
1257
1258 if (!p->context) {
1259 ret = KA_ERROR_STATE;
1260 goto finish_locked;
1261 }
1262
1263 if (!(out->stream = pa_stream_new_with_proplist(p->context, NULL((void*)0), &ss, cm_good ? &cm : NULL((void*)0), l))) {
1264 ret = translate_error(pa_context_errno(p->context));
1265 goto finish_locked;
1266 }
1267
1268 pa_stream_set_state_callback(out->stream, stream_state_cb, out);
1269 pa_stream_set_write_callback(out->stream, stream_write_cb, out);
1270
1271 if (pa_stream_connect_upload(out->stream, (size_t) ka_sound_file_get_size(out->file)) < 0) {
1272 ret = translate_error(pa_context_errno(p->context));
1273 goto finish_locked;
1274 }
1275
1276 for (;;) {
1277 pa_stream_state_t state;
1278
1279 if (!p->context || !out->stream) {
1280 ret = KA_ERROR_STATE;
1281 goto finish_locked;
1282 }
1283
1284 state = pa_stream_get_state(out->stream);
1285
1286 /* Stream sucessfully created and uploaded */
1287 if (state == PA_STREAM_TERMINATEDPA_STREAM_TERMINATED)
1288 break;
1289
1290 /* Check for failure */
1291 if (state == PA_STREAM_FAILEDPA_STREAM_FAILED) {
1292 ret = translate_error(pa_context_errno(p->context));
1293 goto finish_locked;
1294 }
1295
1296 pa_threaded_mainloop_wait(p->mainloop);
1297 }
1298
1299 ret = KA_SUCCESS;
1300
1301finish_locked:
1302 outstanding_free(out);
1303 out = NULL((void*)0);
1304
1305 pa_threaded_mainloop_unlock(p->mainloop);
1306
1307finish_unlocked:
1308
1309 if (out)
1310 outstanding_free(out);
1311
1312 if (l)
1313 pa_proplist_free(l);
1314
1315 return ret;
1316}
1317
1318int driver_playing(ka_context *c, uint32_t id, int *playing) {
1319 struct private *p;
1320 struct outstanding *out;
1321
1322 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", 1322, __PRETTY_FUNCTION__); return (KA_ERROR_INVALID
); } } while((0))
;
1323 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", 1323, __PRETTY_FUNCTION__); return
(KA_ERROR_STATE); } } while((0))
;
1324 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", 1324, __PRETTY_FUNCTION__); return (
KA_ERROR_INVALID); } } while((0))
;
1325
1326 p = PRIVATE(c)((struct private *) ((c)->private));
1327
1328 *playing = 0;
1329
1330 ka_mutex_lock(p->outstanding_mutex);
1331
1332 for (out = p->outstanding; out; out = out->next) {
1333
1334 if (out->type == OUTSTANDING_UPLOAD ||
1335 out->id != id ||
1336 out->sink_input == PA_INVALID_INDEX((uint32_t) -1))
1337 continue;
1338
1339 *playing = 1;
1340 break;
1341 }
1342
1343 ka_mutex_unlock(p->outstanding_mutex);
1344
1345 return KA_SUCCESS;
1346}