]> code.delx.au - pulseaudio/blob - src/polypcore/sink-input.c
bd2a1dcd178905374b74769040cfd2d1fc835bb0
[pulseaudio] / src / polypcore / sink-input.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 Lesser 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 Lesser 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 <stdio.h>
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <polyp/utf8.h>
32 #include <polyp/xmalloc.h>
33
34 #include <polypcore/sample-util.h>
35 #include <polypcore/core-subscribe.h>
36 #include <polypcore/log.h>
37
38 #include "sink-input.h"
39
40 #define CONVERT_BUFFER_LENGTH 4096
41
42 #define CHECK_VALIDITY_RETURN_NULL(condition) \
43 do {\
44 if (!(condition)) \
45 return NULL; \
46 } while (0)
47
48 pa_sink_input* pa_sink_input_new(
49 pa_sink *s,
50 const char *driver,
51 const char *name,
52 const pa_sample_spec *spec,
53 const pa_channel_map *map,
54 const pa_cvolume *volume,
55 int variable_rate,
56 int resample_method) {
57
58 pa_sink_input *i;
59 pa_resampler *resampler = NULL;
60 int r;
61 char st[256];
62 pa_channel_map tmap;
63 pa_cvolume tvol;
64
65 assert(s);
66 assert(spec);
67 assert(s->state == PA_SINK_RUNNING);
68
69 CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec));
70
71 if (!map)
72 map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT);
73 if (!volume)
74 volume = pa_cvolume_reset(&tvol, spec->channels);
75
76 CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map));
77 CHECK_VALIDITY_RETURN_NULL(volume && pa_cvolume_valid(volume));
78 CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels);
79 CHECK_VALIDITY_RETURN_NULL(volume->channels == spec->channels);
80 CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver));
81 CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name));
82
83 if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) {
84 pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink.");
85 return NULL;
86 }
87
88 if (resample_method == PA_RESAMPLER_INVALID)
89 resample_method = s->core->resample_method;
90
91 if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map))
92 if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method)))
93 return NULL;
94
95 i = pa_xnew(pa_sink_input, 1);
96 i->ref = 1;
97 i->state = PA_SINK_INPUT_RUNNING;
98 i->name = pa_xstrdup(name);
99 i->driver = pa_xstrdup(driver);
100 i->owner = NULL;
101 i->sink = s;
102 i->client = NULL;
103
104 i->sample_spec = *spec;
105 i->channel_map = *map;
106 i->volume = *volume;
107
108 i->peek = NULL;
109 i->drop = NULL;
110 i->kill = NULL;
111 i->get_latency = NULL;
112 i->underrun = NULL;
113 i->userdata = NULL;
114
115 i->playing = 0;
116
117 pa_memchunk_reset(&i->resampled_chunk);
118 i->resampler = resampler;
119
120 assert(s->core);
121 r = pa_idxset_put(s->core->sink_inputs, i, &i->index);
122 assert(r == 0 && i->index != PA_IDXSET_INVALID);
123 r = pa_idxset_put(s->inputs, i, NULL);
124 assert(r == 0);
125
126 pa_sample_spec_snprint(st, sizeof(st), spec);
127 pa_log_info(__FILE__": created %u \"%s\" on %u with sample spec \"%s\"", i->index, i->name, s->index, st);
128
129 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
130
131 return i;
132 }
133
134 void pa_sink_input_disconnect(pa_sink_input *i) {
135 assert(i);
136 assert(i->state != PA_SINK_INPUT_DISCONNECTED);
137 assert(i->sink);
138 assert(i->sink->core);
139
140 pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
141 pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
142
143 pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
144 i->sink = NULL;
145
146 i->peek = NULL;
147 i->drop = NULL;
148 i->kill = NULL;
149 i->get_latency = NULL;
150 i->underrun = NULL;
151
152 i->playing = 0;
153 i->state = PA_SINK_INPUT_DISCONNECTED;
154 }
155
156 static void sink_input_free(pa_sink_input* i) {
157 assert(i);
158
159 if (i->state != PA_SINK_INPUT_DISCONNECTED)
160 pa_sink_input_disconnect(i);
161
162 pa_log_info(__FILE__": freed %u \"%s\"", i->index, i->name);
163
164 if (i->resampled_chunk.memblock)
165 pa_memblock_unref(i->resampled_chunk.memblock);
166
167 if (i->resampler)
168 pa_resampler_free(i->resampler);
169
170 pa_xfree(i->name);
171 pa_xfree(i->driver);
172 pa_xfree(i);
173 }
174
175 void pa_sink_input_unref(pa_sink_input *i) {
176 assert(i);
177 assert(i->ref >= 1);
178
179 if (!(--i->ref))
180 sink_input_free(i);
181 }
182
183 pa_sink_input* pa_sink_input_ref(pa_sink_input *i) {
184 assert(i);
185 assert(i->ref >= 1);
186
187 i->ref++;
188 return i;
189 }
190
191 void pa_sink_input_kill(pa_sink_input*i) {
192 assert(i);
193 assert(i->ref >= 1);
194
195 if (i->kill)
196 i->kill(i);
197 }
198
199 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
200 pa_usec_t r = 0;
201
202 assert(i);
203 assert(i->ref >= 1);
204
205 if (i->get_latency)
206 r += i->get_latency(i);
207
208 if (i->resampled_chunk.memblock)
209 r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sample_spec);
210
211 return r;
212 }
213
214 int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) {
215 int ret = -1;
216 int do_volume_adj_here;
217
218 assert(i);
219 assert(i->ref >= 1);
220 assert(chunk);
221 assert(volume);
222
223 pa_sink_input_ref(i);
224
225 if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED)
226 goto finish;
227
228 if (!i->resampler) {
229 do_volume_adj_here = 0;
230 ret = i->peek(i, chunk);
231 goto finish;
232 }
233
234 do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
235
236 while (!i->resampled_chunk.memblock) {
237 pa_memchunk tchunk;
238 size_t l;
239
240 if ((ret = i->peek(i, &tchunk)) < 0)
241 goto finish;
242
243 assert(tchunk.length);
244
245 l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
246
247 if (l > tchunk.length)
248 l = tchunk.length;
249
250 i->drop(i, &tchunk, l);
251 tchunk.length = l;
252
253 /* It might be necessary to adjust the volume here */
254 if (do_volume_adj_here) {
255 pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0);
256 pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume);
257 }
258
259 pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk);
260 pa_memblock_unref(tchunk.memblock);
261 }
262
263 assert(i->resampled_chunk.memblock);
264 assert(i->resampled_chunk.length);
265
266 *chunk = i->resampled_chunk;
267 pa_memblock_ref(i->resampled_chunk.memblock);
268
269 ret = 0;
270
271 finish:
272
273 if (ret < 0 && i->playing && i->underrun)
274 i->underrun(i);
275
276 i->playing = ret >= 0;
277
278 if (ret >= 0) {
279 /* Let's see if we had to apply the volume adjustment
280 * ourselves, or if this can be done by the sink for us */
281
282 if (do_volume_adj_here)
283 /* We had different channel maps, so we already did the adjustment */
284 pa_cvolume_reset(volume, i->sink->sample_spec.channels);
285 else
286 /* We've both the same channel map, so let's have the sink do the adjustment for us*/
287 *volume = i->volume;
288 }
289
290 pa_sink_input_unref(i);
291
292 return ret;
293 }
294
295 void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
296 assert(i);
297 assert(i->ref >= 1);
298 assert(length > 0);
299
300 if (!i->resampler) {
301 if (i->drop)
302 i->drop(i, chunk, length);
303 return;
304 }
305
306 assert(i->resampled_chunk.memblock);
307 assert(i->resampled_chunk.length >= length);
308
309 i->resampled_chunk.index += length;
310 i->resampled_chunk.length -= length;
311
312 if (i->resampled_chunk.length <= 0) {
313 pa_memblock_unref(i->resampled_chunk.memblock);
314 i->resampled_chunk.memblock = NULL;
315 i->resampled_chunk.index = i->resampled_chunk.length = 0;
316 }
317 }
318
319 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
320 assert(i);
321 assert(i->ref >= 1);
322 assert(i->sink);
323 assert(i->sink->core);
324
325 if (pa_cvolume_equal(&i->volume, volume))
326 return;
327
328 i->volume = *volume;
329 pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
330 }
331
332 const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) {
333 assert(i);
334 assert(i->ref >= 1);
335
336 return &i->volume;
337 }
338
339 void pa_sink_input_cork(pa_sink_input *i, int b) {
340 int n;
341
342 assert(i);
343 assert(i->ref >= 1);
344
345 if (i->state == PA_SINK_INPUT_DISCONNECTED)
346 return;
347
348 n = i->state == PA_SINK_INPUT_CORKED && !b;
349
350 i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING;
351
352 if (n)
353 pa_sink_notify(i->sink);
354 }
355
356 void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
357 assert(i);
358 assert(i->resampler);
359 assert(i->ref >= 1);
360
361 if (i->sample_spec.rate == rate)
362 return;
363
364 i->sample_spec.rate = rate;
365 pa_resampler_set_input_rate(i->resampler, rate);
366 }
367
368 void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
369 assert(i);
370 assert(i->ref >= 1);
371
372 pa_xfree(i->name);
373 i->name = pa_xstrdup(name);
374
375 pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
376 }
377
378 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
379 assert(i);
380 assert(i->ref >= 1);
381
382 if (!i->resampler)
383 return PA_RESAMPLER_INVALID;
384
385 return pa_resampler_get_method(i->resampler);
386 }