]> code.delx.au - pulseaudio/blob - polyp/polyplib-simple.c
remove most -W compiler warnings
[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
37 struct pa_simple {
38 struct pa_mainloop *mainloop;
39 struct pa_context *context;
40 struct pa_stream *stream;
41 enum pa_stream_direction direction;
42
43 int dead, drained;
44
45 void *read_data;
46 size_t read_index, read_length;
47 };
48
49 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata);
50
51 static int check_error(struct pa_simple *p, int *perror) {
52 enum pa_context_state cst;
53 enum pa_stream_state sst;
54 assert(p);
55
56 if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED)
57 goto fail;
58
59 assert(cst != PA_CONTEXT_TERMINATED);
60
61 if (p->stream) {
62 if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED)
63 goto fail;
64
65 assert(sst != PA_STREAM_TERMINATED);
66 }
67
68 return 0;
69
70 fail:
71 if (perror)
72 *perror = pa_context_errno(p->context);
73 return -1;
74 }
75
76 static int iterate(struct pa_simple *p, int block, int *perror) {
77 assert(p && p->context && p->mainloop);
78
79 if (check_error(p, perror) < 0)
80 return -1;
81
82 if (!block && !pa_context_is_pending(p->context))
83 return 0;
84
85 do {
86 if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) {
87 if (perror)
88 *perror = PA_ERROR_INTERNAL;
89 return -1;
90 }
91
92 if (check_error(p, perror) < 0)
93 return -1;
94
95 } while (pa_context_is_pending(p->context));
96
97 return 0;
98 }
99
100 struct pa_simple* pa_simple_new(
101 const char *server,
102 const char *name,
103 enum pa_stream_direction dir,
104 const char *dev,
105 const char *stream_name,
106 const struct pa_sample_spec *ss,
107 const struct pa_buffer_attr *attr,
108 int *perror) {
109
110 struct pa_simple *p;
111 int error = PA_ERROR_INTERNAL;
112 assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
113
114 p = pa_xmalloc(sizeof(struct pa_simple));
115 p->context = NULL;
116 p->stream = NULL;
117 p->mainloop = pa_mainloop_new();
118 assert(p->mainloop);
119 p->dead = 0;
120 p->direction = dir;
121 p->read_data = NULL;
122 p->read_index = p->read_length = 0;
123
124 if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
125 goto fail;
126
127 pa_context_connect(p->context, server);
128
129 /* Wait until the context is ready */
130 while (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
131 if (iterate(p, 1, &error) < 0)
132 goto fail;
133 }
134
135 if (!(p->stream = pa_stream_new(p->context, stream_name, ss)))
136 goto fail;
137
138 if (dir == PA_STREAM_PLAYBACK)
139 pa_stream_connect_playback(p->stream, dev, attr);
140 else
141 pa_stream_connect_record(p->stream, dev, attr);
142
143 /* Wait until the stream is ready */
144 while (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
145 if (iterate(p, 1, &error) < 0)
146 goto fail;
147 }
148
149 pa_stream_set_read_callback(p->stream, read_callback, p);
150
151 return p;
152
153 fail:
154 if (perror)
155 *perror = error;
156 pa_simple_free(p);
157 return NULL;
158 }
159
160 void pa_simple_free(struct pa_simple *s) {
161 assert(s);
162
163 pa_xfree(s->read_data);
164
165 if (s->stream)
166 pa_stream_unref(s->stream);
167
168 if (s->context)
169 pa_context_unref(s->context);
170
171 if (s->mainloop)
172 pa_mainloop_free(s->mainloop);
173
174 pa_xfree(s);
175 }
176
177 int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) {
178 assert(p && data && p->direction == PA_STREAM_PLAYBACK);
179
180 while (length > 0) {
181 size_t l;
182
183 while (!(l = pa_stream_writable_size(p->stream)))
184 if (iterate(p, 1, perror) < 0)
185 return -1;
186
187 if (l > length)
188 l = length;
189
190 pa_stream_write(p->stream, data, l, NULL, 0);
191 data = (uint8_t*) data + l;
192 length -= l;
193 }
194
195 /* Make sure that no data is pending for write */
196 if (iterate(p, 0, perror) < 0)
197 return -1;
198
199 return 0;
200 }
201
202 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) {
203 struct pa_simple *p = userdata;
204 assert(s && data && length && p);
205
206 if (p->read_data) {
207 fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n");
208 pa_xfree(p->read_data);
209 }
210
211 p->read_data = pa_xmemdup(data, p->read_length = length);
212 p->read_index = 0;
213 }
214
215 int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) {
216 assert(p && data && p->direction == PA_STREAM_RECORD);
217
218 while (length > 0) {
219 if (p->read_data) {
220 size_t l = length;
221
222 if (p->read_length <= l)
223 l = p->read_length;
224
225 memcpy(data, (uint8_t*) p->read_data+p->read_index, l);
226
227 data = (uint8_t*) data + l;
228 length -= l;
229
230 p->read_index += l;
231 p->read_length -= l;
232
233 if (!p->read_length) {
234 pa_xfree(p->read_data);
235 p->read_data = NULL;
236 p->read_index = 0;
237 }
238
239 if (!length)
240 return 0;
241
242 assert(!p->read_data);
243 }
244
245 if (iterate(p, 1, perror) < 0)
246 return -1;
247 }
248
249 return 0;
250 }
251
252 static void drain_complete(struct pa_stream *s, int success, void *userdata) {
253 struct pa_simple *p = userdata;
254 assert(s && p);
255 p->drained = success ? 1 : -1;
256 }
257
258 int pa_simple_drain(struct pa_simple *p, int *perror) {
259 struct pa_operation *o;
260
261 assert(p && p->direction == PA_STREAM_PLAYBACK);
262 p->drained = 0;
263 o = pa_stream_drain(p->stream, drain_complete, p);
264
265 while (!p->drained) {
266 if (iterate(p, 1, perror) < 0) {
267 pa_operation_cancel(o);
268 pa_operation_unref(o);
269 return -1;
270 }
271 }
272
273 pa_operation_unref(o);
274
275 if (p->drained < 0 && perror)
276 *perror = pa_context_errno(p->context);
277
278 return 0;
279 }