• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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