4 This file is part of polypaudio.
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.
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.
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
31 #include <polyp/polypaudio.h>
32 #include <polyp/mainloop.h>
34 #include <polypcore/native-common.h>
35 #include <polypcore/xmalloc.h>
36 #include <polypcore/log.h>
41 pa_mainloop
*mainloop
;
44 pa_stream_direction_t direction
;
49 size_t read_index
, read_length
;
53 static void read_callback(pa_stream
*s
, const void*data
, size_t length
, void *userdata
);
55 static int check_error(pa_simple
*p
, int *rerror
) {
56 pa_context_state_t cst
;
57 pa_stream_state_t sst
;
60 if ((cst
= pa_context_get_state(p
->context
)) == PA_CONTEXT_FAILED
)
63 assert(cst
!= PA_CONTEXT_TERMINATED
);
66 if ((sst
= pa_stream_get_state(p
->stream
)) == PA_STREAM_FAILED
)
69 assert(sst
!= PA_STREAM_TERMINATED
);
76 *rerror
= pa_context_errno(p
->context
);
83 static int iterate(pa_simple
*p
, int block
, int *rerror
) {
84 assert(p
&& p
->context
&& p
->mainloop
);
86 if (check_error(p
, rerror
) < 0)
89 if (!block
&& !pa_context_is_pending(p
->context
))
93 if (pa_mainloop_iterate(p
->mainloop
, 1, NULL
) < 0) {
95 *rerror
= PA_ERROR_INTERNAL
;
99 if (check_error(p
, rerror
) < 0)
102 } while (pa_context_is_pending(p
->context
));
105 while (pa_mainloop_deferred_pending(p
->mainloop
)) {
107 if (pa_mainloop_iterate(p
->mainloop
, 0, NULL
) < 0) {
109 *rerror
= PA_ERROR_INTERNAL
;
113 if (check_error(p
, rerror
) < 0)
120 pa_simple
* pa_simple_new(
123 pa_stream_direction_t dir
,
125 const char *stream_name
,
126 const pa_sample_spec
*ss
,
127 const pa_buffer_attr
*attr
,
131 int error
= PA_ERROR_INTERNAL
;
132 assert(ss
&& (dir
== PA_STREAM_PLAYBACK
|| dir
== PA_STREAM_RECORD
));
134 p
= pa_xmalloc(sizeof(pa_simple
));
137 p
->mainloop
= pa_mainloop_new();
142 p
->read_index
= p
->read_length
= 0;
145 if (!(p
->context
= pa_context_new(pa_mainloop_get_api(p
->mainloop
), name
)))
148 pa_context_connect(p
->context
, server
, 1, NULL
);
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)
156 if (!(p
->stream
= pa_stream_new(p
->context
, stream_name
, ss
, NULL
)))
159 if (dir
== PA_STREAM_PLAYBACK
)
160 pa_stream_connect_playback(p
->stream
, dev
, attr
, 0, NULL
);
162 pa_stream_connect_record(p
->stream
, dev
, attr
, 0);
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)
170 pa_stream_set_read_callback(p
->stream
, read_callback
, p
);
181 void pa_simple_free(pa_simple
*s
) {
184 pa_xfree(s
->read_data
);
187 pa_stream_unref(s
->stream
);
190 pa_context_unref(s
->context
);
193 pa_mainloop_free(s
->mainloop
);
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
);
203 *rerror
= pa_context_errno(p
->context
);
211 while (!(l
= pa_stream_writable_size(p
->stream
)))
212 if (iterate(p
, 1, rerror
) < 0)
218 pa_stream_write(p
->stream
, data
, l
, NULL
, 0);
219 data
= (const uint8_t*) data
+ l
;
223 /* Make sure that no data is pending for write */
224 if (iterate(p
, 0, rerror
) < 0)
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
);
235 pa_log(__FILE__
": Buffer overflow, dropping incoming memory blocks.\n");
236 pa_xfree(p
->read_data
);
239 p
->read_data
= pa_xmemdup(data
, p
->read_length
= length
);
243 int pa_simple_read(pa_simple
*p
, void*data
, size_t length
, int *rerror
) {
244 assert(p
&& data
&& p
->direction
== PA_STREAM_RECORD
);
248 *rerror
= pa_context_errno(p
->context
);
257 if (p
->read_length
<= l
)
260 memcpy(data
, (uint8_t*) p
->read_data
+p
->read_index
, l
);
262 data
= (uint8_t*) data
+ l
;
268 if (!p
->read_length
) {
269 pa_xfree(p
->read_data
);
277 assert(!p
->read_data
);
280 if (iterate(p
, 1, rerror
) < 0)
287 static void drain_or_flush_complete(pa_stream
*s
, int success
, void *userdata
) {
288 pa_simple
*p
= userdata
;
294 int pa_simple_drain(pa_simple
*p
, int *rerror
) {
296 assert(p
&& p
->direction
== PA_STREAM_PLAYBACK
);
300 *rerror
= pa_context_errno(p
->context
);
305 o
= pa_stream_drain(p
->stream
, drain_or_flush_complete
, p
);
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
);
315 pa_operation_unref(o
);
317 if (p
->dead
&& rerror
)
318 *rerror
= pa_context_errno(p
->context
);
320 return p
->dead
? -1 : 0;
323 static void latency_complete(pa_stream
*s
, const pa_latency_info
*l
, void *userdata
) {
324 pa_simple
*p
= userdata
;
331 p
->latency
= pa_stream_get_latency(s
, l
, &negative
);
337 pa_usec_t
pa_simple_get_playback_latency(pa_simple
*p
, int *rerror
) {
339 assert(p
&& p
->direction
== PA_STREAM_PLAYBACK
);
343 *rerror
= pa_context_errno(p
->context
);
345 return (pa_usec_t
) -1;
349 o
= pa_stream_get_latency_info(p
->stream
, latency_complete
, p
);
351 while (pa_operation_get_state(o
) == PA_OPERATION_RUNNING
) {
353 if (iterate(p
, 1, rerror
) < 0) {
354 pa_operation_cancel(o
);
355 pa_operation_unref(o
);
360 pa_operation_unref(o
);
362 if (p
->dead
&& rerror
)
363 *rerror
= pa_context_errno(p
->context
);
365 return p
->dead
? (pa_usec_t
) -1 : p
->latency
;
368 int pa_simple_flush(pa_simple
*p
, int *rerror
) {
370 assert(p
&& p
->direction
== PA_STREAM_PLAYBACK
);
374 *rerror
= pa_context_errno(p
->context
);
379 o
= pa_stream_flush(p
->stream
, drain_or_flush_complete
, p
);
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
);
389 pa_operation_unref(o
);
391 if (p
->dead
&& rerror
)
392 *rerror
= pa_context_errno(p
->context
);
394 return p
->dead
? -1 : 0;