]> code.delx.au - pulseaudio/blob - src/pulse/simple.c
volume: Increase PA_SW_VOLUME_SNPRINT_DB_MAX
[pulseaudio] / src / pulse / simple.c
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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include <pulse/pulseaudio.h>
32 #include <pulse/thread-mainloop.h>
33 #include <pulse/xmalloc.h>
34
35 #include <pulsecore/log.h>
36 #include <pulsecore/macro.h>
37
38 #include "simple.h"
39
40 struct pa_simple {
41 pa_threaded_mainloop *mainloop;
42 pa_context *context;
43 pa_stream *stream;
44 pa_stream_direction_t direction;
45
46 const void *read_data;
47 size_t read_index, read_length;
48
49 int operation_success;
50 };
51
52 #define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) \
53 do { \
54 if (!(expression)) { \
55 if (rerror) \
56 *(rerror) = error; \
57 return (ret); \
58 } \
59 } while(false);
60
61 #define CHECK_SUCCESS_GOTO(p, rerror, expression, label) \
62 do { \
63 if (!(expression)) { \
64 if (rerror) \
65 *(rerror) = pa_context_errno((p)->context); \
66 goto label; \
67 } \
68 } while(false);
69
70 #define CHECK_DEAD_GOTO(p, rerror, label) \
71 do { \
72 if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \
73 !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \
74 if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \
75 ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \
76 if (rerror) \
77 *(rerror) = pa_context_errno((p)->context); \
78 } else \
79 if (rerror) \
80 *(rerror) = PA_ERR_BADSTATE; \
81 goto label; \
82 } \
83 } while(false);
84
85 static void context_state_cb(pa_context *c, void *userdata) {
86 pa_simple *p = userdata;
87 pa_assert(c);
88 pa_assert(p);
89
90 switch (pa_context_get_state(c)) {
91 case PA_CONTEXT_READY:
92 case PA_CONTEXT_TERMINATED:
93 case PA_CONTEXT_FAILED:
94 pa_threaded_mainloop_signal(p->mainloop, 0);
95 break;
96
97 case PA_CONTEXT_UNCONNECTED:
98 case PA_CONTEXT_CONNECTING:
99 case PA_CONTEXT_AUTHORIZING:
100 case PA_CONTEXT_SETTING_NAME:
101 break;
102 }
103 }
104
105 static void stream_state_cb(pa_stream *s, void * userdata) {
106 pa_simple *p = userdata;
107 pa_assert(s);
108 pa_assert(p);
109
110 switch (pa_stream_get_state(s)) {
111
112 case PA_STREAM_READY:
113 case PA_STREAM_FAILED:
114 case PA_STREAM_TERMINATED:
115 pa_threaded_mainloop_signal(p->mainloop, 0);
116 break;
117
118 case PA_STREAM_UNCONNECTED:
119 case PA_STREAM_CREATING:
120 break;
121 }
122 }
123
124 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
125 pa_simple *p = userdata;
126 pa_assert(p);
127
128 pa_threaded_mainloop_signal(p->mainloop, 0);
129 }
130
131 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
132 pa_simple *p = userdata;
133
134 pa_assert(p);
135
136 pa_threaded_mainloop_signal(p->mainloop, 0);
137 }
138
139 pa_simple* pa_simple_new(
140 const char *server,
141 const char *name,
142 pa_stream_direction_t dir,
143 const char *dev,
144 const char *stream_name,
145 const pa_sample_spec *ss,
146 const pa_channel_map *map,
147 const pa_buffer_attr *attr,
148 int *rerror) {
149
150 pa_simple *p;
151 int error = PA_ERR_INTERNAL, r;
152
153 CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL);
154 CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL);
155 CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL);
156 CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL);
157 CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL)
158
159 p = pa_xnew0(pa_simple, 1);
160 p->direction = dir;
161
162 if (!(p->mainloop = pa_threaded_mainloop_new()))
163 goto fail;
164
165 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name)))
166 goto fail;
167
168 pa_context_set_state_callback(p->context, context_state_cb, p);
169
170 if (pa_context_connect(p->context, server, 0, NULL) < 0) {
171 error = pa_context_errno(p->context);
172 goto fail;
173 }
174
175 pa_threaded_mainloop_lock(p->mainloop);
176
177 if (pa_threaded_mainloop_start(p->mainloop) < 0)
178 goto unlock_and_fail;
179
180 for (;;) {
181 pa_context_state_t state;
182
183 state = pa_context_get_state(p->context);
184
185 if (state == PA_CONTEXT_READY)
186 break;
187
188 if (!PA_CONTEXT_IS_GOOD(state)) {
189 error = pa_context_errno(p->context);
190 goto unlock_and_fail;
191 }
192
193 /* Wait until the context is ready */
194 pa_threaded_mainloop_wait(p->mainloop);
195 }
196
197 if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) {
198 error = pa_context_errno(p->context);
199 goto unlock_and_fail;
200 }
201
202 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
203 pa_stream_set_read_callback(p->stream, stream_request_cb, p);
204 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
205 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
206
207 if (dir == PA_STREAM_PLAYBACK)
208 r = pa_stream_connect_playback(p->stream, dev, attr,
209 PA_STREAM_INTERPOLATE_TIMING
210 |PA_STREAM_ADJUST_LATENCY
211 |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
212 else
213 r = pa_stream_connect_record(p->stream, dev, attr,
214 PA_STREAM_INTERPOLATE_TIMING
215 |PA_STREAM_ADJUST_LATENCY
216 |PA_STREAM_AUTO_TIMING_UPDATE);
217
218 if (r < 0) {
219 error = pa_context_errno(p->context);
220 goto unlock_and_fail;
221 }
222
223 for (;;) {
224 pa_stream_state_t state;
225
226 state = pa_stream_get_state(p->stream);
227
228 if (state == PA_STREAM_READY)
229 break;
230
231 if (!PA_STREAM_IS_GOOD(state)) {
232 error = pa_context_errno(p->context);
233 goto unlock_and_fail;
234 }
235
236 /* Wait until the stream is ready */
237 pa_threaded_mainloop_wait(p->mainloop);
238 }
239
240 pa_threaded_mainloop_unlock(p->mainloop);
241
242 return p;
243
244 unlock_and_fail:
245 pa_threaded_mainloop_unlock(p->mainloop);
246
247 fail:
248 if (rerror)
249 *rerror = error;
250 pa_simple_free(p);
251 return NULL;
252 }
253
254 void pa_simple_free(pa_simple *s) {
255 pa_assert(s);
256
257 if (s->mainloop)
258 pa_threaded_mainloop_stop(s->mainloop);
259
260 if (s->stream)
261 pa_stream_unref(s->stream);
262
263 if (s->context) {
264 pa_context_disconnect(s->context);
265 pa_context_unref(s->context);
266 }
267
268 if (s->mainloop)
269 pa_threaded_mainloop_free(s->mainloop);
270
271 pa_xfree(s);
272 }
273
274 int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) {
275 pa_assert(p);
276
277 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
278 CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1);
279 CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1);
280
281 pa_threaded_mainloop_lock(p->mainloop);
282
283 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
284
285 while (length > 0) {
286 size_t l;
287 int r;
288
289 while (!(l = pa_stream_writable_size(p->stream))) {
290 pa_threaded_mainloop_wait(p->mainloop);
291 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
292 }
293
294 CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail);
295
296 if (l > length)
297 l = length;
298
299 r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
300 CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail);
301
302 data = (const uint8_t*) data + l;
303 length -= l;
304 }
305
306 pa_threaded_mainloop_unlock(p->mainloop);
307 return 0;
308
309 unlock_and_fail:
310 pa_threaded_mainloop_unlock(p->mainloop);
311 return -1;
312 }
313
314 int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) {
315 pa_assert(p);
316
317 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1);
318 CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1);
319 CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1);
320
321 pa_threaded_mainloop_lock(p->mainloop);
322
323 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
324
325 while (length > 0) {
326 size_t l;
327
328 while (!p->read_data) {
329 int r;
330
331 r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
332 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
333
334 if (p->read_length <= 0) {
335 pa_threaded_mainloop_wait(p->mainloop);
336 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
337 } else if (!p->read_data) {
338 /* There's a hole in the stream, skip it. We could generate
339 * silence, but that wouldn't work for compressed streams. */
340 r = pa_stream_drop(p->stream);
341 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
342 } else
343 p->read_index = 0;
344 }
345
346 l = p->read_length < length ? p->read_length : length;
347 memcpy(data, (const uint8_t*) p->read_data+p->read_index, l);
348
349 data = (uint8_t*) data + l;
350 length -= l;
351
352 p->read_index += l;
353 p->read_length -= l;
354
355 if (!p->read_length) {
356 int r;
357
358 r = pa_stream_drop(p->stream);
359 p->read_data = NULL;
360 p->read_length = 0;
361 p->read_index = 0;
362
363 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
364 }
365 }
366
367 pa_threaded_mainloop_unlock(p->mainloop);
368 return 0;
369
370 unlock_and_fail:
371 pa_threaded_mainloop_unlock(p->mainloop);
372 return -1;
373 }
374
375 static void success_cb(pa_stream *s, int success, void *userdata) {
376 pa_simple *p = userdata;
377
378 pa_assert(s);
379 pa_assert(p);
380
381 p->operation_success = success;
382 pa_threaded_mainloop_signal(p->mainloop, 0);
383 }
384
385 int pa_simple_drain(pa_simple *p, int *rerror) {
386 pa_operation *o = NULL;
387
388 pa_assert(p);
389
390 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
391
392 pa_threaded_mainloop_lock(p->mainloop);
393 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
394
395 o = pa_stream_drain(p->stream, success_cb, p);
396 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
397
398 p->operation_success = 0;
399 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
400 pa_threaded_mainloop_wait(p->mainloop);
401 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
402 }
403 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
404
405 pa_operation_unref(o);
406 pa_threaded_mainloop_unlock(p->mainloop);
407
408 return 0;
409
410 unlock_and_fail:
411
412 if (o) {
413 pa_operation_cancel(o);
414 pa_operation_unref(o);
415 }
416
417 pa_threaded_mainloop_unlock(p->mainloop);
418 return -1;
419 }
420
421 int pa_simple_flush(pa_simple *p, int *rerror) {
422 pa_operation *o = NULL;
423
424 pa_assert(p);
425
426 pa_threaded_mainloop_lock(p->mainloop);
427 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
428
429 o = pa_stream_flush(p->stream, success_cb, p);
430 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
431
432 p->operation_success = 0;
433 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
434 pa_threaded_mainloop_wait(p->mainloop);
435 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
436 }
437 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
438
439 pa_operation_unref(o);
440 pa_threaded_mainloop_unlock(p->mainloop);
441
442 return 0;
443
444 unlock_and_fail:
445
446 if (o) {
447 pa_operation_cancel(o);
448 pa_operation_unref(o);
449 }
450
451 pa_threaded_mainloop_unlock(p->mainloop);
452 return -1;
453 }
454
455 pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) {
456 pa_usec_t t;
457 int negative;
458
459 pa_assert(p);
460
461 pa_threaded_mainloop_lock(p->mainloop);
462
463 for (;;) {
464 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
465
466 if (pa_stream_get_latency(p->stream, &t, &negative) >= 0)
467 break;
468
469 CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail);
470
471 /* Wait until latency data is available again */
472 pa_threaded_mainloop_wait(p->mainloop);
473 }
474
475 pa_threaded_mainloop_unlock(p->mainloop);
476
477 return negative ? 0 : t;
478
479 unlock_and_fail:
480
481 pa_threaded_mainloop_unlock(p->mainloop);
482 return (pa_usec_t) -1;
483 }