add output stream draining
[platform/upstream/pulseaudio.git] / src / simple.c
1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include "simple.h"
5 #include "polyp.h"
6 #include "mainloop.h"
7 #include "polyp-error.h"
8
9 struct pa_simple {
10     struct pa_mainloop *mainloop;
11     struct pa_context *context;
12     struct pa_stream *stream;
13
14     int dead, drained;
15 };
16
17 static int iterate(struct pa_simple *p, int block, int *perror) {
18     assert(p && p->context && p->mainloop);
19
20     if (!block && !pa_context_is_pending(p->context))
21         return 0;
22     
23     do {
24         if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) {
25             if (perror)
26                 *perror = pa_context_errno(p->context);
27             return -1;
28         }
29         
30         if (pa_mainloop_iterate(p->mainloop, 1, NULL) < 0) {
31             if (perror)
32                 *perror = PA_ERROR_INTERNAL;
33             return -1;
34         }
35     } while (pa_context_is_pending(p->context));
36
37     return 0;
38 }
39
40 struct pa_simple* pa_simple_new(
41     const char *server,
42     const char *name,
43     enum pa_stream_direction dir,
44     const char *dev,
45     const char *stream_name,
46     const struct pa_sample_spec *ss,
47     const struct pa_buffer_attr *attr,
48     int *perror) {
49     
50     struct pa_simple *p;
51     int error = PA_ERROR_INTERNAL;
52     assert(ss);
53
54     p = malloc(sizeof(struct pa_simple));
55     assert(p);
56     p->context = NULL;
57     p->stream = NULL;
58     p->mainloop = pa_mainloop_new();
59     assert(p->mainloop);
60     p->dead = 0;
61
62     if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
63         goto fail;
64
65     if (pa_context_connect(p->context, server, NULL, NULL) < 0) {
66         error = pa_context_errno(p->context);
67         goto fail;
68     }
69
70     /* Wait until the context is ready */
71     while (!pa_context_is_ready(p->context)) {
72         if (iterate(p, 1, &error) < 0)
73             goto fail;
74     }
75
76     if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL)))
77         goto fail;
78
79     /* Wait until the stream is ready */
80     while (!pa_stream_is_ready(p->stream)) {
81         if (iterate(p, 1, &error) < 0)
82             goto fail;
83     }
84
85     return p;
86     
87 fail:
88     if (perror)
89         *perror = error;
90     pa_simple_free(p);
91     return NULL;
92 }
93
94 void pa_simple_free(struct pa_simple *s) {
95     assert(s);
96
97     if (s->stream)
98         pa_stream_free(s->stream);
99     
100     if (s->context)
101         pa_context_free(s->context);
102
103     if (s->mainloop)
104         pa_mainloop_free(s->mainloop);
105
106     free(s);
107 }
108
109 int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *perror) {
110     assert(p && data);
111
112     while (length > 0) {
113         size_t l;
114         
115         while (!(l = pa_stream_writable_size(p->stream)))
116             if (iterate(p, 1, perror) < 0)
117                 return -1;
118
119         if (l > length)
120             l = length;
121
122         pa_stream_write(p->stream, data, l);
123         data += l;
124         length -= l;
125     }
126
127     /* Make sure that no data is pending for write */
128     if (iterate(p, 0, perror) < 0)
129         return -1;
130
131     return 0;
132 }
133
134 int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *perror) {
135     assert(0);
136 }
137
138
139 static void drain_complete(struct pa_stream *s, void *userdata) {
140     struct pa_simple *p = userdata;
141     assert(s && p);
142     p->drained = 1;
143 }
144
145 int pa_simple_drain(struct pa_simple *p, int *perror) {
146     assert(p);
147     p->drained = 0;
148     pa_stream_drain(p->stream, drain_complete, p);
149
150     while (!p->drained) {
151         if (iterate(p, 1, perror) < 0) {
152             pa_stream_drain(p->stream, NULL, NULL);
153             return -1;
154         }
155     }
156
157     return 0;
158 }