Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : :
6 : : PulseAudio 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.1 of the License,
9 : : or (at your option) any later version.
10 : :
11 : : PulseAudio 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 PulseAudio; 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 <string.h>
27 : :
28 : : #ifdef HAVE_LIBSAMPLERATE
29 : : #include <samplerate.h>
30 : : #endif
31 : :
32 : : #ifdef HAVE_SPEEX
33 : : #include <speex/speex_resampler.h>
34 : : #endif
35 : :
36 : : #include <pulse/xmalloc.h>
37 : : #include <pulsecore/sconv.h>
38 : : #include <pulsecore/log.h>
39 : : #include <pulsecore/macro.h>
40 : : #include <pulsecore/strbuf.h>
41 : : #include <pulsecore/remap.h>
42 : : #include <pulsecore/core-util.h>
43 : : #include "ffmpeg/avcodec.h"
44 : :
45 : : #include "resampler.h"
46 : :
47 : : /* Number of samples of extra space we allow the resamplers to return */
48 : : #define EXTRA_FRAMES 128
49 : :
50 : : struct pa_resampler {
51 : : pa_resample_method_t method;
52 : : pa_resample_flags_t flags;
53 : :
54 : : pa_sample_spec i_ss, o_ss;
55 : : pa_channel_map i_cm, o_cm;
56 : : size_t i_fz, o_fz, w_sz;
57 : : pa_mempool *mempool;
58 : :
59 : : pa_memchunk to_work_format_buf;
60 : : pa_memchunk remap_buf;
61 : : pa_memchunk resample_buf;
62 : : pa_memchunk from_work_format_buf;
63 : : unsigned to_work_format_buf_samples;
64 : : size_t remap_buf_size;
65 : : unsigned resample_buf_samples;
66 : : unsigned from_work_format_buf_samples;
67 : : pa_bool_t remap_buf_contains_leftover_data;
68 : :
69 : : pa_sample_format_t work_format;
70 : :
71 : : pa_convert_func_t to_work_format_func;
72 : : pa_convert_func_t from_work_format_func;
73 : :
74 : : pa_remap_t remap;
75 : : pa_bool_t map_required;
76 : :
77 : : void (*impl_free)(pa_resampler *r);
78 : : void (*impl_update_rates)(pa_resampler *r);
79 : : void (*impl_resample)(pa_resampler *r, const pa_memchunk *in, unsigned in_samples, pa_memchunk *out, unsigned *out_samples);
80 : : void (*impl_reset)(pa_resampler *r);
81 : :
82 : : struct { /* data specific to the trivial resampler */
83 : : unsigned o_counter;
84 : : unsigned i_counter;
85 : : } trivial;
86 : :
87 : : struct { /* data specific to the peak finder pseudo resampler */
88 : : unsigned o_counter;
89 : : unsigned i_counter;
90 : :
91 : : float max_f[PA_CHANNELS_MAX];
92 : : int16_t max_i[PA_CHANNELS_MAX];
93 : :
94 : : } peaks;
95 : :
96 : : #ifdef HAVE_LIBSAMPLERATE
97 : : struct { /* data specific to libsamplerate */
98 : : SRC_STATE *state;
99 : : } src;
100 : : #endif
101 : :
102 : : #ifdef HAVE_SPEEX
103 : : struct { /* data specific to speex */
104 : : SpeexResamplerState* state;
105 : : } speex;
106 : : #endif
107 : :
108 : : struct { /* data specific to ffmpeg */
109 : : struct AVResampleContext *state;
110 : : pa_memchunk buf[PA_CHANNELS_MAX];
111 : : } ffmpeg;
112 : : };
113 : :
114 : : static int copy_init(pa_resampler *r);
115 : : static int trivial_init(pa_resampler*r);
116 : : #ifdef HAVE_SPEEX
117 : : static int speex_init(pa_resampler*r);
118 : : #endif
119 : : static int ffmpeg_init(pa_resampler*r);
120 : : static int peaks_init(pa_resampler*r);
121 : : #ifdef HAVE_LIBSAMPLERATE
122 : : static int libsamplerate_init(pa_resampler*r);
123 : : #endif
124 : :
125 : : static void calc_map_table(pa_resampler *r);
126 : :
127 : : static int (* const init_table[])(pa_resampler*r) = {
128 : : #ifdef HAVE_LIBSAMPLERATE
129 : : [PA_RESAMPLER_SRC_SINC_BEST_QUALITY] = libsamplerate_init,
130 : : [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY] = libsamplerate_init,
131 : : [PA_RESAMPLER_SRC_SINC_FASTEST] = libsamplerate_init,
132 : : [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD] = libsamplerate_init,
133 : : [PA_RESAMPLER_SRC_LINEAR] = libsamplerate_init,
134 : : #else
135 : : [PA_RESAMPLER_SRC_SINC_BEST_QUALITY] = NULL,
136 : : [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY] = NULL,
137 : : [PA_RESAMPLER_SRC_SINC_FASTEST] = NULL,
138 : : [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD] = NULL,
139 : : [PA_RESAMPLER_SRC_LINEAR] = NULL,
140 : : #endif
141 : : [PA_RESAMPLER_TRIVIAL] = trivial_init,
142 : : #ifdef HAVE_SPEEX
143 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+0] = speex_init,
144 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+1] = speex_init,
145 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+2] = speex_init,
146 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+3] = speex_init,
147 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+4] = speex_init,
148 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+5] = speex_init,
149 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+6] = speex_init,
150 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+7] = speex_init,
151 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+8] = speex_init,
152 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+9] = speex_init,
153 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+10] = speex_init,
154 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+0] = speex_init,
155 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+1] = speex_init,
156 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+2] = speex_init,
157 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+3] = speex_init,
158 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+4] = speex_init,
159 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+5] = speex_init,
160 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+6] = speex_init,
161 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+7] = speex_init,
162 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+8] = speex_init,
163 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+9] = speex_init,
164 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+10] = speex_init,
165 : : #else
166 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+0] = NULL,
167 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+1] = NULL,
168 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+2] = NULL,
169 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+3] = NULL,
170 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+4] = NULL,
171 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+5] = NULL,
172 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+6] = NULL,
173 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+7] = NULL,
174 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+8] = NULL,
175 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+9] = NULL,
176 : : [PA_RESAMPLER_SPEEX_FLOAT_BASE+10] = NULL,
177 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+0] = NULL,
178 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+1] = NULL,
179 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+2] = NULL,
180 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+3] = NULL,
181 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+4] = NULL,
182 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+5] = NULL,
183 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+6] = NULL,
184 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+7] = NULL,
185 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+8] = NULL,
186 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+9] = NULL,
187 : : [PA_RESAMPLER_SPEEX_FIXED_BASE+10] = NULL,
188 : : #endif
189 : : [PA_RESAMPLER_FFMPEG] = ffmpeg_init,
190 : : [PA_RESAMPLER_AUTO] = NULL,
191 : : [PA_RESAMPLER_COPY] = copy_init,
192 : : [PA_RESAMPLER_PEAKS] = peaks_init,
193 : : };
194 : :
195 : 338 : pa_resampler* pa_resampler_new(
196 : : pa_mempool *pool,
197 : : const pa_sample_spec *a,
198 : : const pa_channel_map *am,
199 : : const pa_sample_spec *b,
200 : : const pa_channel_map *bm,
201 : : pa_resample_method_t method,
202 : : pa_resample_flags_t flags) {
203 : :
204 : 338 : pa_resampler *r = NULL;
205 : :
206 [ - + ]: 338 : pa_assert(pool);
207 [ - + ]: 338 : pa_assert(a);
208 [ - + ]: 338 : pa_assert(b);
209 [ - + ]: 338 : pa_assert(pa_sample_spec_valid(a));
210 [ - + ]: 338 : pa_assert(pa_sample_spec_valid(b));
211 [ - + ]: 338 : pa_assert(method >= 0);
212 [ - + ]: 338 : pa_assert(method < PA_RESAMPLER_MAX);
213 : :
214 : : /* Fix method */
215 : :
216 [ + - ][ + - ]: 338 : if (!(flags & PA_RESAMPLER_VARIABLE_RATE) && a->rate == b->rate) {
217 : 338 : pa_log_info("Forcing resampler 'copy', because of fixed, identical sample rates.");
218 : 338 : method = PA_RESAMPLER_COPY;
219 : : }
220 : :
221 [ - + ]: 338 : if (!pa_resample_method_supported(method)) {
222 : 0 : pa_log_warn("Support for resampler '%s' not compiled in, reverting to 'auto'.", pa_resample_method_to_string(method));
223 : 0 : method = PA_RESAMPLER_AUTO;
224 : : }
225 : :
226 [ - + ][ # # ]: 338 : if (method == PA_RESAMPLER_FFMPEG && (flags & PA_RESAMPLER_VARIABLE_RATE)) {
227 : 0 : pa_log_info("Resampler 'ffmpeg' cannot do variable rate, reverting to resampler 'auto'.");
228 : 0 : method = PA_RESAMPLER_AUTO;
229 : : }
230 : :
231 [ + - ][ + - ]: 338 : if (method == PA_RESAMPLER_COPY && ((flags & PA_RESAMPLER_VARIABLE_RATE) || a->rate != b->rate)) {
[ - + ]
232 : 0 : pa_log_info("Resampler 'copy' cannot change sampling rate, reverting to resampler 'auto'.");
233 : 0 : method = PA_RESAMPLER_AUTO;
234 : : }
235 : :
236 [ - + ]: 338 : if (method == PA_RESAMPLER_AUTO) {
237 : : #ifdef HAVE_SPEEX
238 : 0 : method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3;
239 : : #else
240 : : method = PA_RESAMPLER_FFMPEG;
241 : : #endif
242 : : }
243 : :
244 : 338 : r = pa_xnew0(pa_resampler, 1);
245 : 338 : r->mempool = pool;
246 : 338 : r->method = method;
247 : 338 : r->flags = flags;
248 : :
249 : : /* Fill sample specs */
250 : 338 : r->i_ss = *a;
251 : 338 : r->o_ss = *b;
252 : :
253 : : /* set up the remap structure */
254 : 338 : r->remap.i_ss = &r->i_ss;
255 : 338 : r->remap.o_ss = &r->o_ss;
256 : 338 : r->remap.format = &r->work_format;
257 : :
258 [ - + ]: 338 : if (am)
259 : 0 : r->i_cm = *am;
260 [ + - ]: 338 : else if (!pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT))
261 : : goto fail;
262 : :
263 [ - + ]: 338 : if (bm)
264 : 0 : r->o_cm = *bm;
265 [ + - ]: 338 : else if (!pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels, PA_CHANNEL_MAP_DEFAULT))
266 : : goto fail;
267 : :
268 : 338 : r->i_fz = pa_frame_size(a);
269 : 338 : r->o_fz = pa_frame_size(b);
270 : :
271 : 338 : calc_map_table(r);
272 : :
273 : 338 : pa_log_info("Using resampler '%s'", pa_resample_method_to_string(method));
274 : :
275 [ - + ]: 338 : if ((method >= PA_RESAMPLER_SPEEX_FIXED_BASE && method <= PA_RESAMPLER_SPEEX_FIXED_MAX) ||
276 : : (method == PA_RESAMPLER_FFMPEG))
277 : 0 : r->work_format = PA_SAMPLE_S16NE;
278 [ - + ][ # # ]: 338 : else if (method == PA_RESAMPLER_TRIVIAL || method == PA_RESAMPLER_COPY || method == PA_RESAMPLER_PEAKS) {
279 : :
280 [ + - ][ + + ]: 338 : if (r->map_required || a->format != b->format || method == PA_RESAMPLER_PEAKS) {
281 : :
282 [ + + ]: 312 : if (a->format == PA_SAMPLE_S32NE || a->format == PA_SAMPLE_S32RE ||
283 [ + + ][ + + ]: 240 : a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE ||
284 [ + + ][ + + ]: 192 : a->format == PA_SAMPLE_S24NE || a->format == PA_SAMPLE_S24RE ||
285 [ + + ][ + + ]: 144 : a->format == PA_SAMPLE_S24_32NE || a->format == PA_SAMPLE_S24_32RE ||
286 [ + + ][ + + ]: 110 : b->format == PA_SAMPLE_S32NE || b->format == PA_SAMPLE_S32RE ||
287 [ + + ][ + + ]: 90 : b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE ||
288 [ + + ][ + + ]: 70 : b->format == PA_SAMPLE_S24NE || b->format == PA_SAMPLE_S24RE ||
289 [ + + ]: 50 : b->format == PA_SAMPLE_S24_32NE || b->format == PA_SAMPLE_S24_32RE)
290 : 272 : r->work_format = PA_SAMPLE_FLOAT32NE;
291 : : else
292 : 40 : r->work_format = PA_SAMPLE_S16NE;
293 : :
294 : : } else
295 : 26 : r->work_format = a->format;
296 : :
297 : : } else
298 : 0 : r->work_format = PA_SAMPLE_FLOAT32NE;
299 : :
300 : 338 : pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format));
301 : :
302 : 338 : r->w_sz = pa_sample_size_of_format(r->work_format);
303 : :
304 [ + + ]: 338 : if (r->i_ss.format != r->work_format) {
305 [ + + ]: 280 : if (r->work_format == PA_SAMPLE_FLOAT32NE) {
306 [ + - ]: 248 : if (!(r->to_work_format_func = pa_get_convert_to_float32ne_function(r->i_ss.format)))
307 : : goto fail;
308 : : } else {
309 [ - + ]: 32 : pa_assert(r->work_format == PA_SAMPLE_S16NE);
310 [ + - ]: 32 : if (!(r->to_work_format_func = pa_get_convert_to_s16ne_function(r->i_ss.format)))
311 : : goto fail;
312 : : }
313 : : }
314 : :
315 [ + + ]: 338 : if (r->o_ss.format != r->work_format) {
316 [ + + ]: 280 : if (r->work_format == PA_SAMPLE_FLOAT32NE) {
317 [ + - ]: 248 : if (!(r->from_work_format_func = pa_get_convert_from_float32ne_function(r->o_ss.format)))
318 : : goto fail;
319 : : } else {
320 [ - + ]: 32 : pa_assert(r->work_format == PA_SAMPLE_S16NE);
321 [ + - ]: 32 : if (!(r->from_work_format_func = pa_get_convert_from_s16ne_function(r->o_ss.format)))
322 : : goto fail;
323 : : }
324 : : }
325 : :
326 : : /* initialize implementation */
327 [ - + ]: 338 : if (init_table[method](r) < 0)
328 : : goto fail;
329 : :
330 : : return r;
331 : :
332 : : fail:
333 : 0 : pa_xfree(r);
334 : :
335 : 338 : return NULL;
336 : : }
337 : :
338 : 338 : void pa_resampler_free(pa_resampler *r) {
339 [ - + ]: 338 : pa_assert(r);
340 : :
341 [ - + ]: 338 : if (r->impl_free)
342 : 0 : r->impl_free(r);
343 : :
344 [ + + ]: 338 : if (r->to_work_format_buf.memblock)
345 : 248 : pa_memblock_unref(r->to_work_format_buf.memblock);
346 [ - + ]: 338 : if (r->remap_buf.memblock)
347 : 0 : pa_memblock_unref(r->remap_buf.memblock);
348 [ - + ]: 338 : if (r->resample_buf.memblock)
349 : 0 : pa_memblock_unref(r->resample_buf.memblock);
350 [ - + ]: 338 : if (r->from_work_format_buf.memblock)
351 : 0 : pa_memblock_unref(r->from_work_format_buf.memblock);
352 : :
353 : 338 : pa_xfree(r);
354 : 338 : }
355 : :
356 : 0 : void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) {
357 [ # # ]: 0 : pa_assert(r);
358 [ # # ]: 0 : pa_assert(rate > 0);
359 : :
360 [ # # ]: 0 : if (r->i_ss.rate == rate)
361 : 0 : return;
362 : :
363 : 0 : r->i_ss.rate = rate;
364 : :
365 : 0 : r->impl_update_rates(r);
366 : : }
367 : :
368 : 0 : void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
369 [ # # ]: 0 : pa_assert(r);
370 [ # # ]: 0 : pa_assert(rate > 0);
371 : :
372 [ # # ]: 0 : if (r->o_ss.rate == rate)
373 : 0 : return;
374 : :
375 : 0 : r->o_ss.rate = rate;
376 : :
377 : 0 : r->impl_update_rates(r);
378 : : }
379 : :
380 : 0 : size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
381 [ # # ]: 0 : pa_assert(r);
382 : :
383 : : /* Let's round up here to make it more likely that the caller will get at
384 : : * least out_length amount of data from pa_resampler_run().
385 : : *
386 : : * We don't take the leftover into account here. If we did, then it might
387 : : * be in theory possible that this function would return 0 and
388 : : * pa_resampler_run() would also return 0. That could lead to infinite
389 : : * loops. When the leftover is ignored here, such loops would eventually
390 : : * terminate, because the leftover would grow each round, finally
391 : : * surpassing the minimum input threshold of the resampler. */
392 : 0 : return (((((out_length + r->o_fz-1) / r->o_fz) * r->i_ss.rate) + r->o_ss.rate-1) / r->o_ss.rate) * r->i_fz;
393 : : }
394 : :
395 : 0 : size_t pa_resampler_result(pa_resampler *r, size_t in_length) {
396 : : size_t frames;
397 : :
398 [ # # ]: 0 : pa_assert(r);
399 : :
400 : : /* Let's round up here to ensure that the caller will always allocate big
401 : : * enough output buffer. */
402 : :
403 : 0 : frames = (in_length + r->i_fz - 1) / r->i_fz;
404 : :
405 [ # # ]: 0 : if (r->remap_buf_contains_leftover_data)
406 : 0 : frames += r->remap_buf.length / (r->w_sz * r->o_ss.channels);
407 : :
408 : 0 : return ((frames * r->o_ss.rate + r->i_ss.rate - 1) / r->i_ss.rate) * r->o_fz;
409 : : }
410 : :
411 : 0 : size_t pa_resampler_max_block_size(pa_resampler *r) {
412 : : size_t block_size_max;
413 : : pa_sample_spec max_ss;
414 : : size_t max_fs;
415 : : size_t frames;
416 : :
417 [ # # ]: 0 : pa_assert(r);
418 : :
419 : 0 : block_size_max = pa_mempool_block_size_max(r->mempool);
420 : :
421 : : /* We deduce the "largest" sample spec we're using during the
422 : : * conversion */
423 : 0 : max_ss.channels = (uint8_t) (PA_MAX(r->i_ss.channels, r->o_ss.channels));
424 : :
425 : : /* We silently assume that the format enum is ordered by size */
426 : 0 : max_ss.format = PA_MAX(r->i_ss.format, r->o_ss.format);
427 : 0 : max_ss.format = PA_MAX(max_ss.format, r->work_format);
428 : :
429 : 0 : max_ss.rate = PA_MAX(r->i_ss.rate, r->o_ss.rate);
430 : :
431 : 0 : max_fs = pa_frame_size(&max_ss);
432 : 0 : frames = block_size_max / max_fs - EXTRA_FRAMES;
433 : :
434 [ # # ]: 0 : if (r->remap_buf_contains_leftover_data)
435 : 0 : frames -= r->remap_buf.length / (r->w_sz * r->o_ss.channels);
436 : :
437 : 0 : return (frames * r->i_ss.rate / max_ss.rate) * r->i_fz;
438 : : }
439 : :
440 : 0 : void pa_resampler_reset(pa_resampler *r) {
441 [ # # ]: 0 : pa_assert(r);
442 : :
443 [ # # ]: 0 : if (r->impl_reset)
444 : 0 : r->impl_reset(r);
445 : :
446 : 0 : r->remap_buf_contains_leftover_data = FALSE;
447 : 0 : }
448 : :
449 : 0 : pa_resample_method_t pa_resampler_get_method(pa_resampler *r) {
450 [ # # ]: 0 : pa_assert(r);
451 : :
452 : 0 : return r->method;
453 : : }
454 : :
455 : 0 : const pa_channel_map* pa_resampler_input_channel_map(pa_resampler *r) {
456 [ # # ]: 0 : pa_assert(r);
457 : :
458 : 0 : return &r->i_cm;
459 : : }
460 : :
461 : 0 : const pa_sample_spec* pa_resampler_input_sample_spec(pa_resampler *r) {
462 [ # # ]: 0 : pa_assert(r);
463 : :
464 : 0 : return &r->i_ss;
465 : : }
466 : :
467 : 0 : const pa_channel_map* pa_resampler_output_channel_map(pa_resampler *r) {
468 [ # # ]: 0 : pa_assert(r);
469 : :
470 : 0 : return &r->o_cm;
471 : : }
472 : :
473 : 0 : const pa_sample_spec* pa_resampler_output_sample_spec(pa_resampler *r) {
474 [ # # ]: 0 : pa_assert(r);
475 : :
476 : 0 : return &r->o_ss;
477 : : }
478 : :
479 : : static const char * const resample_methods[] = {
480 : : "src-sinc-best-quality",
481 : : "src-sinc-medium-quality",
482 : : "src-sinc-fastest",
483 : : "src-zero-order-hold",
484 : : "src-linear",
485 : : "trivial",
486 : : "speex-float-0",
487 : : "speex-float-1",
488 : : "speex-float-2",
489 : : "speex-float-3",
490 : : "speex-float-4",
491 : : "speex-float-5",
492 : : "speex-float-6",
493 : : "speex-float-7",
494 : : "speex-float-8",
495 : : "speex-float-9",
496 : : "speex-float-10",
497 : : "speex-fixed-0",
498 : : "speex-fixed-1",
499 : : "speex-fixed-2",
500 : : "speex-fixed-3",
501 : : "speex-fixed-4",
502 : : "speex-fixed-5",
503 : : "speex-fixed-6",
504 : : "speex-fixed-7",
505 : : "speex-fixed-8",
506 : : "speex-fixed-9",
507 : : "speex-fixed-10",
508 : : "ffmpeg",
509 : : "auto",
510 : : "copy",
511 : : "peaks"
512 : : };
513 : :
514 : 338 : const char *pa_resample_method_to_string(pa_resample_method_t m) {
515 : :
516 [ + - ]: 338 : if (m < 0 || m >= PA_RESAMPLER_MAX)
517 : : return NULL;
518 : :
519 : 338 : return resample_methods[m];
520 : : }
521 : :
522 : 338 : int pa_resample_method_supported(pa_resample_method_t m) {
523 : :
524 [ + - ]: 338 : if (m < 0 || m >= PA_RESAMPLER_MAX)
525 : : return 0;
526 : :
527 : : #ifndef HAVE_LIBSAMPLERATE
528 : : if (m <= PA_RESAMPLER_SRC_LINEAR)
529 : : return 0;
530 : : #endif
531 : :
532 : : #ifndef HAVE_SPEEX
533 : : if (m >= PA_RESAMPLER_SPEEX_FLOAT_BASE && m <= PA_RESAMPLER_SPEEX_FLOAT_MAX)
534 : : return 0;
535 : : if (m >= PA_RESAMPLER_SPEEX_FIXED_BASE && m <= PA_RESAMPLER_SPEEX_FIXED_MAX)
536 : : return 0;
537 : : #endif
538 : :
539 : 338 : return 1;
540 : : }
541 : :
542 : 0 : pa_resample_method_t pa_parse_resample_method(const char *string) {
543 : : pa_resample_method_t m;
544 : :
545 [ # # ]: 0 : pa_assert(string);
546 : :
547 [ # # ]: 0 : for (m = 0; m < PA_RESAMPLER_MAX; m++)
548 [ # # ]: 0 : if (pa_streq(string, resample_methods[m]))
549 : : return m;
550 : :
551 [ # # ]: 0 : if (pa_streq(string, "speex-fixed"))
552 : : return PA_RESAMPLER_SPEEX_FIXED_BASE + 3;
553 : :
554 [ # # ]: 0 : if (pa_streq(string, "speex-float"))
555 : : return PA_RESAMPLER_SPEEX_FLOAT_BASE + 3;
556 : :
557 : 0 : return PA_RESAMPLER_INVALID;
558 : : }
559 : :
560 : 0 : static pa_bool_t on_left(pa_channel_position_t p) {
561 : :
562 : 0 : return
563 : 0 : p == PA_CHANNEL_POSITION_FRONT_LEFT ||
564 : 0 : p == PA_CHANNEL_POSITION_REAR_LEFT ||
565 [ # # ]: 0 : p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ||
566 : 0 : p == PA_CHANNEL_POSITION_SIDE_LEFT ||
567 [ # # ][ # # ]: 0 : p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT ||
568 : 0 : p == PA_CHANNEL_POSITION_TOP_REAR_LEFT;
569 : : }
570 : :
571 : 0 : static pa_bool_t on_right(pa_channel_position_t p) {
572 : :
573 : 0 : return
574 : 0 : p == PA_CHANNEL_POSITION_FRONT_RIGHT ||
575 : 0 : p == PA_CHANNEL_POSITION_REAR_RIGHT ||
576 [ # # ]: 0 : p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER ||
577 : 0 : p == PA_CHANNEL_POSITION_SIDE_RIGHT ||
578 [ # # ][ # # ]: 0 : p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ||
579 : 0 : p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
580 : : }
581 : :
582 : : static pa_bool_t on_center(pa_channel_position_t p) {
583 : :
584 : 0 : return
585 : 0 : p == PA_CHANNEL_POSITION_FRONT_CENTER ||
586 : 0 : p == PA_CHANNEL_POSITION_REAR_CENTER ||
587 : 0 : p == PA_CHANNEL_POSITION_TOP_CENTER ||
588 [ # # ][ # # ]: 0 : p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
589 : 0 : p == PA_CHANNEL_POSITION_TOP_REAR_CENTER;
590 : : }
591 : :
592 : : static pa_bool_t on_lfe(pa_channel_position_t p) {
593 : : return
594 : : p == PA_CHANNEL_POSITION_LFE;
595 : : }
596 : :
597 : : static pa_bool_t on_front(pa_channel_position_t p) {
598 : 0 : return
599 : : p == PA_CHANNEL_POSITION_FRONT_LEFT ||
600 : 0 : p == PA_CHANNEL_POSITION_FRONT_RIGHT ||
601 : 0 : p == PA_CHANNEL_POSITION_FRONT_CENTER ||
602 : 0 : p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT ||
603 [ # # ]: 0 : p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ||
604 : 0 : p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER ||
605 [ # # ][ # # ]: 0 : p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ||
606 : 0 : p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
607 : : }
608 : :
609 : : static pa_bool_t on_rear(pa_channel_position_t p) {
610 : 0 : return
611 : : p == PA_CHANNEL_POSITION_REAR_LEFT ||
612 : 0 : p == PA_CHANNEL_POSITION_REAR_RIGHT ||
613 : 0 : p == PA_CHANNEL_POSITION_REAR_CENTER ||
614 : 0 : p == PA_CHANNEL_POSITION_TOP_REAR_LEFT ||
615 [ # # ][ # # ]: 0 : p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT ||
616 : 0 : p == PA_CHANNEL_POSITION_TOP_REAR_CENTER;
617 : : }
618 : :
619 : : static pa_bool_t on_side(pa_channel_position_t p) {
620 : 0 : return
621 : 0 : p == PA_CHANNEL_POSITION_SIDE_LEFT ||
622 : 0 : p == PA_CHANNEL_POSITION_SIDE_RIGHT ||
623 : 0 : p == PA_CHANNEL_POSITION_TOP_CENTER;
624 : : }
625 : :
626 : : enum {
627 : : ON_FRONT,
628 : : ON_REAR,
629 : : ON_SIDE,
630 : : ON_OTHER
631 : : };
632 : :
633 : 0 : static int front_rear_side(pa_channel_position_t p) {
634 [ # # ]: 0 : if (on_front(p))
635 : : return ON_FRONT;
636 [ # # ]: 0 : if (on_rear(p))
637 : : return ON_REAR;
638 [ # # ]: 0 : if (on_side(p))
639 : : return ON_SIDE;
640 : 0 : return ON_OTHER;
641 : : }
642 : :
643 : 338 : static void calc_map_table(pa_resampler *r) {
644 : : unsigned oc, ic;
645 : : unsigned n_oc, n_ic;
646 : : pa_bool_t ic_connected[PA_CHANNELS_MAX];
647 : : pa_bool_t remix;
648 : : pa_strbuf *s;
649 : : char *t;
650 : : pa_remap_t *m;
651 : :
652 [ - + ]: 338 : pa_assert(r);
653 : :
654 [ + - ][ + - ]: 338 : if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || (!(r->flags & PA_RESAMPLER_NO_REMAP) && !pa_channel_map_equal(&r->i_cm, &r->o_cm)))))
[ + - ][ - + ]
655 : 338 : return;
656 : :
657 : 0 : m = &r->remap;
658 : :
659 : 0 : n_oc = r->o_ss.channels;
660 : 0 : n_ic = r->i_ss.channels;
661 : :
662 : 0 : memset(m->map_table_f, 0, sizeof(m->map_table_f));
663 : 0 : memset(m->map_table_i, 0, sizeof(m->map_table_i));
664 : :
665 : : memset(ic_connected, 0, sizeof(ic_connected));
666 : 0 : remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0;
667 : :
668 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
669 : 0 : pa_bool_t oc_connected = FALSE;
670 : 0 : pa_channel_position_t b = r->o_cm.map[oc];
671 : :
672 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
673 : 0 : pa_channel_position_t a = r->i_cm.map[ic];
674 : :
675 [ # # ]: 0 : if (r->flags & PA_RESAMPLER_NO_REMAP) {
676 : : /* We shall not do any remapping. Hence, just check by index */
677 : :
678 [ # # ]: 0 : if (ic == oc)
679 : 0 : m->map_table_f[oc][ic] = 1.0;
680 : :
681 : 0 : continue;
682 : : }
683 : :
684 [ # # ]: 0 : if (r->flags & PA_RESAMPLER_NO_REMIX) {
685 : : /* We shall not do any remixing. Hence, just check by name */
686 : :
687 [ # # ]: 0 : if (a == b)
688 : 0 : m->map_table_f[oc][ic] = 1.0;
689 : :
690 : 0 : continue;
691 : : }
692 : :
693 [ # # ]: 0 : pa_assert(remix);
694 : :
695 : : /* OK, we shall do the full monty: upmixing and
696 : : * downmixing. Our algorithm is relatively simple, does
697 : : * not do spacialization, delay elements or apply lowpass
698 : : * filters for LFE. Patches are always welcome,
699 : : * though. Oh, and it doesn't do any matrix
700 : : * decoding. (Which probably wouldn't make any sense
701 : : * anyway.)
702 : : *
703 : : * This code is not idempotent: downmixing an upmixed
704 : : * stereo stream is not identical to the original. The
705 : : * volume will not match, and the two channels will be a
706 : : * linear combination of both.
707 : : *
708 : : * This is loosely based on random suggestions found on the
709 : : * Internet, such as this:
710 : : * http://www.halfgaar.net/surround-sound-in-linux and the
711 : : * alsa upmix plugin.
712 : : *
713 : : * The algorithm works basically like this:
714 : : *
715 : : * 1) Connect all channels with matching names.
716 : : *
717 : : * 2) Mono Handling:
718 : : * S:Mono: Copy into all D:channels
719 : : * D:Mono: Copy in all S:channels
720 : : *
721 : : * 3) Mix D:Left, D:Right:
722 : : * D:Left: If not connected, avg all S:Left
723 : : * D:Right: If not connected, avg all S:Right
724 : : *
725 : : * 4) Mix D:Center
726 : : * If not connected, avg all S:Center
727 : : * If still not connected, avg all S:Left, S:Right
728 : : *
729 : : * 5) Mix D:LFE
730 : : * If not connected, avg all S:*
731 : : *
732 : : * 6) Make sure S:Left/S:Right is used: S:Left/S:Right: If
733 : : * not connected, mix into all D:left and all D:right
734 : : * channels. Gain is 0.1, the current left and right
735 : : * should be multiplied by 0.9.
736 : : *
737 : : * 7) Make sure S:Center, S:LFE is used:
738 : : *
739 : : * S:Center, S:LFE: If not connected, mix into all
740 : : * D:left, all D:right, all D:center channels, gain is
741 : : * 0.375. The current (as result of 1..6) factors
742 : : * should be multiplied by 0.75. (Alt. suggestion: 0.25
743 : : * vs. 0.5) If C-front is only mixed into
744 : : * L-front/R-front if available, otherwise into all L/R
745 : : * channels. Similarly for C-rear.
746 : : *
747 : : * S: and D: shall relate to the source resp. destination channels.
748 : : *
749 : : * Rationale: 1, 2 are probably obvious. For 3: this
750 : : * copies front to rear if needed. For 4: we try to find
751 : : * some suitable C source for C, if we don't find any, we
752 : : * avg L and R. For 5: LFE is mixed from all channels. For
753 : : * 6: the rear channels should not be dropped entirely,
754 : : * however have only minimal impact. For 7: movies usually
755 : : * encode speech on the center channel. Thus we have to
756 : : * make sure this channel is distributed to L and R if not
757 : : * available in the output. Also, LFE is used to achieve a
758 : : * greater dynamic range, and thus we should try to do our
759 : : * best to pass it to L+R.
760 : : */
761 : :
762 [ # # ][ # # ]: 0 : if (a == b || a == PA_CHANNEL_POSITION_MONO || b == PA_CHANNEL_POSITION_MONO) {
763 : 0 : m->map_table_f[oc][ic] = 1.0;
764 : :
765 : 0 : oc_connected = TRUE;
766 : 0 : ic_connected[ic] = TRUE;
767 : : }
768 : : }
769 : :
770 [ # # ][ # # ]: 0 : if (!oc_connected && remix) {
771 : : /* OK, we shall remix */
772 : :
773 : : /* Try to find matching input ports for this output port */
774 : :
775 [ # # ]: 0 : if (on_left(b)) {
776 : : unsigned n = 0;
777 : :
778 : : /* We are not connected and on the left side, let's
779 : : * average all left side input channels. */
780 : :
781 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
782 [ # # ]: 0 : if (on_left(r->i_cm.map[ic]))
783 : 0 : n++;
784 : :
785 [ # # ]: 0 : if (n > 0)
786 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
787 [ # # ]: 0 : if (on_left(r->i_cm.map[ic])) {
788 : 0 : m->map_table_f[oc][ic] = 1.0f / (float) n;
789 : 0 : ic_connected[ic] = TRUE;
790 : : }
791 : :
792 : : /* We ignore the case where there is no left input
793 : : * channel. Something is really wrong in this case
794 : : * anyway. */
795 : :
796 [ # # ]: 0 : } else if (on_right(b)) {
797 : : unsigned n = 0;
798 : :
799 : : /* We are not connected and on the right side, let's
800 : : * average all right side input channels. */
801 : :
802 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
803 [ # # ]: 0 : if (on_right(r->i_cm.map[ic]))
804 : 0 : n++;
805 : :
806 [ # # ]: 0 : if (n > 0)
807 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
808 [ # # ]: 0 : if (on_right(r->i_cm.map[ic])) {
809 : 0 : m->map_table_f[oc][ic] = 1.0f / (float) n;
810 : 0 : ic_connected[ic] = TRUE;
811 : : }
812 : :
813 : : /* We ignore the case where there is no right input
814 : : * channel. Something is really wrong in this case
815 : : * anyway. */
816 : :
817 [ # # ]: 0 : } else if (on_center(b)) {
818 : : unsigned n = 0;
819 : :
820 : : /* We are not connected and at the center. Let's
821 : : * average all center input channels. */
822 : :
823 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
824 [ # # ]: 0 : if (on_center(r->i_cm.map[ic]))
825 : 0 : n++;
826 : :
827 [ # # ]: 0 : if (n > 0) {
828 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
829 [ # # ]: 0 : if (on_center(r->i_cm.map[ic])) {
830 : 0 : m->map_table_f[oc][ic] = 1.0f / (float) n;
831 : 0 : ic_connected[ic] = TRUE;
832 : : }
833 : : } else {
834 : :
835 : : /* Hmm, no center channel around, let's synthesize
836 : : * it by mixing L and R.*/
837 : :
838 : : n = 0;
839 : :
840 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
841 [ # # ][ # # ]: 0 : if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic]))
842 : 0 : n++;
843 : :
844 [ # # ]: 0 : if (n > 0)
845 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
846 [ # # ][ # # ]: 0 : if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) {
847 : 0 : m->map_table_f[oc][ic] = 1.0f / (float) n;
848 : 0 : ic_connected[ic] = TRUE;
849 : : }
850 : :
851 : : /* We ignore the case where there is not even a
852 : : * left or right input channel. Something is
853 : : * really wrong in this case anyway. */
854 : : }
855 : :
856 [ # # ]: 0 : } else if (on_lfe(b)) {
857 : :
858 : : /* We are not connected and an LFE. Let's average all
859 : : * channels for LFE. */
860 : :
861 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
862 : :
863 [ # # ]: 0 : if (!(r->flags & PA_RESAMPLER_NO_LFE))
864 : 0 : m->map_table_f[oc][ic] = 1.0f / (float) n_ic;
865 : : else
866 : 0 : m->map_table_f[oc][ic] = 0;
867 : :
868 : : /* Please note that a channel connected to LFE
869 : : * doesn't really count as connected. */
870 : : }
871 : : }
872 : : }
873 : : }
874 : :
875 [ # # ]: 0 : if (remix) {
876 : : unsigned
877 : : ic_unconnected_left = 0,
878 : : ic_unconnected_right = 0,
879 : : ic_unconnected_center = 0,
880 : : ic_unconnected_lfe = 0;
881 : :
882 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
883 : 0 : pa_channel_position_t a = r->i_cm.map[ic];
884 : :
885 [ # # ]: 0 : if (ic_connected[ic])
886 : 0 : continue;
887 : :
888 [ # # ]: 0 : if (on_left(a))
889 : 0 : ic_unconnected_left++;
890 [ # # ]: 0 : else if (on_right(a))
891 : 0 : ic_unconnected_right++;
892 [ # # ]: 0 : else if (on_center(a))
893 : 0 : ic_unconnected_center++;
894 [ # # ]: 0 : else if (on_lfe(a))
895 : 0 : ic_unconnected_lfe++;
896 : : }
897 : :
898 [ # # ]: 0 : if (ic_unconnected_left > 0) {
899 : :
900 : : /* OK, so there are unconnected input channels on the
901 : : * left. Let's multiply all already connected channels on
902 : : * the left side by .9 and add in our averaged unconnected
903 : : * channels multiplied by .1 */
904 : :
905 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
906 : :
907 [ # # ]: 0 : if (!on_left(r->o_cm.map[oc]))
908 : 0 : continue;
909 : :
910 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
911 : :
912 [ # # ]: 0 : if (ic_connected[ic]) {
913 : 0 : m->map_table_f[oc][ic] *= .9f;
914 : 0 : continue;
915 : : }
916 : :
917 [ # # ]: 0 : if (on_left(r->i_cm.map[ic]))
918 : 0 : m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_left;
919 : : }
920 : : }
921 : : }
922 : :
923 [ # # ]: 0 : if (ic_unconnected_right > 0) {
924 : :
925 : : /* OK, so there are unconnected input channels on the
926 : : * right. Let's multiply all already connected channels on
927 : : * the right side by .9 and add in our averaged unconnected
928 : : * channels multiplied by .1 */
929 : :
930 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
931 : :
932 [ # # ]: 0 : if (!on_right(r->o_cm.map[oc]))
933 : 0 : continue;
934 : :
935 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
936 : :
937 [ # # ]: 0 : if (ic_connected[ic]) {
938 : 0 : m->map_table_f[oc][ic] *= .9f;
939 : 0 : continue;
940 : : }
941 : :
942 [ # # ]: 0 : if (on_right(r->i_cm.map[ic]))
943 : 0 : m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_right;
944 : : }
945 : : }
946 : : }
947 : :
948 [ # # ]: 0 : if (ic_unconnected_center > 0) {
949 : : pa_bool_t mixed_in = FALSE;
950 : :
951 : : /* OK, so there are unconnected input channels on the
952 : : * center. Let's multiply all already connected channels on
953 : : * the center side by .9 and add in our averaged unconnected
954 : : * channels multiplied by .1 */
955 : :
956 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
957 : :
958 [ # # ]: 0 : if (!on_center(r->o_cm.map[oc]))
959 : 0 : continue;
960 : :
961 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
962 : :
963 [ # # ]: 0 : if (ic_connected[ic]) {
964 : 0 : m->map_table_f[oc][ic] *= .9f;
965 : 0 : continue;
966 : : }
967 : :
968 [ # # ]: 0 : if (on_center(r->i_cm.map[ic])) {
969 : 0 : m->map_table_f[oc][ic] = .1f / (float) ic_unconnected_center;
970 : 0 : mixed_in = TRUE;
971 : : }
972 : : }
973 : : }
974 : :
975 [ # # ]: 0 : if (!mixed_in) {
976 : : unsigned ncenter[PA_CHANNELS_MAX];
977 : : pa_bool_t found_frs[PA_CHANNELS_MAX];
978 : :
979 : : memset(ncenter, 0, sizeof(ncenter));
980 : : memset(found_frs, 0, sizeof(found_frs));
981 : :
982 : : /* Hmm, as it appears there was no center channel we
983 : : could mix our center channel in. In this case, mix
984 : : it into left and right. Using .375 and 0.75 as
985 : : factors. */
986 : :
987 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
988 : :
989 [ # # ]: 0 : if (ic_connected[ic])
990 : 0 : continue;
991 : :
992 [ # # ]: 0 : if (!on_center(r->i_cm.map[ic]))
993 : 0 : continue;
994 : :
995 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
996 : :
997 [ # # ][ # # ]: 0 : if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
998 : 0 : continue;
999 : :
1000 [ # # ]: 0 : if (front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc])) {
1001 : 0 : found_frs[ic] = TRUE;
1002 : 0 : break;
1003 : : }
1004 : : }
1005 : :
1006 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
1007 : :
1008 [ # # ][ # # ]: 0 : if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
1009 : 0 : continue;
1010 : :
1011 [ # # ][ # # ]: 0 : if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc]))
1012 : 0 : ncenter[oc]++;
1013 : : }
1014 : : }
1015 : :
1016 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
1017 : :
1018 [ # # ][ # # ]: 0 : if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc]))
1019 : 0 : continue;
1020 : :
1021 [ # # ]: 0 : if (ncenter[oc] <= 0)
1022 : 0 : continue;
1023 : :
1024 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
1025 : :
1026 [ # # ]: 0 : if (ic_connected[ic]) {
1027 : 0 : m->map_table_f[oc][ic] *= .75f;
1028 : 0 : continue;
1029 : : }
1030 : :
1031 [ # # ]: 0 : if (!on_center(r->i_cm.map[ic]))
1032 : 0 : continue;
1033 : :
1034 [ # # ][ # # ]: 0 : if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc]))
1035 : 0 : m->map_table_f[oc][ic] = .375f / (float) ncenter[oc];
1036 : : }
1037 : : }
1038 : : }
1039 : : }
1040 : :
1041 [ # # ][ # # ]: 0 : if (ic_unconnected_lfe > 0 && !(r->flags & PA_RESAMPLER_NO_LFE)) {
1042 : :
1043 : : /* OK, so there is an unconnected LFE channel. Let's mix
1044 : : * it into all channels, with factor 0.375 */
1045 : :
1046 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++) {
1047 : :
1048 [ # # ]: 0 : if (!on_lfe(r->i_cm.map[ic]))
1049 : 0 : continue;
1050 : :
1051 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++)
1052 : 0 : m->map_table_f[oc][ic] = 0.375f / (float) ic_unconnected_lfe;
1053 : : }
1054 : : }
1055 : : }
1056 : : /* make an 16:16 int version of the matrix */
1057 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++)
1058 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
1059 : 0 : m->map_table_i[oc][ic] = (int32_t) (m->map_table_f[oc][ic] * 0x10000);
1060 : :
1061 : 0 : s = pa_strbuf_new();
1062 : :
1063 : 0 : pa_strbuf_printf(s, " ");
1064 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
1065 : 0 : pa_strbuf_printf(s, " I%02u ", ic);
1066 : 0 : pa_strbuf_puts(s, "\n +");
1067 : :
1068 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
1069 : 0 : pa_strbuf_printf(s, "------");
1070 : 0 : pa_strbuf_puts(s, "\n");
1071 : :
1072 [ # # ]: 0 : for (oc = 0; oc < n_oc; oc++) {
1073 : 0 : pa_strbuf_printf(s, "O%02u |", oc);
1074 : :
1075 [ # # ]: 0 : for (ic = 0; ic < n_ic; ic++)
1076 : 0 : pa_strbuf_printf(s, " %1.3f", m->map_table_f[oc][ic]);
1077 : :
1078 : 0 : pa_strbuf_puts(s, "\n");
1079 : : }
1080 : :
1081 : 0 : pa_log_debug("Channel matrix:\n%s", t = pa_strbuf_tostring_free(s));
1082 : 0 : pa_xfree(t);
1083 : :
1084 : : /* initialize the remapping function */
1085 : 0 : pa_init_remap(m);
1086 : : }
1087 : :
1088 : 338 : static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
1089 : : unsigned n_samples;
1090 : : void *src, *dst;
1091 : :
1092 [ - + ]: 338 : pa_assert(r);
1093 [ - + ]: 338 : pa_assert(input);
1094 [ - + ]: 338 : pa_assert(input->memblock);
1095 : :
1096 : : /* Convert the incoming sample into the work sample format and place them
1097 : : * in to_work_format_buf. */
1098 : :
1099 [ + + ][ + - ]: 338 : if (!r->to_work_format_func || !input->length)
1100 : : return input;
1101 : :
1102 : 280 : n_samples = (unsigned) ((input->length / r->i_fz) * r->i_ss.channels);
1103 : :
1104 : 280 : r->to_work_format_buf.index = 0;
1105 : 280 : r->to_work_format_buf.length = r->w_sz * n_samples;
1106 : :
1107 [ - + ][ # # ]: 280 : if (!r->to_work_format_buf.memblock || r->to_work_format_buf_samples < n_samples) {
1108 [ - + ]: 280 : if (r->to_work_format_buf.memblock)
1109 : 0 : pa_memblock_unref(r->to_work_format_buf.memblock);
1110 : :
1111 : 280 : r->to_work_format_buf_samples = n_samples;
1112 : 280 : r->to_work_format_buf.memblock = pa_memblock_new(r->mempool, r->to_work_format_buf.length);
1113 : : }
1114 : :
1115 : 280 : src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
1116 : 280 : dst = (uint8_t*) pa_memblock_acquire(r->to_work_format_buf.memblock);
1117 : :
1118 : 280 : r->to_work_format_func(n_samples, src, dst);
1119 : :
1120 : 280 : pa_memblock_release(input->memblock);
1121 : 280 : pa_memblock_release(r->to_work_format_buf.memblock);
1122 : :
1123 : 338 : return &r->to_work_format_buf;
1124 : : }
1125 : :
1126 : 338 : static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
1127 : : unsigned in_n_samples, out_n_samples, in_n_frames, out_n_frames;
1128 : : void *src, *dst;
1129 : 338 : size_t leftover_length = 0;
1130 : : pa_bool_t have_leftover;
1131 : :
1132 [ - + ]: 338 : pa_assert(r);
1133 [ - + ]: 338 : pa_assert(input);
1134 [ - + ]: 338 : pa_assert(input->memblock);
1135 : :
1136 : : /* Remap channels and place the result in remap_buf. There may be leftover
1137 : : * data in the beginning of remap_buf. The leftover data is already
1138 : : * remapped, so it's not part of the input, it's part of the output. */
1139 : :
1140 : 338 : have_leftover = r->remap_buf_contains_leftover_data;
1141 : 338 : r->remap_buf_contains_leftover_data = FALSE;
1142 : :
1143 [ + - ][ - + ]: 338 : if (!have_leftover && (!r->map_required || input->length <= 0))
[ # # ]
1144 : : return input;
1145 [ # # ]: 0 : else if (input->length <= 0)
1146 : 0 : return &r->remap_buf;
1147 : :
1148 : 0 : in_n_samples = (unsigned) (input->length / r->w_sz);
1149 : 0 : in_n_frames = out_n_frames = in_n_samples / r->i_ss.channels;
1150 : :
1151 [ # # ]: 0 : if (have_leftover) {
1152 : 0 : leftover_length = r->remap_buf.length;
1153 : 0 : out_n_frames += leftover_length / (r->w_sz * r->o_ss.channels);
1154 : : }
1155 : :
1156 : 0 : out_n_samples = out_n_frames * r->o_ss.channels;
1157 : 0 : r->remap_buf.length = out_n_samples * r->w_sz;
1158 : :
1159 [ # # ]: 0 : if (have_leftover) {
1160 [ # # ]: 0 : if (r->remap_buf_size < r->remap_buf.length) {
1161 : 0 : pa_memblock *new_block = pa_memblock_new(r->mempool, r->remap_buf.length);
1162 : :
1163 : 0 : src = pa_memblock_acquire(r->remap_buf.memblock);
1164 : 0 : dst = pa_memblock_acquire(new_block);
1165 : 0 : memcpy(dst, src, leftover_length);
1166 : 0 : pa_memblock_release(r->remap_buf.memblock);
1167 : 0 : pa_memblock_release(new_block);
1168 : :
1169 : 0 : pa_memblock_unref(r->remap_buf.memblock);
1170 : 0 : r->remap_buf.memblock = new_block;
1171 : 0 : r->remap_buf_size = r->remap_buf.length;
1172 : : }
1173 : :
1174 : : } else {
1175 [ # # ][ # # ]: 0 : if (!r->remap_buf.memblock || r->remap_buf_size < r->remap_buf.length) {
1176 [ # # ]: 0 : if (r->remap_buf.memblock)
1177 : 0 : pa_memblock_unref(r->remap_buf.memblock);
1178 : :
1179 : 0 : r->remap_buf_size = r->remap_buf.length;
1180 : 0 : r->remap_buf.memblock = pa_memblock_new(r->mempool, r->remap_buf.length);
1181 : : }
1182 : : }
1183 : :
1184 : 0 : src = (uint8_t *) pa_memblock_acquire(input->memblock) + input->index;
1185 : 0 : dst = (uint8_t *) pa_memblock_acquire(r->remap_buf.memblock) + leftover_length;
1186 : :
1187 [ # # ]: 0 : if (r->map_required) {
1188 : 0 : pa_remap_t *remap = &r->remap;
1189 : :
1190 [ # # ]: 0 : pa_assert(remap->do_remap);
1191 : 0 : remap->do_remap(remap, dst, src, in_n_frames);
1192 : :
1193 : : } else
1194 : 0 : memcpy(dst, src, input->length);
1195 : :
1196 : 0 : pa_memblock_release(input->memblock);
1197 : 0 : pa_memblock_release(r->remap_buf.memblock);
1198 : :
1199 : 338 : return &r->remap_buf;
1200 : : }
1201 : :
1202 : 338 : static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
1203 : : unsigned in_n_frames, in_n_samples;
1204 : : unsigned out_n_frames, out_n_samples;
1205 : :
1206 [ - + ]: 338 : pa_assert(r);
1207 [ - + ]: 338 : pa_assert(input);
1208 : :
1209 : : /* Resample the data and place the result in resample_buf. */
1210 : :
1211 [ - + ][ # # ]: 338 : if (!r->impl_resample || !input->length)
1212 : : return input;
1213 : :
1214 : 0 : in_n_samples = (unsigned) (input->length / r->w_sz);
1215 : 0 : in_n_frames = (unsigned) (in_n_samples / r->o_ss.channels);
1216 : :
1217 : 0 : out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_FRAMES;
1218 : 0 : out_n_samples = out_n_frames * r->o_ss.channels;
1219 : :
1220 : 0 : r->resample_buf.index = 0;
1221 : 0 : r->resample_buf.length = r->w_sz * out_n_samples;
1222 : :
1223 [ # # ][ # # ]: 0 : if (!r->resample_buf.memblock || r->resample_buf_samples < out_n_samples) {
1224 [ # # ]: 0 : if (r->resample_buf.memblock)
1225 : 0 : pa_memblock_unref(r->resample_buf.memblock);
1226 : :
1227 : 0 : r->resample_buf_samples = out_n_samples;
1228 : 0 : r->resample_buf.memblock = pa_memblock_new(r->mempool, r->resample_buf.length);
1229 : : }
1230 : :
1231 : 0 : r->impl_resample(r, input, in_n_frames, &r->resample_buf, &out_n_frames);
1232 : 0 : r->resample_buf.length = out_n_frames * r->w_sz * r->o_ss.channels;
1233 : :
1234 : 338 : return &r->resample_buf;
1235 : : }
1236 : :
1237 : 338 : static pa_memchunk *convert_from_work_format(pa_resampler *r, pa_memchunk *input) {
1238 : : unsigned n_samples, n_frames;
1239 : : void *src, *dst;
1240 : :
1241 [ - + ]: 338 : pa_assert(r);
1242 [ - + ]: 338 : pa_assert(input);
1243 : :
1244 : : /* Convert the data into the correct sample type and place the result in
1245 : : * from_work_format_buf. */
1246 : :
1247 [ + + ][ + - ]: 338 : if (!r->from_work_format_func || !input->length)
1248 : : return input;
1249 : :
1250 : 280 : n_samples = (unsigned) (input->length / r->w_sz);
1251 : 280 : n_frames = n_samples / r->o_ss.channels;
1252 : :
1253 : 280 : r->from_work_format_buf.index = 0;
1254 : 280 : r->from_work_format_buf.length = r->o_fz * n_frames;
1255 : :
1256 [ - + ][ # # ]: 280 : if (!r->from_work_format_buf.memblock || r->from_work_format_buf_samples < n_samples) {
1257 [ - + ]: 280 : if (r->from_work_format_buf.memblock)
1258 : 0 : pa_memblock_unref(r->from_work_format_buf.memblock);
1259 : :
1260 : 280 : r->from_work_format_buf_samples = n_samples;
1261 : 280 : r->from_work_format_buf.memblock = pa_memblock_new(r->mempool, r->from_work_format_buf.length);
1262 : : }
1263 : :
1264 : 280 : src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
1265 : 280 : dst = pa_memblock_acquire(r->from_work_format_buf.memblock);
1266 : 280 : r->from_work_format_func(n_samples, src, dst);
1267 : 280 : pa_memblock_release(input->memblock);
1268 : 280 : pa_memblock_release(r->from_work_format_buf.memblock);
1269 : :
1270 : 280 : r->from_work_format_buf.length = r->o_fz * n_frames;
1271 : :
1272 : 338 : return &r->from_work_format_buf;
1273 : : }
1274 : :
1275 : 338 : void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
1276 : : pa_memchunk *buf;
1277 : :
1278 [ - + ]: 338 : pa_assert(r);
1279 [ - + ]: 338 : pa_assert(in);
1280 [ - + ]: 338 : pa_assert(out);
1281 [ - + ]: 338 : pa_assert(in->length);
1282 [ - + ]: 338 : pa_assert(in->memblock);
1283 [ - + ]: 338 : pa_assert(in->length % r->i_fz == 0);
1284 : :
1285 : 338 : buf = (pa_memchunk*) in;
1286 : 338 : buf = convert_to_work_format(r, buf);
1287 : 338 : buf = remap_channels(r, buf);
1288 : 338 : buf = resample(r, buf);
1289 : :
1290 [ + - ]: 338 : if (buf->length) {
1291 : 338 : buf = convert_from_work_format(r, buf);
1292 : 338 : *out = *buf;
1293 : :
1294 [ + + ]: 338 : if (buf == in)
1295 : 26 : pa_memblock_ref(buf->memblock);
1296 : : else
1297 : 312 : pa_memchunk_reset(buf);
1298 : : } else
1299 : 0 : pa_memchunk_reset(out);
1300 : 338 : }
1301 : :
1302 : 0 : static void save_leftover(pa_resampler *r, void *buf, size_t len) {
1303 : : void *dst;
1304 : :
1305 [ # # ]: 0 : pa_assert(r);
1306 [ # # ]: 0 : pa_assert(buf);
1307 [ # # ]: 0 : pa_assert(len > 0);
1308 : :
1309 : : /* Store the leftover to remap_buf. */
1310 : :
1311 : 0 : r->remap_buf.length = len;
1312 : :
1313 [ # # ][ # # ]: 0 : if (!r->remap_buf.memblock || r->remap_buf_size < r->remap_buf.length) {
1314 [ # # ]: 0 : if (r->remap_buf.memblock)
1315 : 0 : pa_memblock_unref(r->remap_buf.memblock);
1316 : :
1317 : 0 : r->remap_buf_size = r->remap_buf.length;
1318 : 0 : r->remap_buf.memblock = pa_memblock_new(r->mempool, r->remap_buf.length);
1319 : : }
1320 : :
1321 : 0 : dst = pa_memblock_acquire(r->remap_buf.memblock);
1322 : 0 : memcpy(dst, buf, r->remap_buf.length);
1323 : 0 : pa_memblock_release(r->remap_buf.memblock);
1324 : :
1325 : 0 : r->remap_buf_contains_leftover_data = TRUE;
1326 : 0 : }
1327 : :
1328 : : /*** libsamplerate based implementation ***/
1329 : :
1330 : : #ifdef HAVE_LIBSAMPLERATE
1331 : 0 : static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
1332 : : SRC_DATA data;
1333 : :
1334 [ # # ]: 0 : pa_assert(r);
1335 [ # # ]: 0 : pa_assert(input);
1336 [ # # ]: 0 : pa_assert(output);
1337 [ # # ]: 0 : pa_assert(out_n_frames);
1338 : :
1339 : : memset(&data, 0, sizeof(data));
1340 : :
1341 : 0 : data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
1342 : 0 : data.input_frames = (long int) in_n_frames;
1343 : :
1344 : 0 : data.data_out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
1345 : 0 : data.output_frames = (long int) *out_n_frames;
1346 : :
1347 : 0 : data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
1348 : 0 : data.end_of_input = 0;
1349 : :
1350 [ # # ]: 0 : pa_assert_se(src_process(r->src.state, &data) == 0);
1351 : :
1352 [ # # ]: 0 : if (data.input_frames_used < in_n_frames) {
1353 : 0 : void *leftover_data = data.data_in + data.input_frames_used * r->o_ss.channels;
1354 : 0 : size_t leftover_length = (in_n_frames - data.input_frames_used) * sizeof(float) * r->o_ss.channels;
1355 : :
1356 : 0 : save_leftover(r, leftover_data, leftover_length);
1357 : : }
1358 : :
1359 : 0 : pa_memblock_release(input->memblock);
1360 : 0 : pa_memblock_release(output->memblock);
1361 : :
1362 : 0 : *out_n_frames = (unsigned) data.output_frames_gen;
1363 : 0 : }
1364 : :
1365 : 0 : static void libsamplerate_update_rates(pa_resampler *r) {
1366 [ # # ]: 0 : pa_assert(r);
1367 : :
1368 [ # # ]: 0 : pa_assert_se(src_set_ratio(r->src.state, (double) r->o_ss.rate / r->i_ss.rate) == 0);
1369 : 0 : }
1370 : :
1371 : 0 : static void libsamplerate_reset(pa_resampler *r) {
1372 [ # # ]: 0 : pa_assert(r);
1373 : :
1374 [ # # ]: 0 : pa_assert_se(src_reset(r->src.state) == 0);
1375 : 0 : }
1376 : :
1377 : 0 : static void libsamplerate_free(pa_resampler *r) {
1378 [ # # ]: 0 : pa_assert(r);
1379 : :
1380 [ # # ]: 0 : if (r->src.state)
1381 : 0 : src_delete(r->src.state);
1382 : 0 : }
1383 : :
1384 : 0 : static int libsamplerate_init(pa_resampler *r) {
1385 : : int err;
1386 : :
1387 [ # # ]: 0 : pa_assert(r);
1388 : :
1389 [ # # ]: 0 : if (!(r->src.state = src_new(r->method, r->o_ss.channels, &err)))
1390 : : return -1;
1391 : :
1392 : 0 : r->impl_free = libsamplerate_free;
1393 : 0 : r->impl_update_rates = libsamplerate_update_rates;
1394 : 0 : r->impl_resample = libsamplerate_resample;
1395 : 0 : r->impl_reset = libsamplerate_reset;
1396 : :
1397 : 0 : return 0;
1398 : : }
1399 : : #endif
1400 : :
1401 : : #ifdef HAVE_SPEEX
1402 : : /*** speex based implementation ***/
1403 : :
1404 : 0 : static void speex_resample_float(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
1405 : : float *in, *out;
1406 : 0 : uint32_t inf = in_n_frames, outf = *out_n_frames;
1407 : :
1408 [ # # ]: 0 : pa_assert(r);
1409 [ # # ]: 0 : pa_assert(input);
1410 [ # # ]: 0 : pa_assert(output);
1411 [ # # ]: 0 : pa_assert(out_n_frames);
1412 : :
1413 : 0 : in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
1414 : 0 : out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
1415 : :
1416 [ # # ]: 0 : pa_assert_se(speex_resampler_process_interleaved_float(r->speex.state, in, &inf, out, &outf) == 0);
1417 : :
1418 : 0 : pa_memblock_release(input->memblock);
1419 : 0 : pa_memblock_release(output->memblock);
1420 : :
1421 [ # # ]: 0 : pa_assert(inf == in_n_frames);
1422 : 0 : *out_n_frames = outf;
1423 : 0 : }
1424 : :
1425 : 0 : static void speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
1426 : : int16_t *in, *out;
1427 : 0 : uint32_t inf = in_n_frames, outf = *out_n_frames;
1428 : :
1429 [ # # ]: 0 : pa_assert(r);
1430 [ # # ]: 0 : pa_assert(input);
1431 [ # # ]: 0 : pa_assert(output);
1432 [ # # ]: 0 : pa_assert(out_n_frames);
1433 : :
1434 : 0 : in = (int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
1435 : 0 : out = (int16_t*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
1436 : :
1437 [ # # ]: 0 : pa_assert_se(speex_resampler_process_interleaved_int(r->speex.state, in, &inf, out, &outf) == 0);
1438 : :
1439 : 0 : pa_memblock_release(input->memblock);
1440 : 0 : pa_memblock_release(output->memblock);
1441 : :
1442 [ # # ]: 0 : pa_assert(inf == in_n_frames);
1443 : 0 : *out_n_frames = outf;
1444 : 0 : }
1445 : :
1446 : 0 : static void speex_update_rates(pa_resampler *r) {
1447 [ # # ]: 0 : pa_assert(r);
1448 : :
1449 [ # # ]: 0 : pa_assert_se(speex_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0);
1450 : 0 : }
1451 : :
1452 : 0 : static void speex_reset(pa_resampler *r) {
1453 [ # # ]: 0 : pa_assert(r);
1454 : :
1455 [ # # ]: 0 : pa_assert_se(speex_resampler_reset_mem(r->speex.state) == 0);
1456 : 0 : }
1457 : :
1458 : 0 : static void speex_free(pa_resampler *r) {
1459 [ # # ]: 0 : pa_assert(r);
1460 : :
1461 [ # # ]: 0 : if (!r->speex.state)
1462 : 0 : return;
1463 : :
1464 : 0 : speex_resampler_destroy(r->speex.state);
1465 : : }
1466 : :
1467 : 0 : static int speex_init(pa_resampler *r) {
1468 : : int q, err;
1469 : :
1470 [ # # ]: 0 : pa_assert(r);
1471 : :
1472 : 0 : r->impl_free = speex_free;
1473 : 0 : r->impl_update_rates = speex_update_rates;
1474 : 0 : r->impl_reset = speex_reset;
1475 : :
1476 [ # # ]: 0 : if (r->method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->method <= PA_RESAMPLER_SPEEX_FIXED_MAX) {
1477 : :
1478 : 0 : q = r->method - PA_RESAMPLER_SPEEX_FIXED_BASE;
1479 : 0 : r->impl_resample = speex_resample_int;
1480 : :
1481 : : } else {
1482 [ # # ]: 0 : pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
1483 : :
1484 : 0 : q = r->method - PA_RESAMPLER_SPEEX_FLOAT_BASE;
1485 : 0 : r->impl_resample = speex_resample_float;
1486 : : }
1487 : :
1488 : 0 : pa_log_info("Choosing speex quality setting %i.", q);
1489 : :
1490 [ # # ]: 0 : if (!(r->speex.state = speex_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
1491 : : return -1;
1492 : :
1493 : 0 : return 0;
1494 : : }
1495 : : #endif
1496 : :
1497 : : /* Trivial implementation */
1498 : :
1499 : 0 : static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
1500 : : size_t fz;
1501 : : unsigned i_index, o_index;
1502 : : void *src, *dst;
1503 : :
1504 [ # # ]: 0 : pa_assert(r);
1505 [ # # ]: 0 : pa_assert(input);
1506 [ # # ]: 0 : pa_assert(output);
1507 [ # # ]: 0 : pa_assert(out_n_frames);
1508 : :
1509 : 0 : fz = r->w_sz * r->o_ss.channels;
1510 : :
1511 : 0 : src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
1512 : 0 : dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index;
1513 : :
1514 : 0 : for (o_index = 0;; o_index++, r->trivial.o_counter++) {
1515 : 0 : i_index = (r->trivial.o_counter * r->i_ss.rate) / r->o_ss.rate;
1516 [ # # ]: 0 : i_index = i_index > r->trivial.i_counter ? i_index - r->trivial.i_counter : 0;
1517 : :
1518 [ # # ]: 0 : if (i_index >= in_n_frames)
1519 : : break;
1520 : :
1521 : : pa_assert_fp(o_index * fz < pa_memblock_get_length(output->memblock));
1522 : :
1523 : 0 : memcpy((uint8_t*) dst + fz * o_index, (uint8_t*) src + fz * i_index, (int) fz);
1524 : 0 : }
1525 : :
1526 : 0 : pa_memblock_release(input->memblock);
1527 : 0 : pa_memblock_release(output->memblock);
1528 : :
1529 : 0 : *out_n_frames = o_index;
1530 : :
1531 : 0 : r->trivial.i_counter += in_n_frames;
1532 : :
1533 : : /* Normalize counters */
1534 [ # # ]: 0 : while (r->trivial.i_counter >= r->i_ss.rate) {
1535 [ # # ]: 0 : pa_assert(r->trivial.o_counter >= r->o_ss.rate);
1536 : :
1537 : 0 : r->trivial.i_counter -= r->i_ss.rate;
1538 : 0 : r->trivial.o_counter -= r->o_ss.rate;
1539 : : }
1540 : 0 : }
1541 : :
1542 : 0 : static void trivial_update_rates_or_reset(pa_resampler *r) {
1543 [ # # ]: 0 : pa_assert(r);
1544 : :
1545 : 0 : r->trivial.i_counter = 0;
1546 : 0 : r->trivial.o_counter = 0;
1547 : 0 : }
1548 : :
1549 : 0 : static int trivial_init(pa_resampler*r) {
1550 [ # # ]: 0 : pa_assert(r);
1551 : :
1552 : 0 : r->trivial.o_counter = r->trivial.i_counter = 0;
1553 : :
1554 : 0 : r->impl_resample = trivial_resample;
1555 : 0 : r->impl_update_rates = trivial_update_rates_or_reset;
1556 : 0 : r->impl_reset = trivial_update_rates_or_reset;
1557 : :
1558 : 0 : return 0;
1559 : : }
1560 : :
1561 : : /* Peak finder implementation */
1562 : :
1563 : 0 : static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
1564 : 0 : unsigned c, o_index = 0;
1565 : 0 : unsigned i, i_end = 0;
1566 : : void *src, *dst;
1567 : :
1568 [ # # ]: 0 : pa_assert(r);
1569 [ # # ]: 0 : pa_assert(input);
1570 [ # # ]: 0 : pa_assert(output);
1571 [ # # ]: 0 : pa_assert(out_n_frames);
1572 : :
1573 : 0 : src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
1574 : 0 : dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index;
1575 : :
1576 : 0 : i = (r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate;
1577 [ # # ]: 0 : i = i > r->peaks.i_counter ? i - r->peaks.i_counter : 0;
1578 : :
1579 [ # # ]: 0 : while (i_end < in_n_frames) {
1580 : 0 : i_end = ((r->peaks.o_counter+1) * r->i_ss.rate) / r->o_ss.rate;
1581 [ # # ]: 0 : i_end = i_end > r->peaks.i_counter ? i_end - r->peaks.i_counter : 0;
1582 : :
1583 : : pa_assert_fp(o_index * r->w_sz * r->o_ss.channels < pa_memblock_get_length(output->memblock));
1584 : :
1585 : : /* 1ch float is treated separately, because that is the common case */
1586 [ # # ][ # # ]: 0 : if (r->o_ss.channels == 1 && r->work_format == PA_SAMPLE_FLOAT32NE) {
1587 : 0 : float *s = (float*) src + i;
1588 : 0 : float *d = (float*) dst + o_index;
1589 : :
1590 [ # # ]: 0 : for (; i < i_end && i < in_n_frames; i++) {
1591 : 0 : float n = fabsf(*s++);
1592 : :
1593 [ # # ]: 0 : if (n > r->peaks.max_f[0])
1594 : 0 : r->peaks.max_f[0] = n;
1595 : : }
1596 : :
1597 [ # # ]: 0 : if (i == i_end) {
1598 : 0 : *d = r->peaks.max_f[0];
1599 : 0 : r->peaks.max_f[0] = 0;
1600 : 0 : o_index++, r->peaks.o_counter++;
1601 : : }
1602 [ # # ]: 0 : } else if (r->work_format == PA_SAMPLE_S16NE) {
1603 : 0 : int16_t *s = (int16_t*) src + r->i_ss.channels * i;
1604 : 0 : int16_t *d = (int16_t*) dst + r->o_ss.channels * o_index;
1605 : :
1606 [ # # ]: 0 : for (; i < i_end && i < in_n_frames; i++)
1607 [ # # ]: 0 : for (c = 0; c < r->o_ss.channels; c++) {
1608 : 0 : int16_t n = abs(*s++);
1609 : :
1610 [ # # ]: 0 : if (n > r->peaks.max_i[c])
1611 : 0 : r->peaks.max_i[c] = n;
1612 : : }
1613 : :
1614 [ # # ]: 0 : if (i == i_end) {
1615 [ # # ]: 0 : for (c = 0; c < r->o_ss.channels; c++, d++) {
1616 : 0 : *d = r->peaks.max_i[c];
1617 : 0 : r->peaks.max_i[c] = 0;
1618 : : }
1619 : 0 : o_index++, r->peaks.o_counter++;
1620 : : }
1621 : : } else {
1622 : 0 : float *s = (float*) src + r->i_ss.channels * i;
1623 : 0 : float *d = (float*) dst + r->o_ss.channels * o_index;
1624 : :
1625 [ # # ]: 0 : for (; i < i_end && i < in_n_frames; i++)
1626 [ # # ]: 0 : for (c = 0; c < r->o_ss.channels; c++) {
1627 : 0 : float n = fabsf(*s++);
1628 : :
1629 [ # # ]: 0 : if (n > r->peaks.max_f[c])
1630 : 0 : r->peaks.max_f[c] = n;
1631 : : }
1632 : :
1633 [ # # ]: 0 : if (i == i_end) {
1634 [ # # ]: 0 : for (c = 0; c < r->o_ss.channels; c++, d++) {
1635 : 0 : *d = r->peaks.max_f[c];
1636 : 0 : r->peaks.max_f[c] = 0;
1637 : : }
1638 : 0 : o_index++, r->peaks.o_counter++;
1639 : : }
1640 : : }
1641 : : }
1642 : :
1643 : 0 : pa_memblock_release(input->memblock);
1644 : 0 : pa_memblock_release(output->memblock);
1645 : :
1646 : 0 : *out_n_frames = o_index;
1647 : :
1648 : 0 : r->peaks.i_counter += in_n_frames;
1649 : :
1650 : : /* Normalize counters */
1651 [ # # ]: 0 : while (r->peaks.i_counter >= r->i_ss.rate) {
1652 [ # # ]: 0 : pa_assert(r->peaks.o_counter >= r->o_ss.rate);
1653 : :
1654 : 0 : r->peaks.i_counter -= r->i_ss.rate;
1655 : 0 : r->peaks.o_counter -= r->o_ss.rate;
1656 : : }
1657 : 0 : }
1658 : :
1659 : 0 : static void peaks_update_rates_or_reset(pa_resampler *r) {
1660 [ # # ]: 0 : pa_assert(r);
1661 : :
1662 : 0 : r->peaks.i_counter = 0;
1663 : 0 : r->peaks.o_counter = 0;
1664 : 0 : }
1665 : :
1666 : 0 : static int peaks_init(pa_resampler*r) {
1667 [ # # ]: 0 : pa_assert(r);
1668 [ # # ]: 0 : pa_assert(r->i_ss.rate >= r->o_ss.rate);
1669 [ # # ]: 0 : pa_assert(r->work_format == PA_SAMPLE_S16NE || r->work_format == PA_SAMPLE_FLOAT32NE);
1670 : :
1671 : 0 : r->peaks.o_counter = r->peaks.i_counter = 0;
1672 : 0 : memset(r->peaks.max_i, 0, sizeof(r->peaks.max_i));
1673 : 0 : memset(r->peaks.max_f, 0, sizeof(r->peaks.max_f));
1674 : :
1675 : 0 : r->impl_resample = peaks_resample;
1676 : 0 : r->impl_update_rates = peaks_update_rates_or_reset;
1677 : 0 : r->impl_reset = peaks_update_rates_or_reset;
1678 : :
1679 : 0 : return 0;
1680 : : }
1681 : :
1682 : : /*** ffmpeg based implementation ***/
1683 : :
1684 : 0 : static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
1685 : 0 : unsigned used_frames = 0, c;
1686 : 0 : int previous_consumed_frames = -1;
1687 : :
1688 [ # # ]: 0 : pa_assert(r);
1689 [ # # ]: 0 : pa_assert(input);
1690 [ # # ]: 0 : pa_assert(output);
1691 [ # # ]: 0 : pa_assert(out_n_frames);
1692 : :
1693 [ # # ]: 0 : for (c = 0; c < r->o_ss.channels; c++) {
1694 : : unsigned u;
1695 : : pa_memblock *b, *w;
1696 : : int16_t *p, *t, *k, *q, *s;
1697 : : int consumed_frames;
1698 : :
1699 : : /* Allocate a new block */
1700 : 0 : b = pa_memblock_new(r->mempool, r->ffmpeg.buf[c].length + in_n_frames * sizeof(int16_t));
1701 : 0 : p = pa_memblock_acquire(b);
1702 : :
1703 : : /* Now copy the input data, splitting up channels */
1704 : 0 : t = ((int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index)) + c;
1705 : 0 : k = (int16_t*) ((uint8_t*) p);
1706 [ # # ]: 0 : for (u = 0; u < in_n_frames; u++) {
1707 : 0 : *k = *t;
1708 : 0 : t += r->o_ss.channels;
1709 : 0 : k ++;
1710 : : }
1711 : 0 : pa_memblock_release(input->memblock);
1712 : :
1713 : : /* Allocate buffer for the result */
1714 : 0 : w = pa_memblock_new(r->mempool, *out_n_frames * sizeof(int16_t));
1715 : 0 : q = pa_memblock_acquire(w);
1716 : :
1717 : : /* Now, resample */
1718 : 0 : used_frames = (unsigned) av_resample(r->ffmpeg.state,
1719 : : q, p,
1720 : : &consumed_frames,
1721 : 0 : (int) in_n_frames, (int) *out_n_frames,
1722 : 0 : c >= (unsigned) (r->o_ss.channels-1));
1723 : :
1724 : 0 : pa_memblock_release(b);
1725 : 0 : pa_memblock_unref(b);
1726 : :
1727 [ # # ]: 0 : pa_assert(consumed_frames <= (int) in_n_frames);
1728 [ # # ][ # # ]: 0 : pa_assert(previous_consumed_frames == -1 || consumed_frames == previous_consumed_frames);
1729 : 0 : previous_consumed_frames = consumed_frames;
1730 : :
1731 : : /* And place the results in the output buffer */
1732 : 0 : s = (short*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index) + c;
1733 [ # # ]: 0 : for (u = 0; u < used_frames; u++) {
1734 : 0 : *s = *q;
1735 : 0 : q++;
1736 : 0 : s += r->o_ss.channels;
1737 : : }
1738 : 0 : pa_memblock_release(output->memblock);
1739 : 0 : pa_memblock_release(w);
1740 : 0 : pa_memblock_unref(w);
1741 : : }
1742 : :
1743 [ # # ]: 0 : if (previous_consumed_frames < (int) in_n_frames) {
1744 : 0 : void *leftover_data = (int16_t *) ((uint8_t *) pa_memblock_acquire(input->memblock) + output->index) + previous_consumed_frames * r->o_ss.channels;
1745 : 0 : size_t leftover_length = (in_n_frames - previous_consumed_frames) * r->o_ss.channels * sizeof(int16_t);
1746 : :
1747 : 0 : save_leftover(r, leftover_data, leftover_length);
1748 : 0 : pa_memblock_release(input->memblock);
1749 : : }
1750 : :
1751 : 0 : *out_n_frames = used_frames;
1752 : 0 : }
1753 : :
1754 : 0 : static void ffmpeg_free(pa_resampler *r) {
1755 : : unsigned c;
1756 : :
1757 [ # # ]: 0 : pa_assert(r);
1758 : :
1759 [ # # ]: 0 : if (r->ffmpeg.state)
1760 : 0 : av_resample_close(r->ffmpeg.state);
1761 : :
1762 [ # # ]: 0 : for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++)
1763 [ # # ]: 0 : if (r->ffmpeg.buf[c].memblock)
1764 : 0 : pa_memblock_unref(r->ffmpeg.buf[c].memblock);
1765 : 0 : }
1766 : :
1767 : 0 : static int ffmpeg_init(pa_resampler *r) {
1768 : : unsigned c;
1769 : :
1770 [ # # ]: 0 : pa_assert(r);
1771 : :
1772 : : /* We could probably implement different quality levels by
1773 : : * adjusting the filter parameters here. However, ffmpeg
1774 : : * internally only uses these hardcoded values, so let's use them
1775 : : * here for now as well until ffmpeg makes this configurable. */
1776 : :
1777 [ # # ]: 0 : if (!(r->ffmpeg.state = av_resample_init((int) r->o_ss.rate, (int) r->i_ss.rate, 16, 10, 0, 0.8)))
1778 : : return -1;
1779 : :
1780 : 0 : r->impl_free = ffmpeg_free;
1781 : 0 : r->impl_resample = ffmpeg_resample;
1782 : :
1783 [ # # ]: 0 : for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++)
1784 : 0 : pa_memchunk_reset(&r->ffmpeg.buf[c]);
1785 : :
1786 : : return 0;
1787 : : }
1788 : :
1789 : : /*** copy (noop) implementation ***/
1790 : :
1791 : 338 : static int copy_init(pa_resampler *r) {
1792 [ - + ]: 338 : pa_assert(r);
1793 : :
1794 [ - + ]: 338 : pa_assert(r->o_ss.rate == r->i_ss.rate);
1795 : :
1796 : 338 : return 0;
1797 : : }
|