rename src to polyp
[profile/ivi/pulseaudio.git] / polyp / sink.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 <stdlib.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 #include "sink.h"
32 #include "sink-input.h"
33 #include "namereg.h"
34 #include "util.h"
35 #include "sample-util.h"
36
37 #define MAX_MIX_CHANNELS 32
38
39 struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) {
40     struct pa_sink *s;
41     char *n = NULL;
42     char st[256];
43     int r;
44     assert(core && name && spec);
45
46     s = malloc(sizeof(struct pa_sink));
47     assert(s);
48
49     if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) {
50         free(s);
51         return NULL;
52     }
53     
54     s->name = strdup(name);
55     s->description = NULL;
56     
57     s->owner = NULL;
58     s->core = core;
59     s->sample_spec = *spec;
60     s->inputs = pa_idxset_new(NULL, NULL);
61
62     n = pa_sprintf_malloc("%s_monitor", name);
63     s->monitor_source = pa_source_new(core, n, 0, spec);
64     assert(s->monitor_source);
65     free(n);
66     s->monitor_source->monitor_of = s;
67     
68     s->volume = PA_VOLUME_NORM;
69
70     s->notify = NULL;
71     s->get_latency = NULL;
72     s->userdata = NULL;
73
74     r = pa_idxset_put(core->sinks, s, &s->index);
75     assert(s->index != PA_IDXSET_INVALID && r >= 0);
76     
77     pa_sample_snprint(st, sizeof(st), spec);
78     fprintf(stderr, "sink: created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st);
79     
80     return s;
81 }
82
83 void pa_sink_free(struct pa_sink *s) {
84     struct pa_sink_input *i, *j = NULL;
85     assert(s);
86
87     pa_namereg_unregister(s->core, s->name);
88     
89     while ((i = pa_idxset_first(s->inputs, NULL))) {
90         assert(i != j);
91         pa_sink_input_kill(i);
92         j = i;
93     }
94     pa_idxset_free(s->inputs, NULL, NULL);
95
96     pa_source_free(s->monitor_source);
97     pa_idxset_remove_by_data(s->core->sinks, s, NULL);
98
99     fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name);
100     
101     free(s->name);
102     free(s->description);
103     free(s);
104 }
105
106 void pa_sink_notify(struct pa_sink*s) {
107     assert(s);
108
109     if (s->notify)
110         s->notify(s);
111 }
112
113 static unsigned fill_mix_info(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo) {
114     uint32_t index = PA_IDXSET_INVALID;
115     struct pa_sink_input *i;
116     unsigned n = 0;
117     
118     assert(s && info);
119
120     for (i = pa_idxset_first(s->inputs, &index); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &index)) {
121         if (pa_sink_input_peek(i, &info->chunk) < 0)
122             continue;
123
124         info->volume = i->volume;
125         
126         assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length);
127         info->userdata = i;
128         
129         info++;
130         maxinfo--;
131         n++;
132     }
133
134     return n;
135 }
136
137 static void inputs_drop(struct pa_sink *s, struct pa_mix_info *info, unsigned maxinfo, size_t length) {
138     assert(s && info);
139     
140     for (; maxinfo > 0; maxinfo--, info++) {
141         struct pa_sink_input *i = info->userdata;
142         assert(i && info->chunk.memblock);
143         
144         pa_memblock_unref(info->chunk.memblock);
145         pa_sink_input_drop(i, length);
146     }
147 }
148         
149 int pa_sink_render(struct pa_sink*s, size_t length, struct pa_memchunk *result) {
150     struct pa_mix_info info[MAX_MIX_CHANNELS];
151     unsigned n;
152     size_t l;
153     assert(s && length && result);
154     
155     n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
156
157     if (n <= 0)
158         return -1;
159
160     if (n == 1) {
161         uint32_t volume = PA_VOLUME_NORM;
162         struct pa_sink_input *i = info[0].userdata;
163         assert(i);
164         *result = info[0].chunk;
165         pa_memblock_ref(result->memblock);
166
167         if (result->length > length)
168             result->length = length;
169
170         l = result->length;
171
172         if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM)
173             volume = pa_volume_multiply(s->volume, info[0].volume);
174         
175         if (volume != PA_VOLUME_NORM) {
176             pa_memchunk_make_writable(result);
177             pa_volume_memchunk(result, &s->sample_spec, volume);
178         }
179     } else {
180         result->memblock = pa_memblock_new(length);
181         assert(result->memblock);
182
183         result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume);
184         result->index = 0;
185         
186         assert(l);
187     }
188
189     inputs_drop(s, info, n, l);
190
191     assert(s->monitor_source);
192     pa_source_post(s->monitor_source, result);
193
194     return 0;
195 }
196
197 int pa_sink_render_into(struct pa_sink*s, struct pa_memchunk *target) {
198     struct pa_mix_info info[MAX_MIX_CHANNELS];
199     unsigned n;
200     size_t l;
201     assert(s && target && target->length && target->memblock && target->memblock->data);
202     
203     n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
204
205     if (n <= 0)
206         return -1;
207
208     if (n == 1) {
209         uint32_t volume = PA_VOLUME_NORM;
210         struct pa_sink_info *i = info[0].userdata;
211         assert(i);
212
213         l = target->length;
214         if (l > info[0].chunk.length)
215             l = info[0].chunk.length;
216         
217         memcpy(target->memblock->data+target->index, info[0].chunk.memblock->data + info[0].chunk.index, l);
218         target->length = l;
219
220         if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM)
221             volume = pa_volume_multiply(s->volume, info[0].volume);
222
223         if (volume != PA_VOLUME_NORM)
224             pa_volume_memchunk(target, &s->sample_spec, volume);
225     } else
226         target->length = l = pa_mix(info, n, target->memblock->data+target->index, target->length, &s->sample_spec, s->volume);
227     
228     assert(l);
229     inputs_drop(s, info, n, l);
230
231     assert(s->monitor_source);
232     pa_source_post(s->monitor_source, target);
233
234     return 0;
235 }
236
237 void pa_sink_render_into_full(struct pa_sink *s, struct pa_memchunk *target) {
238     struct pa_memchunk chunk;
239     size_t l, d;
240     assert(s && target && target->memblock && target->length && target->memblock->data);
241
242     l = target->length;
243     d = 0;
244     while (l > 0) {
245         chunk = *target;
246         chunk.index += d;
247         chunk.length -= d;
248         
249         if (pa_sink_render_into(s, &chunk) < 0)
250             break;
251
252         d += chunk.length;
253         l -= chunk.length;
254     }
255
256     if (l > 0) {
257         chunk = *target;
258         chunk.index += d;
259         chunk.length -= d;
260         pa_silence_memchunk(&chunk, &s->sample_spec);
261     }
262 }
263
264 uint32_t pa_sink_get_latency(struct pa_sink *s) {
265     assert(s);
266
267     if (!s->get_latency)
268         return 0;
269
270     return s->get_latency(s);
271 }
272
273 struct pa_sink* pa_sink_get_default(struct pa_core *c) {
274     struct pa_sink *sink;
275     assert(c);
276
277     if ((sink = pa_idxset_get_by_index(c->sinks, c->default_sink_index)))
278         return sink;
279
280     if (!(sink = pa_idxset_first(c->sinks, &c->default_sink_index)))
281         return NULL;
282
283     fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index);
284     return sink;
285 }
286
287 void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m) {
288     sink->owner = m;
289
290     if (sink->monitor_source)
291         pa_source_set_owner(sink->monitor_source, m);
292 }