]> code.delx.au - pulseaudio/blob - src/polyp/simple.c
e14cab2ebb57faead1ffd6b4c328c6c1d6ed83f8
[pulseaudio] / src / polyp / simple.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <stdlib.h>
30
31 #include <polyp/polypaudio.h>
32 #include <polyp/mainloop.h>
33
34 #include <polypcore/native-common.h>
35 #include <polypcore/xmalloc.h>
36 #include <polypcore/log.h>
37
38 #include "simple.h"
39
40 struct pa_simple {
41 pa_mainloop *mainloop;
42 pa_context *context;
43 pa_stream *stream;
44 pa_stream_direction_t direction;
45
46 int dead;
47
48 void *read_data;
49 size_t read_index, read_length;
50 pa_usec_t latency;
51 };
52
53 static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata);
54
55 static int check_error(pa_simple *p, int *rerror) {
56 pa_context_state_t cst;
57 pa_stream_state_t sst;
58 assert(p);
59
60 if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED)
61 goto fail;
62
63 assert(cst != PA_CONTEXT_TERMINATED);
64
65 if (p->stream) {
66 if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED)
67 goto fail;
68
69 assert(sst != PA_STREAM_TERMINATED);
70 }
71
72 return 0;
73
74 fail:
75 if (rerror)
76 *rerror = pa_context_errno(p->context);
77
78 p->dead = 1;
79
80 return -1;
81 }
82
83 static int iterate(pa_simple *p, int block, int *rerror) {
84 assert(p && p->context && p->mainloop);
85
86 if (check_error(p, rerror) < 0)
87 return -1;
88
89 if (!block && !pa_context_is_pending(p->context))
90 return 0;
91
92 do {
93 if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) {
94 if (rerror)
95 *rerror = PA_ERROR_INTERNAL;
96 return -1;
97 }
98
99 if (check_error(p, rerror) < 0)
100 return -1;
101
102 } while (pa_context_is_pending(p->context));
103
104
105 while (pa_mainloop_deferred_pending(p->mainloop)) {
106
107 if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) {
108 if (rerror)
109 *rerror = PA_ERROR_INTERNAL;
110 return -1;
111 }
112
113 if (check_error(p, rerror) < 0)
114 return -1;
115 }
116
117 return 0;
118 }
119
120 pa_simple* pa_simple_new(
121 const char *server,
122 const char *name,
123 pa_stream_direction_t dir,
124 const char *dev,
125 const char *stream_name,
126 const pa_sample_spec *ss,
127 const pa_buffer_attr *attr,
128 int *rerror) {
129
130 pa_simple *p;
131 int error = PA_ERROR_INTERNAL;
132 assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
133
134 p = pa_xmalloc(sizeof(pa_simple));
135 p->context = NULL;
136 p->stream = NULL;
137 p->mainloop = pa_mainloop_new();
138 assert(p->mainloop);
139 p->dead = 0;
140 p->direction = dir;
141 p->read_data = NULL;
142 p->read_index = p->read_length = 0;
143 p->latency = 0;
144
145 if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
146 goto fail;
147
148 pa_context_connect(p->context, server, 1, NULL);
149
150 /* Wait until the context is ready */
151 while (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
152 if (iterate(p, 1, &error) < 0)
153 goto fail;
154 }
155
156 if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL)))
157 goto fail;
158
159 if (dir == PA_STREAM_PLAYBACK)
160 pa_stream_connect_playback(p->stream, dev, attr, 0, NULL);
161 else
162 pa_stream_connect_record(p->stream, dev, attr, 0);
163
164 /* Wait until the stream is ready */
165 while (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
166 if (iterate(p, 1, &error) < 0)
167 goto fail;
168 }
169
170 pa_stream_set_read_callback(p->stream, read_callback, p);
171
172 return p;
173
174 fail:
175 if (rerror)
176 *rerror = error;
177 pa_simple_free(p);
178 return NULL;
179 }
180
181 void pa_simple_free(pa_simple *s) {
182 assert(s);
183
184 pa_xfree(s->read_data);
185
186 if (s->stream)
187 pa_stream_unref(s->stream);
188
189 if (s->context)
190 pa_context_unref(s->context);
191
192 if (s->mainloop)
193 pa_mainloop_free(s->mainloop);
194
195 pa_xfree(s);
196 }
197
198 int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) {
199 assert(p && data && p->direction == PA_STREAM_PLAYBACK);
200
201 if (p->dead) {
202 if (rerror)
203 *rerror = pa_context_errno(p->context);
204
205 return -1;
206 }
207
208 while (length > 0) {
209 size_t l;
210
211 while (!(l = pa_stream_writable_size(p->stream)))
212 if (iterate(p, 1, rerror) < 0)
213 return -1;
214
215 if (l > length)
216 l = length;
217
218 pa_stream_write(p->stream, data, l, NULL, 0);
219 data = (const uint8_t*) data + l;
220 length -= l;
221 }
222
223 /* Make sure that no data is pending for write */
224 if (iterate(p, 0, rerror) < 0)
225 return -1;
226
227 return 0;
228 }
229
230 static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata) {
231 pa_simple *p = userdata;
232 assert(s && data && length && p);
233
234 if (p->read_data) {
235 pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n");
236 pa_xfree(p->read_data);
237 }
238
239 p->read_data = pa_xmemdup(data, p->read_length = length);
240 p->read_index = 0;
241 }
242
243 int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) {
244 assert(p && data && p->direction == PA_STREAM_RECORD);
245
246 if (p->dead) {
247 if (rerror)
248 *rerror = pa_context_errno(p->context);
249
250 return -1;
251 }
252
253 while (length > 0) {
254 if (p->read_data) {
255 size_t l = length;
256
257 if (p->read_length <= l)
258 l = p->read_length;
259
260 memcpy(data, (uint8_t*) p->read_data+p->read_index, l);
261
262 data = (uint8_t*) data + l;
263 length -= l;
264
265 p->read_index += l;
266 p->read_length -= l;
267
268 if (!p->read_length) {
269 pa_xfree(p->read_data);
270 p->read_data = NULL;
271 p->read_index = 0;
272 }
273
274 if (!length)
275 return 0;
276
277 assert(!p->read_data);
278 }
279
280 if (iterate(p, 1, rerror) < 0)
281 return -1;
282 }
283
284 return 0;
285 }
286
287 static void drain_or_flush_complete(pa_stream *s, int success, void *userdata) {
288 pa_simple *p = userdata;
289 assert(s && p);
290 if (!success)
291 p->dead = 1;
292 }
293
294 int pa_simple_drain(pa_simple *p, int *rerror) {
295 pa_operation *o;
296 assert(p && p->direction == PA_STREAM_PLAYBACK);
297
298 if (p->dead) {
299 if (rerror)
300 *rerror = pa_context_errno(p->context);
301
302 return -1;
303 }
304
305 o = pa_stream_drain(p->stream, drain_or_flush_complete, p);
306
307 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
308 if (iterate(p, 1, rerror) < 0) {
309 pa_operation_cancel(o);
310 pa_operation_unref(o);
311 return -1;
312 }
313 }
314
315 pa_operation_unref(o);
316
317 if (p->dead && rerror)
318 *rerror = pa_context_errno(p->context);
319
320 return p->dead ? -1 : 0;
321 }
322
323 static void latency_complete(pa_stream *s, const pa_latency_info *l, void *userdata) {
324 pa_simple *p = userdata;
325 assert(s && p);
326
327 if (!l)
328 p->dead = 1;
329 else {
330 int negative = 0;
331 p->latency = pa_stream_get_latency(s, l, &negative);
332 if (negative)
333 p->latency = 0;
334 }
335 }
336
337 pa_usec_t pa_simple_get_playback_latency(pa_simple *p, int *rerror) {
338 pa_operation *o;
339 assert(p && p->direction == PA_STREAM_PLAYBACK);
340
341 if (p->dead) {
342 if (rerror)
343 *rerror = pa_context_errno(p->context);
344
345 return (pa_usec_t) -1;
346 }
347
348 p->latency = 0;
349 o = pa_stream_get_latency_info(p->stream, latency_complete, p);
350
351 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
352
353 if (iterate(p, 1, rerror) < 0) {
354 pa_operation_cancel(o);
355 pa_operation_unref(o);
356 return -1;
357 }
358 }
359
360 pa_operation_unref(o);
361
362 if (p->dead && rerror)
363 *rerror = pa_context_errno(p->context);
364
365 return p->dead ? (pa_usec_t) -1 : p->latency;
366 }
367
368 int pa_simple_flush(pa_simple *p, int *rerror) {
369 pa_operation *o;
370 assert(p && p->direction == PA_STREAM_PLAYBACK);
371
372 if (p->dead) {
373 if (rerror)
374 *rerror = pa_context_errno(p->context);
375
376 return -1;
377 }
378
379 o = pa_stream_flush(p->stream, drain_or_flush_complete, p);
380
381 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
382 if (iterate(p, 1, rerror) < 0) {
383 pa_operation_cancel(o);
384 pa_operation_unref(o);
385 return -1;
386 }
387 }
388
389 pa_operation_unref(o);
390
391 if (p->dead && rerror)
392 *rerror = pa_context_errno(p->context);
393
394 return p->dead ? -1 : 0;
395 }