1
2 /***
3 This file is part of PulseAudio.
4
5 Copyright 2004-2006 Lennart Poettering
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include <pulse/pulseaudio.h>
30 #include <pulse/thread-mainloop.h>
31 #include <pulse/xmalloc.h>
32
33 #include <pulsecore/log.h>
34 #include <pulsecore/macro.h>
35
36 #include "simple.h"
37
38 struct pa_simple {
39 pa_threaded_mainloop *mainloop;
40 pa_context *context;
41 pa_stream *stream;
42 pa_stream_direction_t direction;
43
44 const void *read_data;
45 size_t read_index, read_length;
46
47 int operation_success;
48 };
49
50 #define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) \
51 do { \
52 if (!(expression)) { \
53 if (rerror) \
54 *(rerror) = error; \
55 return (ret); \
56 } \
57 } while(false);
58
59 #define CHECK_SUCCESS_GOTO(p, rerror, expression, label) \
60 do { \
61 if (!(expression)) { \
62 if (rerror) \
63 *(rerror) = pa_context_errno((p)->context); \
64 goto label; \
65 } \
66 } while(false);
67
68 #define CHECK_DEAD_GOTO(p, rerror, label) \
69 do { \
70 if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \
71 !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \
72 if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \
73 ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \
74 if (rerror) \
75 *(rerror) = pa_context_errno((p)->context); \
76 } else \
77 if (rerror) \
78 *(rerror) = PA_ERR_BADSTATE; \
79 goto label; \
80 } \
81 } while(false);
82
context_state_cb(pa_context * c,void * userdata)83 static void context_state_cb(pa_context *c, void *userdata) {
84 pa_simple *p = userdata;
85 pa_assert(c);
86 pa_assert(p);
87
88 switch (pa_context_get_state(c)) {
89 case PA_CONTEXT_READY:
90 case PA_CONTEXT_TERMINATED:
91 case PA_CONTEXT_FAILED:
92 pa_threaded_mainloop_signal(p->mainloop, 0);
93 break;
94
95 case PA_CONTEXT_UNCONNECTED:
96 case PA_CONTEXT_CONNECTING:
97 case PA_CONTEXT_AUTHORIZING:
98 case PA_CONTEXT_SETTING_NAME:
99 break;
100 }
101 }
102
stream_state_cb(pa_stream * s,void * userdata)103 static void stream_state_cb(pa_stream *s, void * userdata) {
104 pa_simple *p = userdata;
105 pa_assert(s);
106 pa_assert(p);
107
108 switch (pa_stream_get_state(s)) {
109
110 case PA_STREAM_READY:
111 case PA_STREAM_FAILED:
112 case PA_STREAM_TERMINATED:
113 pa_threaded_mainloop_signal(p->mainloop, 0);
114 break;
115
116 case PA_STREAM_UNCONNECTED:
117 case PA_STREAM_CREATING:
118 break;
119 }
120 }
121
stream_request_cb(pa_stream * s,size_t length,void * userdata)122 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
123 pa_simple *p = userdata;
124 pa_assert(p);
125
126 pa_threaded_mainloop_signal(p->mainloop, 0);
127 }
128
stream_latency_update_cb(pa_stream * s,void * userdata)129 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
130 pa_simple *p = userdata;
131
132 pa_assert(p);
133
134 pa_threaded_mainloop_signal(p->mainloop, 0);
135 }
136
pa_simple_new(const char * server,const char * name,pa_stream_direction_t dir,const char * dev,const char * stream_name,const pa_sample_spec * ss,const pa_channel_map * map,const pa_buffer_attr * attr,int * rerror)137 pa_simple* pa_simple_new(
138 const char *server,
139 const char *name,
140 pa_stream_direction_t dir,
141 const char *dev,
142 const char *stream_name,
143 const pa_sample_spec *ss,
144 const pa_channel_map *map,
145 const pa_buffer_attr *attr,
146 int *rerror) {
147
148 pa_simple *p;
149 int error = PA_ERR_INTERNAL, r;
150
151 CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL);
152 CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL);
153 CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL);
154 CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL);
155 CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL)
156
157 p = pa_xnew0(pa_simple, 1);
158 p->direction = dir;
159
160 if (!(p->mainloop = pa_threaded_mainloop_new()))
161 goto fail;
162
163 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name)))
164 goto fail;
165
166 pa_context_set_state_callback(p->context, context_state_cb, p);
167
168 if (pa_context_connect(p->context, server, 0, NULL) < 0) {
169 error = pa_context_errno(p->context);
170 goto fail;
171 }
172
173 pa_threaded_mainloop_lock(p->mainloop);
174
175 if (pa_threaded_mainloop_start(p->mainloop) < 0)
176 goto unlock_and_fail;
177
178 for (;;) {
179 pa_context_state_t state;
180
181 state = pa_context_get_state(p->context);
182
183 if (state == PA_CONTEXT_READY)
184 break;
185
186 if (!PA_CONTEXT_IS_GOOD(state)) {
187 error = pa_context_errno(p->context);
188 goto unlock_and_fail;
189 }
190
191 /* Wait until the context is ready */
192 pa_threaded_mainloop_wait(p->mainloop);
193 }
194
195 if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) {
196 error = pa_context_errno(p->context);
197 goto unlock_and_fail;
198 }
199
200 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
201 pa_stream_set_read_callback(p->stream, stream_request_cb, p);
202 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
203 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
204
205 if (dir == PA_STREAM_PLAYBACK)
206 r = pa_stream_connect_playback(p->stream, dev, attr,
207 PA_STREAM_INTERPOLATE_TIMING
208 |PA_STREAM_ADJUST_LATENCY
209 |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
210 else
211 r = pa_stream_connect_record(p->stream, dev, attr,
212 PA_STREAM_INTERPOLATE_TIMING
213 |PA_STREAM_ADJUST_LATENCY
214 |PA_STREAM_AUTO_TIMING_UPDATE);
215
216 if (r < 0) {
217 error = pa_context_errno(p->context);
218 goto unlock_and_fail;
219 }
220
221 for (;;) {
222 pa_stream_state_t state;
223
224 state = pa_stream_get_state(p->stream);
225
226 if (state == PA_STREAM_READY)
227 break;
228
229 if (!PA_STREAM_IS_GOOD(state)) {
230 error = pa_context_errno(p->context);
231 goto unlock_and_fail;
232 }
233
234 /* Wait until the stream is ready */
235 pa_threaded_mainloop_wait(p->mainloop);
236 }
237
238 pa_threaded_mainloop_unlock(p->mainloop);
239
240 return p;
241
242 unlock_and_fail:
243 pa_threaded_mainloop_unlock(p->mainloop);
244
245 fail:
246 if (rerror)
247 *rerror = error;
248 pa_simple_free(p);
249 return NULL;
250 }
251
pa_simple_free(pa_simple * s)252 void pa_simple_free(pa_simple *s) {
253 pa_assert(s);
254
255 if (s->mainloop)
256 pa_threaded_mainloop_stop(s->mainloop);
257
258 if (s->stream)
259 pa_stream_unref(s->stream);
260
261 if (s->context) {
262 pa_context_disconnect(s->context);
263 pa_context_unref(s->context);
264 }
265
266 if (s->mainloop)
267 pa_threaded_mainloop_free(s->mainloop);
268
269 pa_xfree(s);
270 }
271
pa_simple_write(pa_simple * p,const void * data,size_t length,int * rerror)272 int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) {
273 pa_assert(p);
274
275 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
276 CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1);
277 CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1);
278
279 pa_threaded_mainloop_lock(p->mainloop);
280
281 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
282
283 while (length > 0) {
284 size_t l;
285 int r;
286
287 while (!(l = pa_stream_writable_size(p->stream))) {
288 pa_threaded_mainloop_wait(p->mainloop);
289 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
290 }
291
292 CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail);
293
294 if (l > length)
295 l = length;
296
297 r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
298 CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail);
299
300 data = (const uint8_t*) data + l;
301 length -= l;
302 }
303
304 pa_threaded_mainloop_unlock(p->mainloop);
305 return 0;
306
307 unlock_and_fail:
308 pa_threaded_mainloop_unlock(p->mainloop);
309 return -1;
310 }
311
pa_simple_read(pa_simple * p,void * data,size_t length,int * rerror)312 int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) {
313 pa_assert(p);
314
315 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1);
316 CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1);
317 CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1);
318
319 pa_threaded_mainloop_lock(p->mainloop);
320
321 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
322
323 while (length > 0) {
324 size_t l;
325
326 while (!p->read_data) {
327 int r;
328
329 r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
330 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
331
332 if (p->read_length <= 0) {
333 pa_threaded_mainloop_wait(p->mainloop);
334 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
335 } else if (!p->read_data) {
336 /* There's a hole in the stream, skip it. We could generate
337 * silence, but that wouldn't work for compressed streams. */
338 r = pa_stream_drop(p->stream);
339 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
340 } else
341 p->read_index = 0;
342 }
343
344 l = p->read_length < length ? p->read_length : length;
345 memcpy(data, (const uint8_t*) p->read_data+p->read_index, l);
346
347 data = (uint8_t*) data + l;
348 length -= l;
349
350 p->read_index += l;
351 p->read_length -= l;
352
353 if (!p->read_length) {
354 int r;
355
356 r = pa_stream_drop(p->stream);
357 p->read_data = NULL;
358 p->read_length = 0;
359 p->read_index = 0;
360
361 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
362 }
363 }
364
365 pa_threaded_mainloop_unlock(p->mainloop);
366 return 0;
367
368 unlock_and_fail:
369 pa_threaded_mainloop_unlock(p->mainloop);
370 return -1;
371 }
372
success_cb(pa_stream * s,int success,void * userdata)373 static void success_cb(pa_stream *s, int success, void *userdata) {
374 pa_simple *p = userdata;
375
376 pa_assert(s);
377 pa_assert(p);
378
379 p->operation_success = success;
380 pa_threaded_mainloop_signal(p->mainloop, 0);
381 }
382
pa_simple_drain(pa_simple * p,int * rerror)383 int pa_simple_drain(pa_simple *p, int *rerror) {
384 pa_operation *o = NULL;
385
386 pa_assert(p);
387
388 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
389
390 pa_threaded_mainloop_lock(p->mainloop);
391 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
392
393 o = pa_stream_drain(p->stream, success_cb, p);
394 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
395
396 p->operation_success = 0;
397 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
398 pa_threaded_mainloop_wait(p->mainloop);
399 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
400 }
401 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
402
403 pa_operation_unref(o);
404 pa_threaded_mainloop_unlock(p->mainloop);
405
406 return 0;
407
408 unlock_and_fail:
409
410 if (o) {
411 pa_operation_cancel(o);
412 pa_operation_unref(o);
413 }
414
415 pa_threaded_mainloop_unlock(p->mainloop);
416 return -1;
417 }
418
pa_simple_flush(pa_simple * p,int * rerror)419 int pa_simple_flush(pa_simple *p, int *rerror) {
420 pa_operation *o = NULL;
421
422 pa_assert(p);
423
424 pa_threaded_mainloop_lock(p->mainloop);
425 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
426
427 o = pa_stream_flush(p->stream, success_cb, p);
428 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
429
430 p->operation_success = 0;
431 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
432 pa_threaded_mainloop_wait(p->mainloop);
433 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
434 }
435 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
436
437 pa_operation_unref(o);
438 pa_threaded_mainloop_unlock(p->mainloop);
439
440 return 0;
441
442 unlock_and_fail:
443
444 if (o) {
445 pa_operation_cancel(o);
446 pa_operation_unref(o);
447 }
448
449 pa_threaded_mainloop_unlock(p->mainloop);
450 return -1;
451 }
452
pa_simple_get_latency(pa_simple * p,int * rerror)453 pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) {
454 pa_usec_t t;
455
456 pa_assert(p);
457
458 pa_threaded_mainloop_lock(p->mainloop);
459
460 for (;;) {
461 int negative;
462
463 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
464
465 if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) {
466 if (p->direction == PA_STREAM_RECORD) {
467 pa_usec_t already_read;
468
469 /* pa_simple_read() calls pa_stream_peek() to get the next
470 * chunk of audio. If the next chunk is larger than what the
471 * pa_simple_read() caller wanted, the leftover data is stored
472 * in p->read_data until pa_simple_read() is called again.
473 * pa_stream_drop() won't be called until the whole chunk has
474 * been consumed, which means that pa_stream_get_latency() will
475 * return too large values, because the whole size of the
476 * partially read chunk is included in the latency. Therefore,
477 * we need to subtract the already-read amount from the
478 * latency. */
479 already_read = pa_bytes_to_usec(p->read_index, pa_stream_get_sample_spec(p->stream));
480
481 if (!negative) {
482 if (t > already_read)
483 t -= already_read;
484 else
485 t = 0;
486 }
487 }
488
489 /* We don't have a way to report negative latencies from
490 * pa_simple_get_latency(). If the latency is negative, let's
491 * report zero. */
492 if (negative)
493 t = 0;
494
495 break;
496 }
497
498 CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail);
499
500 /* Wait until latency data is available again */
501 pa_threaded_mainloop_wait(p->mainloop);
502 }
503
504 pa_threaded_mainloop_unlock(p->mainloop);
505
506 return t;
507
508 unlock_and_fail:
509
510 pa_threaded_mainloop_unlock(p->mainloop);
511 return (pa_usec_t) -1;
512 }
513