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