Line data Source code
1 : /*
2 : * Copyright © 2016 Mozilla Foundation
3 : *
4 : * This program is made available under an ISC-style license. See the
5 : * accompanying file LICENSE for details.
6 : */
7 :
8 : #if !defined(CUBEB_RESAMPLER_INTERNAL)
9 : #define CUBEB_RESAMPLER_INTERNAL
10 :
11 : #include <cmath>
12 : #include <cassert>
13 : #include <algorithm>
14 : #include <memory>
15 : #ifdef CUBEB_GECKO_BUILD
16 : #include "mozilla/UniquePtr.h"
17 : // In libc++, symbols such as std::unique_ptr may be defined in std::__1.
18 : // The _LIBCPP_BEGIN_NAMESPACE_STD and _LIBCPP_END_NAMESPACE_STD macros
19 : // will expand to the correct namespace.
20 : #ifdef _LIBCPP_BEGIN_NAMESPACE_STD
21 : #define MOZ_BEGIN_STD_NAMESPACE _LIBCPP_BEGIN_NAMESPACE_STD
22 : #define MOZ_END_STD_NAMESPACE _LIBCPP_END_NAMESPACE_STD
23 : #else
24 : #define MOZ_BEGIN_STD_NAMESPACE namespace std {
25 : #define MOZ_END_STD_NAMESPACE }
26 : #endif
27 : MOZ_BEGIN_STD_NAMESPACE
28 : using mozilla::DefaultDelete;
29 : using mozilla::UniquePtr;
30 : #define default_delete DefaultDelete
31 : #define unique_ptr UniquePtr
32 : MOZ_END_STD_NAMESPACE
33 : #endif
34 : #include "cubeb/cubeb.h"
35 : #include "cubeb_utils.h"
36 : #include "cubeb-speex-resampler.h"
37 : #include "cubeb_resampler.h"
38 : #include <stdio.h>
39 :
40 : /* This header file contains the internal C++ API of the resamplers, for testing. */
41 :
42 : int to_speex_quality(cubeb_resampler_quality q);
43 :
44 0 : struct cubeb_resampler {
45 : virtual long fill(void * input_buffer, long * input_frames_count,
46 : void * output_buffer, long frames_needed) = 0;
47 : virtual long latency() = 0;
48 0 : virtual ~cubeb_resampler() {}
49 : };
50 :
51 : /** Base class for processors. This is just used to share methods for now. */
52 : class processor {
53 : public:
54 0 : explicit processor(uint32_t channels)
55 0 : : channels(channels)
56 0 : {}
57 : protected:
58 0 : size_t frames_to_samples(size_t frames)
59 : {
60 0 : return frames * channels;
61 : }
62 0 : size_t samples_to_frames(size_t samples)
63 : {
64 0 : assert(!(samples % channels));
65 0 : return samples / channels;
66 : }
67 : /** The number of channel of the audio buffers to be resampled. */
68 : const uint32_t channels;
69 : };
70 :
71 : template<typename T>
72 0 : class passthrough_resampler : public cubeb_resampler
73 : , public processor {
74 : public:
75 : passthrough_resampler(cubeb_stream * s,
76 : cubeb_data_callback cb,
77 : void * ptr,
78 : uint32_t input_channels);
79 :
80 : virtual long fill(void * input_buffer, long * input_frames_count,
81 : void * output_buffer, long output_frames);
82 :
83 0 : virtual long latency()
84 : {
85 0 : return 0;
86 : }
87 :
88 : private:
89 : cubeb_stream * const stream;
90 : const cubeb_data_callback data_callback;
91 : void * const user_ptr;
92 : /* This allows to buffer some input to account for the fact that we buffer
93 : * some inputs. */
94 : auto_array<T> internal_input_buffer;
95 : };
96 :
97 : /** Bidirectional resampler, can resample an input and an output stream, or just
98 : * an input stream or output stream. In this case a delay is inserted in the
99 : * opposite direction to keep the streams synchronized. */
100 : template<typename T, typename InputProcessing, typename OutputProcessing>
101 : class cubeb_resampler_speex : public cubeb_resampler {
102 : public:
103 : cubeb_resampler_speex(InputProcessing * input_processor,
104 : OutputProcessing * output_processor,
105 : cubeb_stream * s,
106 : cubeb_data_callback cb,
107 : void * ptr);
108 :
109 : virtual ~cubeb_resampler_speex();
110 :
111 : virtual long fill(void * input_buffer, long * input_frames_count,
112 : void * output_buffer, long output_frames_needed);
113 :
114 0 : virtual long latency()
115 : {
116 0 : if (input_processor && output_processor) {
117 0 : assert(input_processor->latency() == output_processor->latency());
118 0 : return input_processor->latency();
119 0 : } else if (input_processor) {
120 0 : return input_processor->latency();
121 : } else {
122 0 : return output_processor->latency();
123 : }
124 : }
125 :
126 : private:
127 : typedef long(cubeb_resampler_speex::*processing_callback)(T * input_buffer, long * input_frames_count, T * output_buffer, long output_frames_needed);
128 :
129 : long fill_internal_duplex(T * input_buffer, long * input_frames_count,
130 : T * output_buffer, long output_frames_needed);
131 : long fill_internal_input(T * input_buffer, long * input_frames_count,
132 : T * output_buffer, long output_frames_needed);
133 : long fill_internal_output(T * input_buffer, long * input_frames_count,
134 : T * output_buffer, long output_frames_needed);
135 :
136 : std::unique_ptr<InputProcessing> input_processor;
137 : std::unique_ptr<OutputProcessing> output_processor;
138 : processing_callback fill_internal;
139 : cubeb_stream * const stream;
140 : const cubeb_data_callback data_callback;
141 : void * const user_ptr;
142 : };
143 :
144 : /** Handles one way of a (possibly) duplex resampler, working on interleaved
145 : * audio buffers of type T. This class is designed so that the number of frames
146 : * coming out of the resampler can be precisely controled. It manages its own
147 : * input buffer, and can use the caller's output buffer, or allocate its own. */
148 : template<typename T>
149 : class cubeb_resampler_speex_one_way : public processor {
150 : public:
151 : /** The sample type of this resampler, either 16-bit integers or 32-bit
152 : * floats. */
153 : typedef T sample_type;
154 : /** Construct a resampler resampling from #source_rate to #target_rate, that
155 : * can be arbitrary, strictly positive number.
156 : * @parameter channels The number of channels this resampler will resample.
157 : * @parameter source_rate The sample-rate of the audio input.
158 : * @parameter target_rate The sample-rate of the audio output.
159 : * @parameter quality A number between 0 (fast, low quality) and 10 (slow,
160 : * high quality). */
161 0 : cubeb_resampler_speex_one_way(uint32_t channels,
162 : uint32_t source_rate,
163 : uint32_t target_rate,
164 : int quality)
165 : : processor(channels)
166 0 : , resampling_ratio(static_cast<float>(source_rate) / target_rate)
167 : , additional_latency(0)
168 0 : , leftover_samples(0)
169 : {
170 : int r;
171 0 : speex_resampler = speex_resampler_init(channels, source_rate,
172 : target_rate, quality, &r);
173 0 : assert(r == RESAMPLER_ERR_SUCCESS && "resampler allocation failure");
174 0 : }
175 :
176 : /** Destructor, deallocate the resampler */
177 0 : virtual ~cubeb_resampler_speex_one_way()
178 : {
179 0 : speex_resampler_destroy(speex_resampler);
180 0 : }
181 :
182 : /** Sometimes, it is necessary to add latency on one way of a two-way
183 : * resampler so that the stream are synchronized. This must be called only on
184 : * a fresh resampler, otherwise, silent samples will be inserted in the
185 : * stream.
186 : * @param frames the number of frames of latency to add. */
187 0 : void add_latency(size_t frames)
188 : {
189 0 : additional_latency += frames;
190 0 : resampling_in_buffer.push_silence(frames_to_samples(frames));
191 0 : }
192 :
193 : /* Fill the resampler with `input_frame_count` frames. */
194 0 : void input(T * input_buffer, size_t input_frame_count)
195 : {
196 0 : resampling_in_buffer.push(input_buffer,
197 : frames_to_samples(input_frame_count));
198 0 : }
199 :
200 : /** Outputs exactly `output_frame_count` into `output_buffer`.
201 : * `output_buffer` has to be at least `output_frame_count` long. */
202 0 : size_t output(T * output_buffer, size_t output_frame_count)
203 : {
204 0 : uint32_t in_len = samples_to_frames(resampling_in_buffer.length());
205 0 : uint32_t out_len = output_frame_count;
206 :
207 0 : speex_resample(resampling_in_buffer.data(), &in_len,
208 : output_buffer, &out_len);
209 :
210 : /* This shifts back any unresampled samples to the beginning of the input
211 : buffer. */
212 0 : resampling_in_buffer.pop(nullptr, frames_to_samples(in_len));
213 :
214 0 : return out_len;
215 : }
216 :
217 0 : size_t output_for_input(uint32_t input_frames)
218 : {
219 0 : return (size_t)floorf((input_frames + samples_to_frames(resampling_in_buffer.length()))
220 0 : / resampling_ratio);
221 : }
222 :
223 : /** Returns a buffer containing exactly `output_frame_count` resampled frames.
224 : * The consumer should not hold onto the pointer. */
225 0 : T * output(size_t output_frame_count, size_t * input_frames_used)
226 : {
227 0 : if (resampling_out_buffer.capacity() < frames_to_samples(output_frame_count)) {
228 0 : resampling_out_buffer.reserve(frames_to_samples(output_frame_count));
229 : }
230 :
231 0 : uint32_t in_len = samples_to_frames(resampling_in_buffer.length());
232 0 : uint32_t out_len = output_frame_count;
233 :
234 0 : speex_resample(resampling_in_buffer.data(), &in_len,
235 : resampling_out_buffer.data(), &out_len);
236 :
237 0 : assert(out_len == output_frame_count);
238 :
239 : /* This shifts back any unresampled samples to the beginning of the input
240 : buffer. */
241 0 : resampling_in_buffer.pop(nullptr, frames_to_samples(in_len));
242 0 : *input_frames_used = in_len;
243 :
244 0 : return resampling_out_buffer.data();
245 : }
246 :
247 : /** Get the latency of the resampler, in output frames. */
248 0 : uint32_t latency() const
249 : {
250 : /* The documentation of the resampler talks about "samples" here, but it
251 : * only consider a single channel here so it's the same number of frames. */
252 0 : int latency = 0;
253 :
254 0 : latency =
255 0 : speex_resampler_get_output_latency(speex_resampler) + additional_latency;
256 :
257 0 : assert(latency >= 0);
258 :
259 0 : return latency;
260 : }
261 :
262 : /** Returns the number of frames to pass in the input of the resampler to have
263 : * exactly `output_frame_count` resampled frames. This can return a number
264 : * slightly bigger than what is strictly necessary, but it guaranteed that the
265 : * number of output frames will be exactly equal. */
266 0 : uint32_t input_needed_for_output(uint32_t output_frame_count)
267 : {
268 0 : int32_t unresampled_frames_left = samples_to_frames(resampling_in_buffer.length());
269 0 : int32_t resampled_frames_left = samples_to_frames(resampling_out_buffer.length());
270 : float input_frames_needed =
271 0 : (output_frame_count - unresampled_frames_left) * resampling_ratio
272 0 : - resampled_frames_left;
273 0 : if (input_frames_needed < 0) {
274 0 : return 0;
275 : }
276 0 : return (uint32_t)ceilf(input_frames_needed);
277 : }
278 :
279 : /** Returns a pointer to the input buffer, that contains empty space for at
280 : * least `frame_count` elements. This is useful so that consumer can directly
281 : * write into the input buffer of the resampler. The pointer returned is
282 : * adjusted so that leftover data are not overwritten.
283 : */
284 0 : T * input_buffer(size_t frame_count)
285 : {
286 0 : leftover_samples = resampling_in_buffer.length();
287 0 : resampling_in_buffer.reserve(leftover_samples +
288 : frames_to_samples(frame_count));
289 0 : return resampling_in_buffer.data() + leftover_samples;
290 : }
291 :
292 : /** This method works with `input_buffer`, and allows to inform the processor
293 : how much frames have been written in the provided buffer. */
294 0 : void written(size_t written_frames)
295 : {
296 0 : resampling_in_buffer.set_length(leftover_samples +
297 : frames_to_samples(written_frames));
298 0 : }
299 : private:
300 : /** Wrapper for the speex resampling functions to have a typed
301 : * interface. */
302 0 : void speex_resample(float * input_buffer, uint32_t * input_frame_count,
303 : float * output_buffer, uint32_t * output_frame_count)
304 : {
305 : #ifndef NDEBUG
306 : int rv;
307 0 : rv =
308 : #endif
309 0 : speex_resampler_process_interleaved_float(speex_resampler,
310 : input_buffer,
311 : input_frame_count,
312 : output_buffer,
313 : output_frame_count);
314 0 : assert(rv == RESAMPLER_ERR_SUCCESS);
315 0 : }
316 :
317 0 : void speex_resample(short * input_buffer, uint32_t * input_frame_count,
318 : short * output_buffer, uint32_t * output_frame_count)
319 : {
320 : #ifndef NDEBUG
321 : int rv;
322 0 : rv =
323 : #endif
324 0 : speex_resampler_process_interleaved_int(speex_resampler,
325 : input_buffer,
326 : input_frame_count,
327 : output_buffer,
328 : output_frame_count);
329 0 : assert(rv == RESAMPLER_ERR_SUCCESS);
330 0 : }
331 : /** The state for the speex resampler used internaly. */
332 : SpeexResamplerState * speex_resampler;
333 : /** Source rate / target rate. */
334 : const float resampling_ratio;
335 : /** Storage for the input frames, to be resampled. Also contains
336 : * any unresampled frames after resampling. */
337 : auto_array<T> resampling_in_buffer;
338 : /* Storage for the resampled frames, to be passed back to the caller. */
339 : auto_array<T> resampling_out_buffer;
340 : /** Additional latency inserted into the pipeline for synchronisation. */
341 : uint32_t additional_latency;
342 : /** When `input_buffer` is called, this allows tracking the number of samples
343 : that were in the buffer. */
344 : uint32_t leftover_samples;
345 : };
346 :
347 : /** This class allows delaying an audio stream by `frames` frames. */
348 : template<typename T>
349 0 : class delay_line : public processor {
350 : public:
351 : /** Constructor
352 : * @parameter frames the number of frames of delay.
353 : * @parameter channels the number of channels of this delay line. */
354 0 : delay_line(uint32_t frames, uint32_t channels)
355 : : processor(channels)
356 : , length(frames)
357 0 : , leftover_samples(0)
358 : {
359 : /* Fill the delay line with some silent frames to add latency. */
360 0 : delay_input_buffer.push_silence(frames * channels);
361 0 : }
362 : /* Add some latency to the delay line.
363 : * @param frames the number of frames of latency to add. */
364 0 : void add_latency(size_t frames)
365 : {
366 0 : length += frames;
367 0 : delay_input_buffer.push_silence(frames_to_samples(frames));
368 0 : }
369 : /** Push some frames into the delay line.
370 : * @parameter buffer the frames to push.
371 : * @parameter frame_count the number of frames in #buffer. */
372 0 : void input(T * buffer, uint32_t frame_count)
373 : {
374 0 : delay_input_buffer.push(buffer, frames_to_samples(frame_count));
375 0 : }
376 : /** Pop some frames from the internal buffer, into a internal output buffer.
377 : * @parameter frames_needed the number of frames to be returned.
378 : * @return a buffer containing the delayed frames. The consumer should not
379 : * hold onto the pointer. */
380 0 : T * output(uint32_t frames_needed, size_t * input_frames_used)
381 : {
382 0 : if (delay_output_buffer.capacity() < frames_to_samples(frames_needed)) {
383 0 : delay_output_buffer.reserve(frames_to_samples(frames_needed));
384 : }
385 :
386 0 : delay_output_buffer.clear();
387 0 : delay_output_buffer.push(delay_input_buffer.data(),
388 : frames_to_samples(frames_needed));
389 0 : delay_input_buffer.pop(nullptr, frames_to_samples(frames_needed));
390 0 : *input_frames_used = frames_needed;
391 :
392 0 : return delay_output_buffer.data();
393 : }
394 : /** Get a pointer to the first writable location in the input buffer>
395 : * @parameter frames_needed the number of frames the user needs to write into
396 : * the buffer.
397 : * @returns a pointer to a location in the input buffer where #frames_needed
398 : * can be writen. */
399 0 : T * input_buffer(uint32_t frames_needed)
400 : {
401 0 : leftover_samples = delay_input_buffer.length();
402 0 : delay_input_buffer.reserve(leftover_samples + frames_to_samples(frames_needed));
403 0 : return delay_input_buffer.data() + leftover_samples;
404 : }
405 : /** This method works with `input_buffer`, and allows to inform the processor
406 : how much frames have been written in the provided buffer. */
407 0 : void written(size_t frames_written)
408 : {
409 0 : delay_input_buffer.set_length(leftover_samples +
410 : frames_to_samples(frames_written));
411 0 : }
412 : /** Drains the delay line, emptying the buffer.
413 : * @parameter output_buffer the buffer in which the frames are written.
414 : * @parameter frames_needed the maximum number of frames to write.
415 : * @return the actual number of frames written. */
416 0 : size_t output(T * output_buffer, uint32_t frames_needed)
417 : {
418 0 : uint32_t in_len = samples_to_frames(delay_input_buffer.length());
419 0 : uint32_t out_len = frames_needed;
420 :
421 0 : uint32_t to_pop = std::min(in_len, out_len);
422 :
423 0 : delay_input_buffer.pop(output_buffer, frames_to_samples(to_pop));
424 :
425 0 : return to_pop;
426 : }
427 : /** Returns the number of frames one needs to input into the delay line to get
428 : * #frames_needed frames back.
429 : * @parameter frames_needed the number of frames one want to write into the
430 : * delay_line
431 : * @returns the number of frames one will get. */
432 0 : size_t input_needed_for_output(uint32_t frames_needed)
433 : {
434 0 : return frames_needed;
435 : }
436 : /** Returns the number of frames produces for `input_frames` frames in input */
437 0 : size_t output_for_input(uint32_t input_frames)
438 : {
439 0 : return input_frames;
440 : }
441 : /** The number of frames this delay line delays the stream by.
442 : * @returns The number of frames of delay. */
443 0 : size_t latency()
444 : {
445 0 : return length;
446 : }
447 : private:
448 : /** The length, in frames, of this delay line */
449 : uint32_t length;
450 : /** When `input_buffer` is called, this allows tracking the number of samples
451 : that where in the buffer. */
452 : uint32_t leftover_samples;
453 : /** The input buffer, where the delay is applied. */
454 : auto_array<T> delay_input_buffer;
455 : /** The output buffer. This is only ever used if using the ::output with a
456 : * single argument. */
457 : auto_array<T> delay_output_buffer;
458 : };
459 :
460 : /** This sits behind the C API and is more typed. */
461 : template<typename T>
462 : cubeb_resampler *
463 0 : cubeb_resampler_create_internal(cubeb_stream * stream,
464 : cubeb_stream_params * input_params,
465 : cubeb_stream_params * output_params,
466 : unsigned int target_rate,
467 : cubeb_data_callback callback,
468 : void * user_ptr,
469 : cubeb_resampler_quality quality)
470 : {
471 0 : std::unique_ptr<cubeb_resampler_speex_one_way<T>> input_resampler = nullptr;
472 0 : std::unique_ptr<cubeb_resampler_speex_one_way<T>> output_resampler = nullptr;
473 0 : std::unique_ptr<delay_line<T>> input_delay = nullptr;
474 0 : std::unique_ptr<delay_line<T>> output_delay = nullptr;
475 :
476 0 : assert((input_params || output_params) &&
477 : "need at least one valid parameter pointer.");
478 :
479 : /* All the streams we have have a sample rate that matches the target
480 : sample rate, use a no-op resampler, that simply forwards the buffers to the
481 : callback. */
482 0 : if (((input_params && input_params->rate == target_rate) &&
483 0 : (output_params && output_params->rate == target_rate)) ||
484 0 : (input_params && !output_params && (input_params->rate == target_rate)) ||
485 0 : (output_params && !input_params && (output_params->rate == target_rate))) {
486 0 : return new passthrough_resampler<T>(stream, callback,
487 : user_ptr,
488 0 : input_params ? input_params->channels : 0);
489 : }
490 :
491 : /* Determine if we need to resampler one or both directions, and create the
492 : resamplers. */
493 0 : if (output_params && (output_params->rate != target_rate)) {
494 0 : output_resampler.reset(
495 0 : new cubeb_resampler_speex_one_way<T>(output_params->channels,
496 : target_rate,
497 : output_params->rate,
498 0 : to_speex_quality(quality)));
499 0 : if (!output_resampler) {
500 0 : return NULL;
501 : }
502 : }
503 :
504 0 : if (input_params && (input_params->rate != target_rate)) {
505 0 : input_resampler.reset(
506 0 : new cubeb_resampler_speex_one_way<T>(input_params->channels,
507 : input_params->rate,
508 : target_rate,
509 0 : to_speex_quality(quality)));
510 0 : if (!input_resampler) {
511 0 : return NULL;
512 : }
513 : }
514 :
515 : /* If we resample only one direction but we have a duplex stream, insert a
516 : * delay line with a length equal to the resampler latency of the
517 : * other direction so that the streams are synchronized. */
518 0 : if (input_resampler && !output_resampler && input_params && output_params) {
519 0 : output_delay.reset(new delay_line<T>(input_resampler->latency(),
520 : output_params->channels));
521 0 : if (!output_delay) {
522 0 : return NULL;
523 : }
524 0 : } else if (output_resampler && !input_resampler && input_params && output_params) {
525 0 : input_delay.reset(new delay_line<T>(output_resampler->latency(),
526 : input_params->channels));
527 0 : if (!input_delay) {
528 0 : return NULL;
529 : }
530 : }
531 :
532 0 : if (input_resampler && output_resampler) {
533 0 : return new cubeb_resampler_speex<T,
534 : cubeb_resampler_speex_one_way<T>,
535 : cubeb_resampler_speex_one_way<T>>
536 : (input_resampler.release(),
537 : output_resampler.release(),
538 0 : stream, callback, user_ptr);
539 0 : } else if (input_resampler) {
540 0 : return new cubeb_resampler_speex<T,
541 : cubeb_resampler_speex_one_way<T>,
542 : delay_line<T>>
543 : (input_resampler.release(),
544 : output_delay.release(),
545 0 : stream, callback, user_ptr);
546 : } else {
547 0 : return new cubeb_resampler_speex<T,
548 : delay_line<T>,
549 : cubeb_resampler_speex_one_way<T>>
550 : (input_delay.release(),
551 : output_resampler.release(),
552 0 : stream, callback, user_ptr);
553 : }
554 : }
555 :
556 : #endif /* CUBEB_RESAMPLER_INTERNAL */
|