]> code.delx.au - pulseaudio/blob - src/sink.c
implement parec-simple and matching simple recording API
[pulseaudio] / 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