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