Bug Summary

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

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-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D HAVE_CONFIG_H -I . -I .. -D _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-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2022-12-26-003908-18484-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"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
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, 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
497int 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
539static 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
575static 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
593static 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
642static 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
679static 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
755finish:
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
779static 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
785static 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
807static 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
824int 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) {
Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret'
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
1090finish_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
1106finish_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
1119int 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
1180int 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"))) {
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
1299finish_locked:
1300 outstanding_free(out);
1301 out = NULL((void*)0);
1302
1303 pa_threaded_mainloop_unlock(p->mainloop);
1304
1305finish_unlocked:
1306
1307 if (out)
1308 outstanding_free(out);
1309
1310 if (l)
1311 pa_proplist_free(l);
1312
1313 return ret;
1314}
1315
1316int 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}