]> code.delx.au - pulseaudio/blob - src/pulse/simple.c
Merge commit 'origin/master-tx'
[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/native-common.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/macro.h>
38
39 #include "simple.h"
40
41 struct pa_simple {
42 pa_threaded_mainloop *mainloop;
43 pa_context *context;
44 pa_stream *stream;
45 pa_stream_direction_t direction;
46
47 const void *read_data;
48 size_t read_index, read_length;
49
50 int operation_success;
51 };
52
53 #define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) do { \
54 if (!(expression)) { \
55 if (rerror) \
56 *(rerror) = error; \
57 return (ret); \
58 } \
59 } while(0);
60
61 #define CHECK_SUCCESS_GOTO(p, rerror, expression, label) do { \
62 if (!(expression)) { \
63 if (rerror) \
64 *(rerror) = pa_context_errno((p)->context); \
65 goto label; \
66 } \
67 } while(0);
68
69 #define CHECK_DEAD_GOTO(p, rerror, label) do { \
70 if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \
71 !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \
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(0);
82
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
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
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
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
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_xnew(pa_simple, 1);
158 p->context = NULL;
159 p->stream = NULL;
160 p->direction = dir;
161 p->read_data = NULL;
162 p->read_index = p->read_length = 0;
163
164 if (!(p->mainloop = pa_threaded_mainloop_new()))
165 goto fail;
166
167 if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name)))
168 goto fail;
169
170 pa_context_set_state_callback(p->context, context_state_cb, p);
171
172 if (pa_context_connect(p->context, server, 0, NULL) < 0) {
173 error = pa_context_errno(p->context);
174 goto fail;
175 }
176
177 pa_threaded_mainloop_lock(p->mainloop);
178
179 if (pa_threaded_mainloop_start(p->mainloop) < 0)
180 goto unlock_and_fail;
181
182 /* Wait until the context is ready */
183 pa_threaded_mainloop_wait(p->mainloop);
184
185 if (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
186 error = pa_context_errno(p->context);
187 goto unlock_and_fail;
188 }
189
190 if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) {
191 error = pa_context_errno(p->context);
192 goto unlock_and_fail;
193 }
194
195 pa_stream_set_state_callback(p->stream, stream_state_cb, p);
196 pa_stream_set_read_callback(p->stream, stream_request_cb, p);
197 pa_stream_set_write_callback(p->stream, stream_request_cb, p);
198 pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
199
200 if (dir == PA_STREAM_PLAYBACK)
201 r = pa_stream_connect_playback(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
202 else
203 r = pa_stream_connect_record(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE);
204
205 if (r < 0) {
206 error = pa_context_errno(p->context);
207 goto unlock_and_fail;
208 }
209
210 /* Wait until the stream is ready */
211 pa_threaded_mainloop_wait(p->mainloop);
212
213 /* Wait until the stream is ready */
214 if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
215 error = pa_context_errno(p->context);
216 goto unlock_and_fail;
217 }
218
219 pa_threaded_mainloop_unlock(p->mainloop);
220
221 return p;
222
223 unlock_and_fail:
224 pa_threaded_mainloop_unlock(p->mainloop);
225
226 fail:
227 if (rerror)
228 *rerror = error;
229 pa_simple_free(p);
230 return NULL;
231 }
232
233 void pa_simple_free(pa_simple *s) {
234 pa_assert(s);
235
236 if (s->mainloop)
237 pa_threaded_mainloop_stop(s->mainloop);
238
239 if (s->stream)
240 pa_stream_unref(s->stream);
241
242 if (s->context)
243 pa_context_unref(s->context);
244
245 if (s->mainloop)
246 pa_threaded_mainloop_free(s->mainloop);
247
248 pa_xfree(s);
249 }
250
251 int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) {
252 pa_assert(p);
253
254 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
255 CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1);
256
257 pa_threaded_mainloop_lock(p->mainloop);
258
259 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
260
261 while (length > 0) {
262 size_t l;
263 int r;
264
265 while (!(l = pa_stream_writable_size(p->stream))) {
266 pa_threaded_mainloop_wait(p->mainloop);
267 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
268 }
269
270 CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail);
271
272 if (l > length)
273 l = length;
274
275 r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
276 CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail);
277
278 data = (const uint8_t*) data + l;
279 length -= l;
280 }
281
282 pa_threaded_mainloop_unlock(p->mainloop);
283 return 0;
284
285 unlock_and_fail:
286 pa_threaded_mainloop_unlock(p->mainloop);
287 return -1;
288 }
289
290 int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) {
291 pa_assert(p);
292
293 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1);
294 CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1);
295
296 pa_threaded_mainloop_lock(p->mainloop);
297
298 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
299
300 while (length > 0) {
301 size_t l;
302
303 while (!p->read_data) {
304 int r;
305
306 r = pa_stream_peek(p->stream, &p->read_data, &p->read_length);
307 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
308
309 if (!p->read_data) {
310 pa_threaded_mainloop_wait(p->mainloop);
311 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
312 } else
313 p->read_index = 0;
314 }
315
316 l = p->read_length < length ? p->read_length : length;
317 memcpy(data, (const uint8_t*) p->read_data+p->read_index, l);
318
319 data = (uint8_t*) data + l;
320 length -= l;
321
322 p->read_index += l;
323 p->read_length -= l;
324
325 if (!p->read_length) {
326 int r;
327
328 r = pa_stream_drop(p->stream);
329 p->read_data = NULL;
330 p->read_length = 0;
331 p->read_index = 0;
332
333 CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail);
334 }
335 }
336
337 pa_threaded_mainloop_unlock(p->mainloop);
338 return 0;
339
340 unlock_and_fail:
341 pa_threaded_mainloop_unlock(p->mainloop);
342 return -1;
343 }
344
345 static void success_cb(pa_stream *s, int success, void *userdata) {
346 pa_simple *p = userdata;
347
348 pa_assert(s);
349 pa_assert(p);
350
351 p->operation_success = success;
352 pa_threaded_mainloop_signal(p->mainloop, 0);
353 }
354
355 int pa_simple_drain(pa_simple *p, int *rerror) {
356 pa_operation *o = NULL;
357
358 pa_assert(p);
359
360 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
361
362 pa_threaded_mainloop_lock(p->mainloop);
363 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
364
365 o = pa_stream_drain(p->stream, success_cb, p);
366 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
367
368 p->operation_success = 0;
369 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
370 pa_threaded_mainloop_wait(p->mainloop);
371 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
372 }
373 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
374
375 pa_operation_unref(o);
376 pa_threaded_mainloop_unlock(p->mainloop);
377
378 return 0;
379
380 unlock_and_fail:
381
382 if (o) {
383 pa_operation_cancel(o);
384 pa_operation_unref(o);
385 }
386
387 pa_threaded_mainloop_unlock(p->mainloop);
388 return -1;
389 }
390
391 int pa_simple_flush(pa_simple *p, int *rerror) {
392 pa_operation *o = NULL;
393
394 pa_assert(p);
395
396 CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
397
398 pa_threaded_mainloop_lock(p->mainloop);
399 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
400
401 o = pa_stream_flush(p->stream, success_cb, p);
402 CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
403
404 p->operation_success = 0;
405 while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
406 pa_threaded_mainloop_wait(p->mainloop);
407 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
408 }
409 CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
410
411 pa_operation_unref(o);
412 pa_threaded_mainloop_unlock(p->mainloop);
413
414 return 0;
415
416 unlock_and_fail:
417
418 if (o) {
419 pa_operation_cancel(o);
420 pa_operation_unref(o);
421 }
422
423 pa_threaded_mainloop_unlock(p->mainloop);
424 return -1;
425 }
426
427 pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) {
428 pa_usec_t t;
429 int negative;
430
431 pa_assert(p);
432
433 pa_threaded_mainloop_lock(p->mainloop);
434
435 for (;;) {
436 CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
437
438 if (pa_stream_get_latency(p->stream, &t, &negative) >= 0)
439 break;
440
441 CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail);
442
443 /* Wait until latency data is available again */
444 pa_threaded_mainloop_wait(p->mainloop);
445 }
446
447 pa_threaded_mainloop_unlock(p->mainloop);
448
449 return negative ? 0 : t;
450
451 unlock_and_fail:
452
453 pa_threaded_mainloop_unlock(p->mainloop);
454 return (pa_usec_t) -1;
455 }