]> code.delx.au - pulseaudio/blob - polyp/polyplib-simple.c
Make the whole stuff LGPL only
[pulseaudio] / polyp / polyplib-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 "polyplib-simple.h"
32 #include "polyplib.h"
33 #include "mainloop.h"
34 #include "native-common.h"
35 #include "xmalloc.h"
36 #include "log.h"
37
38 struct pa_simple {
39 struct pa_mainloop *mainloop;
40 struct pa_context *context;
41 struct pa_stream *stream;
42 enum pa_stream_direction direction;
43
44 int dead;
45
46 void *read_data;
47 size_t read_index, read_length;
48 pa_usec_t latency;
49 };
50
51 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata);
52
53 static int check_error(struct pa_simple *p, int *perror) {
54 enum pa_context_state cst;
55 enum pa_stream_state sst;
56 assert(p);
57
58 if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED)
59 goto fail;
60
61 assert(cst != PA_CONTEXT_TERMINATED);
62
63 if (p->stream) {
64 if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED)
65 goto fail;
66
67 assert(sst != PA_STREAM_TERMINATED);
68 }
69
70 return 0;
71
72 fail:
73 if (perror)
74 *perror = pa_context_errno(p->context);
75
76 p->dead = 1;
77
78 return -1;
79 }
80
81 static int iterate(struct pa_simple *p, int block, int *perror) {
82 assert(p && p->context && p->mainloop);
83
84 if (check_error(p, perror) < 0)
85 return -1;
86
87 if (!block && !pa_context_is_pending(p->context))
88 return 0;
89
90 do {
91 if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) {
92 if (perror)
93 *perror = PA_ERROR_INTERNAL;
94 return -1;
95 }
96
97 if (check_error(p, perror) < 0)
98 return -1;
99
100 } while (pa_context_is_pending(p->context));
101
102
103 while (pa_mainloop_deferred_pending(p->mainloop)) {
104
105 if (pa_mainloop_iterate(p->mainloop, 0, NULL) < 0) {
106 if (perror)
107 *perror = PA_ERROR_INTERNAL;
108 return -1;
109 }
110
111 if (check_error(p, perror) < 0)
112 return -1;
113 }
114
115 return 0;
116 }
117
118 struct pa_simple* pa_simple_new(
119 const char *server,
120 const char *name,
121 enum pa_stream_direction dir,
122 const char *dev,
123 const char *stream_name,
124 const struct pa_sample_spec *ss,
125 const struct pa_buffer_attr *attr,
126 pa_volume_t volume,
127 int *perror) {
128
129 struct pa_simple *p;
130 int error = PA_ERROR_INTERNAL;
131 assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
132
133 p = pa_xmalloc(sizeof(struct pa_simple));
134 p->context = NULL;
135 p->stream = NULL;
136 p->mainloop = pa_mainloop_new();
137 assert(p->mainloop);
138 p->dead = 0;
139 p->direction = dir;
140 p->read_data = NULL;
141 p->read_index = p->read_length = 0;
142 p->latency = 0;
143
144 if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
145 goto fail;
146
147 pa_context_connect(p->context, server, 1, NULL);
148
149 /* Wait until the context is ready */
150 while (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
151 if (iterate(p, 1, &error) < 0)
152 goto fail;
153 }
154
155 if (!(p->stream = pa_stream_new(p->context, stream_name, ss)))
156 goto fail;
157
158 if (dir == PA_STREAM_PLAYBACK)
159 pa_stream_connect_playback(p->stream, dev, attr, 0, volume);
160 else
161 pa_stream_connect_record(p->stream, dev, attr, 0);
162
163 /* Wait until the stream is ready */
164 while (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
165 if (iterate(p, 1, &error) < 0)
166 goto fail;
167 }
168
169 pa_stream_set_read_callback(p->stream, read_callback, p);
170
171 return p;
172
173 fail:
174 if (perror)
175 *perror = error;
176 pa_simple_free(p);
177 return NULL;
178 }
179
180 void pa_simple_free(struct pa_simple *s) {
181 assert(s);
182
183 pa_xfree(s->read_data);
184
185 if (s->stream)
186 pa_stream_unref(s->stream);
187
188 if (s->context)
189 pa_context_unref(s->context);
190
191 if (s->mainloop)
192 pa_mainloop_free(s->mainloop);
193
194 pa_xfree(s);
195 }
196
197 int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) {
198 assert(p && data && p->direction == PA_STREAM_PLAYBACK);
199
200 if (p->dead) {
201 if (perror)
202 *perror = pa_context_errno(p->context);
203
204 return -1;
205 }
206
207 while (length > 0) {
208 size_t l;
209
210 while (!(l = pa_stream_writable_size(p->stream)))
211 if (iterate(p, 1, perror) < 0)
212 return -1;
213
214 if (l > length)
215 l = length;
216
217 pa_stream_write(p->stream, data, l, NULL, 0);
218 data = (uint8_t*) data + l;
219 length -= l;
220 }
221
222 /* Make sure that no data is pending for write */
223 if (iterate(p, 0, perror) < 0)
224 return -1;
225
226 return 0;
227 }
228
229 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) {
230 struct pa_simple *p = userdata;
231 assert(s && data && length && p);
232
233 if (p->read_data) {
234 pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n");
235 pa_xfree(p->read_data);
236 }
237
238 p->read_data = pa_xmemdup(data, p->read_length = length);
239 p->read_index = 0;
240 }
241
242 int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) {
243 assert(p && data && p->direction == PA_STREAM_RECORD);
244
245 if (p->dead) {
246 if (perror)
247 *perror = pa_context_errno(p->context);
248
249 return -1;
250 }
251
252 while (length > 0) {
253 if (p->read_data) {
254 size_t l = length;
255
256 if (p->read_length <= l)
257 l = p->read_length;
258
259 memcpy(data, (uint8_t*) p->read_data+p->read_index, l);
260
261 data = (uint8_t*) data + l;
262 length -= l;
263
264 p->read_index += l;
265 p->read_length -= l;
266
267 if (!p->read_length) {
268 pa_xfree(p->read_data);
269 p->read_data = NULL;
270 p->read_index = 0;
271 }
272
273 if (!length)
274 return 0;
275
276 assert(!p->read_data);
277 }
278
279 if (iterate(p, 1, perror) < 0)
280 return -1;
281 }
282
283 return 0;
284 }
285
286 static void drain_or_flush_complete(struct pa_stream *s, int success, void *userdata) {
287 struct pa_simple *p = userdata;
288 assert(s && p);
289 if (!success)
290 p->dead = 1;
291 }
292
293 int pa_simple_drain(struct pa_simple *p, int *perror) {
294 struct pa_operation *o;
295 assert(p && p->direction == PA_STREAM_PLAYBACK);
296
297 if (p->dead) {
298 if (perror)
299 *perror = pa_context_errno(p->context);
300
301 return -1;
302 }
303
304 o = pa_stream_drain(p->stream, drain_or_flush_complete, p);
305
306 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
307 if (iterate(p, 1, perror) < 0) {
308 pa_operation_cancel(o);
309 pa_operation_unref(o);
310 return -1;
311 }
312 }
313
314 pa_operation_unref(o);
315
316 if (p->dead && perror)
317 *perror = pa_context_errno(p->context);
318
319 return p->dead ? -1 : 0;
320 }
321
322 static void latency_complete(struct pa_stream *s, const struct pa_latency_info *l, void *userdata) {
323 struct pa_simple *p = userdata;
324 assert(s && p);
325
326 if (!l)
327 p->dead = 1;
328 else {
329 int negative = 0;
330 p->latency = pa_stream_get_latency(s, l, &negative);
331 if (negative)
332 p->latency = 0;
333 }
334 }
335
336 pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) {
337 struct pa_operation *o;
338 assert(p && p->direction == PA_STREAM_PLAYBACK);
339
340 if (p->dead) {
341 if (perror)
342 *perror = pa_context_errno(p->context);
343
344 return (pa_usec_t) -1;
345 }
346
347 p->latency = 0;
348 o = pa_stream_get_latency_info(p->stream, latency_complete, p);
349
350 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
351
352 if (iterate(p, 1, perror) < 0) {
353 pa_operation_cancel(o);
354 pa_operation_unref(o);
355 return -1;
356 }
357 }
358
359 pa_operation_unref(o);
360
361 if (p->dead && perror)
362 *perror = pa_context_errno(p->context);
363
364 return p->dead ? (pa_usec_t) -1 : p->latency;
365 }
366
367 int pa_simple_flush(struct pa_simple *p, int *perror) {
368 struct pa_operation *o;
369 assert(p && p->direction == PA_STREAM_PLAYBACK);
370
371 if (p->dead) {
372 if (perror)
373 *perror = pa_context_errno(p->context);
374
375 return -1;
376 }
377
378 o = pa_stream_flush(p->stream, drain_or_flush_complete, p);
379
380 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
381 if (iterate(p, 1, perror) < 0) {
382 pa_operation_cancel(o);
383 pa_operation_unref(o);
384 return -1;
385 }
386 }
387
388 pa_operation_unref(o);
389
390 if (p->dead && perror)
391 *perror = pa_context_errno(p->context);
392
393 return p->dead ? -1 : 0;
394 }