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