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