xref: /third_party/pulseaudio/src/pulse/simple.c (revision 53a5a1b3)
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
38struct 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
83static 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
103static 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
122static 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
129static 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
137pa_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
242unlock_and_fail:
243    pa_threaded_mainloop_unlock(p->mainloop);
244
245fail:
246    if (rerror)
247        *rerror = error;
248    pa_simple_free(p);
249    return NULL;
250}
251
252void 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
272int 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
307unlock_and_fail:
308    pa_threaded_mainloop_unlock(p->mainloop);
309    return -1;
310}
311
312int 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
368unlock_and_fail:
369    pa_threaded_mainloop_unlock(p->mainloop);
370    return -1;
371}
372
373static 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
383int 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
408unlock_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
419int 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
442unlock_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
453pa_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
508unlock_and_fail:
509
510    pa_threaded_mainloop_unlock(p->mainloop);
511    return (pa_usec_t) -1;
512}
513