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