]> code.delx.au - pulseaudio/blob - polyp/polyplib-simple.c
update simple API
[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 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 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 return 0;
103 }
104
105 struct pa_simple* pa_simple_new(
106 const char *server,
107 const char *name,
108 enum pa_stream_direction dir,
109 const char *dev,
110 const char *stream_name,
111 const struct pa_sample_spec *ss,
112 const struct pa_buffer_attr *attr,
113 int *perror) {
114
115 struct pa_simple *p;
116 int error = PA_ERROR_INTERNAL;
117 assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
118
119 p = pa_xmalloc(sizeof(struct pa_simple));
120 p->context = NULL;
121 p->stream = NULL;
122 p->mainloop = pa_mainloop_new();
123 assert(p->mainloop);
124 p->dead = 0;
125 p->direction = dir;
126 p->read_data = NULL;
127 p->read_index = p->read_length = 0;
128 p->latency = 0;
129
130 if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
131 goto fail;
132
133 pa_context_connect(p->context, server);
134
135 /* Wait until the context is ready */
136 while (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
137 if (iterate(p, 1, &error) < 0)
138 goto fail;
139 }
140
141 if (!(p->stream = pa_stream_new(p->context, stream_name, ss)))
142 goto fail;
143
144 if (dir == PA_STREAM_PLAYBACK)
145 pa_stream_connect_playback(p->stream, dev, attr);
146 else
147 pa_stream_connect_record(p->stream, dev, attr);
148
149 /* Wait until the stream is ready */
150 while (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
151 if (iterate(p, 1, &error) < 0)
152 goto fail;
153 }
154
155 pa_stream_set_read_callback(p->stream, read_callback, p);
156
157 return p;
158
159 fail:
160 if (perror)
161 *perror = error;
162 pa_simple_free(p);
163 return NULL;
164 }
165
166 void pa_simple_free(struct pa_simple *s) {
167 assert(s);
168
169 pa_xfree(s->read_data);
170
171 if (s->stream)
172 pa_stream_unref(s->stream);
173
174 if (s->context)
175 pa_context_unref(s->context);
176
177 if (s->mainloop)
178 pa_mainloop_free(s->mainloop);
179
180 pa_xfree(s);
181 }
182
183 int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) {
184 assert(p && data && p->direction == PA_STREAM_PLAYBACK);
185
186 if (p->dead) {
187 if (perror)
188 *perror = pa_context_errno(p->context);
189
190 return -1;
191 }
192
193 while (length > 0) {
194 size_t l;
195
196 while (!(l = pa_stream_writable_size(p->stream)))
197 if (iterate(p, 1, perror) < 0)
198 return -1;
199
200 if (l > length)
201 l = length;
202
203 pa_stream_write(p->stream, data, l, NULL, 0);
204 data = (uint8_t*) data + l;
205 length -= l;
206 }
207
208 /* Make sure that no data is pending for write */
209 if (iterate(p, 0, perror) < 0)
210 return -1;
211
212 return 0;
213 }
214
215 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) {
216 struct pa_simple *p = userdata;
217 assert(s && data && length && p);
218
219 if (p->read_data) {
220 pa_log(__FILE__": Buffer overflow, dropping incoming memory blocks.\n");
221 pa_xfree(p->read_data);
222 }
223
224 p->read_data = pa_xmemdup(data, p->read_length = length);
225 p->read_index = 0;
226 }
227
228 int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) {
229 assert(p && data && p->direction == PA_STREAM_RECORD);
230
231 if (p->dead) {
232 if (perror)
233 *perror = pa_context_errno(p->context);
234
235 return -1;
236 }
237
238 while (length > 0) {
239 if (p->read_data) {
240 size_t l = length;
241
242 if (p->read_length <= l)
243 l = p->read_length;
244
245 memcpy(data, (uint8_t*) p->read_data+p->read_index, l);
246
247 data = (uint8_t*) data + l;
248 length -= l;
249
250 p->read_index += l;
251 p->read_length -= l;
252
253 if (!p->read_length) {
254 pa_xfree(p->read_data);
255 p->read_data = NULL;
256 p->read_index = 0;
257 }
258
259 if (!length)
260 return 0;
261
262 assert(!p->read_data);
263 }
264
265 if (iterate(p, 1, perror) < 0)
266 return -1;
267 }
268
269 return 0;
270 }
271
272 static void drain_or_flush_complete(struct pa_stream *s, int success, void *userdata) {
273 struct pa_simple *p = userdata;
274 assert(s && p);
275 if (!success)
276 p->dead = 1;
277 }
278
279 int pa_simple_drain(struct pa_simple *p, int *perror) {
280 struct pa_operation *o;
281 assert(p && p->direction == PA_STREAM_PLAYBACK);
282
283 if (p->dead) {
284 if (perror)
285 *perror = pa_context_errno(p->context);
286
287 return -1;
288 }
289
290 o = pa_stream_drain(p->stream, drain_or_flush_complete, p);
291
292 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
293 if (iterate(p, 1, perror) < 0) {
294 pa_operation_cancel(o);
295 pa_operation_unref(o);
296 return -1;
297 }
298 }
299
300 pa_operation_unref(o);
301
302 if (p->dead && perror)
303 *perror = pa_context_errno(p->context);
304
305 return p->dead ? -1 : 0;
306 }
307
308 static void latency_complete(struct pa_stream *s, const struct pa_latency_info *l, void *userdata) {
309 struct pa_simple *p = userdata;
310 assert(s && p);
311
312 if (!l)
313 p->dead = 1;
314 else
315 p->latency = l->buffer_usec + l->sink_usec + l->transport_usec;
316 }
317
318 pa_usec_t pa_simple_get_playback_latency(struct pa_simple *p, int *perror) {
319 struct pa_operation *o;
320 assert(p && p->direction == PA_STREAM_PLAYBACK);
321
322 if (p->dead) {
323 if (perror)
324 *perror = pa_context_errno(p->context);
325
326 return (pa_usec_t) -1;
327 }
328
329 p->latency = 0;
330 o = pa_stream_get_latency(p->stream, latency_complete, p);
331
332 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
333
334 if (iterate(p, 1, perror) < 0) {
335 pa_operation_cancel(o);
336 pa_operation_unref(o);
337 return -1;
338 }
339 }
340
341 pa_operation_unref(o);
342
343 if (p->dead && perror)
344 *perror = pa_context_errno(p->context);
345
346 return p->dead ? (pa_usec_t) -1 : p->latency;
347 }
348
349 int pa_simple_flush(struct pa_simple *p, int *perror) {
350 struct pa_operation *o;
351 assert(p && p->direction == PA_STREAM_PLAYBACK);
352
353 if (p->dead) {
354 if (perror)
355 *perror = pa_context_errno(p->context);
356
357 return -1;
358 }
359
360 o = pa_stream_flush(p->stream, drain_or_flush_complete, p);
361
362 while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
363 if (iterate(p, 1, perror) < 0) {
364 pa_operation_cancel(o);
365 pa_operation_unref(o);
366 return -1;
367 }
368 }
369
370 pa_operation_unref(o);
371
372 if (p->dead && perror)
373 *perror = pa_context_errno(p->context);
374
375 return p->dead ? -1 : 0;
376 }