make a symbol in module-ptorocol-stub static
[profile/ivi/pulseaudio.git] / src / polyplib-simple.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4 #include <stdlib.h>
5
6 #include "simple.h"
7 #include "polyp.h"
8 #include "mainloop.h"
9 #include "polyp-error.h"
10
11 struct pa_simple {
12     struct pa_mainloop *mainloop;
13     struct pa_context *context;
14     struct pa_stream *stream;
15     enum pa_stream_direction direction;
16
17     int dead, drained;
18
19     void *read_data;
20     size_t read_index, read_length;
21 };
22
23 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata);
24
25 static int check_error(struct pa_simple *p, int *perror) {
26     assert(p);
27     
28     if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) {
29         if (perror)
30             *perror = pa_context_errno(p->context);
31         return -1;
32     }
33
34     return 0;
35 }
36
37 static int iterate(struct pa_simple *p, int block, int *perror) {
38     assert(p && p->context && p->mainloop);
39
40     if (check_error(p, perror) < 0)
41         return -1;
42     
43     if (!block && !pa_context_is_pending(p->context))
44         return 0;
45
46     do {
47         if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) {
48             if (perror)
49                 *perror = PA_ERROR_INTERNAL;
50             return -1;
51         }
52
53         if (check_error(p, perror) < 0)
54             return -1;
55         
56     } while (pa_context_is_pending(p->context));
57
58     return 0;
59 }
60
61 struct pa_simple* pa_simple_new(
62     const char *server,
63     const char *name,
64     enum pa_stream_direction dir,
65     const char *dev,
66     const char *stream_name,
67     const struct pa_sample_spec *ss,
68     const struct pa_buffer_attr *attr,
69     int *perror) {
70     
71     struct pa_simple *p;
72     int error = PA_ERROR_INTERNAL;
73     assert(ss);
74
75     p = malloc(sizeof(struct pa_simple));
76     assert(p);
77     p->context = NULL;
78     p->stream = NULL;
79     p->mainloop = pa_mainloop_new();
80     assert(p->mainloop);
81     p->dead = 0;
82     p->direction = dir;
83     p->read_data = NULL;
84     p->read_index = p->read_length = 0;
85
86     if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
87         goto fail;
88
89     if (pa_context_connect(p->context, server, NULL, NULL) < 0) {
90         error = pa_context_errno(p->context);
91         goto fail;
92     }
93
94     /* Wait until the context is ready */
95     while (!pa_context_is_ready(p->context)) {
96         if (iterate(p, 1, &error) < 0)
97             goto fail;
98     }
99
100     if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL)))
101         goto fail;
102
103     /* Wait until the stream is ready */
104     while (!pa_stream_is_ready(p->stream)) {
105         if (iterate(p, 1, &error) < 0)
106             goto fail;
107     }
108
109     pa_stream_set_read_callback(p->stream, read_callback, p);
110     
111     return p;
112     
113 fail:
114     if (perror)
115         *perror = error;
116     pa_simple_free(p);
117     return NULL;
118 }
119
120 void pa_simple_free(struct pa_simple *s) {
121     assert(s);
122
123     free(s->read_data);
124
125     if (s->stream)
126         pa_stream_free(s->stream);
127     
128     if (s->context)
129         pa_context_free(s->context);
130
131     if (s->mainloop)
132         pa_mainloop_free(s->mainloop);
133
134     free(s);
135 }
136
137 int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) {
138     assert(p && data && p->direction == PA_STREAM_PLAYBACK);
139
140     while (length > 0) {
141         size_t l;
142         
143         while (!(l = pa_stream_writable_size(p->stream)))
144             if (iterate(p, 1, perror) < 0)
145                 return -1;
146
147         if (l > length)
148             l = length;
149
150         pa_stream_write(p->stream, data, l);
151         data += l;
152         length -= l;
153     }
154
155     /* Make sure that no data is pending for write */
156     if (iterate(p, 0, perror) < 0)
157         return -1;
158
159     return 0;
160 }
161
162 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata) {
163     struct pa_simple *p = userdata;
164     assert(s && data && length && p);
165
166     if (p->read_data) {
167         fprintf(stderr, __FILE__": Buffer overflow, dropping incoming memory blocks.\n");
168         free(p->read_data);
169     }
170
171     p->read_data = malloc(p->read_length = length);
172     assert(p->read_data);
173     memcpy(p->read_data, data, length);
174     p->read_index = 0;
175 }
176
177 int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) {
178     assert(p && data && p->direction == PA_STREAM_RECORD);
179
180     while (length > 0) {
181         if (p->read_data) {
182             size_t l = length;
183
184             if (p->read_length <= l)
185                 l = p->read_length;
186
187             memcpy(data, p->read_data+p->read_index, l);
188
189             data += l;
190             length -= l;
191             
192             p->read_index += l;
193             p->read_length -= l;
194
195             if (!p->read_length) {
196                 free(p->read_data);
197                 p->read_data = NULL;
198                 p->read_index = 0;
199             }
200             
201             if (!length)
202                 return 0;
203
204             assert(!p->read_data);
205         }
206
207         if (iterate(p, 1, perror) < 0)
208             return -1;
209     }
210
211     return 0;
212 }
213
214 static void drain_complete(struct pa_stream *s, void *userdata) {
215     struct pa_simple *p = userdata;
216     assert(s && p);
217     p->drained = 1;
218 }
219
220 int pa_simple_drain(struct pa_simple *p, int *perror) {
221     assert(p && p->direction == PA_STREAM_PLAYBACK);
222     p->drained = 0;
223     pa_stream_drain(p->stream, drain_complete, p);
224
225     while (!p->drained) {
226         if (iterate(p, 1, perror) < 0) {
227             pa_stream_drain(p->stream, NULL, NULL);
228             return -1;
229         }
230     }
231
232     return 0;
233 }