1 /*
2 * Copyright © 2014 Mozilla Foundation
3 *
4 * This program is made available under an ISC-style license. See the
5 * accompanying file LICENSE for details.
6 */
7 #ifndef NOMINMAX
8 #define NOMINMAX
9 #endif // NOMINMAX
10
11 #include "cubeb_resampler.h"
12 #include "cubeb-speex-resampler.h"
13 #include "cubeb_resampler_internal.h"
14 #include "cubeb_utils.h"
15 #include <algorithm>
16 #include <cassert>
17 #include <cmath>
18 #include <cstddef>
19 #include <cstdio>
20 #include <cstring>
21
22 int
to_speex_quality(cubeb_resampler_quality q)23 to_speex_quality(cubeb_resampler_quality q)
24 {
25 switch (q) {
26 case CUBEB_RESAMPLER_QUALITY_VOIP:
27 return SPEEX_RESAMPLER_QUALITY_VOIP;
28 case CUBEB_RESAMPLER_QUALITY_DEFAULT:
29 return SPEEX_RESAMPLER_QUALITY_DEFAULT;
30 case CUBEB_RESAMPLER_QUALITY_DESKTOP:
31 return SPEEX_RESAMPLER_QUALITY_DESKTOP;
32 default:
33 assert(false);
34 return 0XFFFFFFFF;
35 }
36 }
37
38 uint32_t
min_buffered_audio_frame(uint32_t sample_rate)39 min_buffered_audio_frame(uint32_t sample_rate)
40 {
41 return sample_rate / 20;
42 }
43
44 template <typename T>
passthrough_resampler(cubeb_stream * s,cubeb_data_callback cb,void * ptr,uint32_t input_channels,uint32_t sample_rate)45 passthrough_resampler<T>::passthrough_resampler(cubeb_stream * s,
46 cubeb_data_callback cb,
47 void * ptr,
48 uint32_t input_channels,
49 uint32_t sample_rate)
50 : processor(input_channels), stream(s), data_callback(cb), user_ptr(ptr),
51 sample_rate(sample_rate)
52 {
53 }
54
55 template <typename T>
56 long
fill(void * input_buffer,long * input_frames_count,void * output_buffer,long output_frames)57 passthrough_resampler<T>::fill(void * input_buffer, long * input_frames_count,
58 void * output_buffer, long output_frames)
59 {
60 if (input_buffer) {
61 assert(input_frames_count);
62 }
63 assert((input_buffer && output_buffer) ||
64 (output_buffer && !input_buffer &&
65 (!input_frames_count || *input_frames_count == 0)) ||
66 (input_buffer && !output_buffer && output_frames == 0));
67
68 // When we have no pending input data and exactly as much input
69 // as output data, we don't need to copy it into the internal buffer
70 // and can directly forward it to the callback.
71 void * in_buf = input_buffer;
72 unsigned long pop_input_count = 0u;
73 if (input_buffer && !output_buffer) {
74 output_frames = *input_frames_count;
75 } else if (input_buffer) {
76 if (internal_input_buffer.length() != 0 ||
77 *input_frames_count < output_frames) {
78 // If we have pending input data left and have to first append the input
79 // so we can pass it as one pointer to the callback. Or this is a glitch.
80 // It can happen when system's performance is poor. Audible silence is
81 // being pushed at the end of the short input buffer. An improvement for
82 // the future is to resample to the output number of frames, when that
83 // happens.
84 internal_input_buffer.push(static_cast<T *>(input_buffer),
85 frames_to_samples(*input_frames_count));
86 if (internal_input_buffer.length() < frames_to_samples(output_frames)) {
87 // This is unxpected but it can happen when a glitch occurs. Fill the
88 // buffer with silence. First keep the actual number of input samples
89 // used without the silence.
90 pop_input_count = internal_input_buffer.length();
91 internal_input_buffer.push_silence(frames_to_samples(output_frames) -
92 internal_input_buffer.length());
93 } else {
94 pop_input_count = frames_to_samples(output_frames);
95 }
96 in_buf = internal_input_buffer.data();
97 } else if (*input_frames_count > output_frames) {
98 // In this case we have more input that we need output and
99 // fill the overflowing input into internal_input_buffer
100 // Since we have no other pending data, we can nonetheless
101 // pass the current input data directly to the callback
102 assert(pop_input_count == 0);
103 unsigned long samples_off = frames_to_samples(output_frames);
104 internal_input_buffer.push(
105 static_cast<T *>(input_buffer) + samples_off,
106 frames_to_samples(*input_frames_count - output_frames));
107 }
108 }
109
110 long rv =
111 data_callback(stream, user_ptr, in_buf, output_buffer, output_frames);
112
113 if (input_buffer) {
114 if (pop_input_count) {
115 internal_input_buffer.pop(nullptr, pop_input_count);
116 *input_frames_count = samples_to_frames(pop_input_count);
117 } else {
118 *input_frames_count = output_frames;
119 }
120 drop_audio_if_needed();
121 }
122
123 return rv;
124 }
125
126 // Explicit instantiation of template class.
127 template class passthrough_resampler<float>;
128 template class passthrough_resampler<short>;
129
130 template <typename T, typename InputProcessor, typename OutputProcessor>
131 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::
cubeb_resampler_speex(InputProcessor * input_processor,OutputProcessor * output_processor,cubeb_stream * s,cubeb_data_callback cb,void * ptr)132 cubeb_resampler_speex(InputProcessor * input_processor,
133 OutputProcessor * output_processor, cubeb_stream * s,
134 cubeb_data_callback cb, void * ptr)
135 : input_processor(input_processor), output_processor(output_processor),
136 stream(s), data_callback(cb), user_ptr(ptr)
137 {
138 if (input_processor && output_processor) {
139 fill_internal = &cubeb_resampler_speex::fill_internal_duplex;
140 } else if (input_processor) {
141 fill_internal = &cubeb_resampler_speex::fill_internal_input;
142 } else if (output_processor) {
143 fill_internal = &cubeb_resampler_speex::fill_internal_output;
144 }
145 }
146
147 template <typename T, typename InputProcessor, typename OutputProcessor>
148 cubeb_resampler_speex<T, InputProcessor,
~cubeb_resampler_speex()149 OutputProcessor>::~cubeb_resampler_speex()
150 {
151 }
152
153 template <typename T, typename InputProcessor, typename OutputProcessor>
154 long
fill(void * input_buffer,long * input_frames_count,void * output_buffer,long output_frames_needed)155 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill(
156 void * input_buffer, long * input_frames_count, void * output_buffer,
157 long output_frames_needed)
158 {
159 /* Input and output buffers, typed */
160 T * in_buffer = reinterpret_cast<T *>(input_buffer);
161 T * out_buffer = reinterpret_cast<T *>(output_buffer);
162 return (this->*fill_internal)(in_buffer, input_frames_count, out_buffer,
163 output_frames_needed);
164 }
165
166 template <typename T, typename InputProcessor, typename OutputProcessor>
167 long
fill_internal_output(T * input_buffer,long * input_frames_count,T * output_buffer,long output_frames_needed)168 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill_internal_output(
169 T * input_buffer, long * input_frames_count, T * output_buffer,
170 long output_frames_needed)
171 {
172 assert(!input_buffer && (!input_frames_count || *input_frames_count == 0) &&
173 output_buffer && output_frames_needed);
174
175 if (!draining) {
176 long got = 0;
177 T * out_unprocessed = nullptr;
178 long output_frames_before_processing = 0;
179
180 /* fill directly the input buffer of the output processor to save a copy */
181 output_frames_before_processing =
182 output_processor->input_needed_for_output(output_frames_needed);
183
184 out_unprocessed =
185 output_processor->input_buffer(output_frames_before_processing);
186
187 got = data_callback(stream, user_ptr, nullptr, out_unprocessed,
188 output_frames_before_processing);
189
190 if (got < output_frames_before_processing) {
191 draining = true;
192
193 if (got < 0) {
194 return got;
195 }
196 }
197
198 output_processor->written(got);
199 }
200
201 /* Process the output. If not enough frames have been returned from the
202 * callback, drain the processors. */
203 return output_processor->output(output_buffer, output_frames_needed);
204 }
205
206 template <typename T, typename InputProcessor, typename OutputProcessor>
207 long
fill_internal_input(T * input_buffer,long * input_frames_count,T * output_buffer,long)208 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill_internal_input(
209 T * input_buffer, long * input_frames_count, T * output_buffer,
210 long /*output_frames_needed*/)
211 {
212 assert(input_buffer && input_frames_count && *input_frames_count &&
213 !output_buffer);
214
215 /* The input data, after eventual resampling. This is passed to the callback.
216 */
217 T * resampled_input = nullptr;
218 uint32_t resampled_frame_count =
219 input_processor->output_for_input(*input_frames_count);
220
221 /* process the input, and present exactly `output_frames_needed` in the
222 * callback. */
223 input_processor->input(input_buffer, *input_frames_count);
224
225 /* resampled_frame_count == 0 happens if the resampler
226 * doesn't have enough input frames buffered to produce 1 resampled frame. */
227 if (resampled_frame_count == 0) {
228 return *input_frames_count;
229 }
230
231 size_t frames_resampled = 0;
232 resampled_input =
233 input_processor->output(resampled_frame_count, &frames_resampled);
234 *input_frames_count = frames_resampled;
235
236 long got = data_callback(stream, user_ptr, resampled_input, nullptr,
237 resampled_frame_count);
238
239 /* Return the number of initial input frames or part of it.
240 * Since output_frames_needed == 0 in input scenario, the only
241 * available number outside resampler is the initial number of frames. */
242 return (*input_frames_count) * (got / resampled_frame_count);
243 }
244
245 template <typename T, typename InputProcessor, typename OutputProcessor>
246 long
fill_internal_duplex(T * in_buffer,long * input_frames_count,T * out_buffer,long output_frames_needed)247 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>::fill_internal_duplex(
248 T * in_buffer, long * input_frames_count, T * out_buffer,
249 long output_frames_needed)
250 {
251 if (draining) {
252 // discard input and drain any signal remaining in the resampler.
253 return output_processor->output(out_buffer, output_frames_needed);
254 }
255
256 /* The input data, after eventual resampling. This is passed to the callback.
257 */
258 T * resampled_input = nullptr;
259 /* The output buffer passed down in the callback, that might be resampled. */
260 T * out_unprocessed = nullptr;
261 long output_frames_before_processing = 0;
262 /* The number of frames returned from the callback. */
263 long got = 0;
264
265 /* We need to determine how much frames to present to the consumer.
266 * - If we have a two way stream, but we're only resampling input, we resample
267 * the input to the number of output frames.
268 * - If we have a two way stream, but we're only resampling the output, we
269 * resize the input buffer of the output resampler to the number of input
270 * frames, and we resample it afterwards.
271 * - If we resample both ways, we resample the input to the number of frames
272 * we would need to pass down to the consumer (before resampling the output),
273 * get the output data, and resample it to the number of frames needed by the
274 * caller. */
275
276 output_frames_before_processing =
277 output_processor->input_needed_for_output(output_frames_needed);
278 /* fill directly the input buffer of the output processor to save a copy */
279 out_unprocessed =
280 output_processor->input_buffer(output_frames_before_processing);
281
282 if (in_buffer) {
283 /* process the input, and present exactly `output_frames_needed` in the
284 * callback. */
285 input_processor->input(in_buffer, *input_frames_count);
286
287 size_t frames_resampled = 0;
288 resampled_input = input_processor->output(output_frames_before_processing,
289 &frames_resampled);
290 *input_frames_count = frames_resampled;
291 } else {
292 resampled_input = nullptr;
293 }
294
295 got = data_callback(stream, user_ptr, resampled_input, out_unprocessed,
296 output_frames_before_processing);
297
298 if (got < output_frames_before_processing) {
299 draining = true;
300
301 if (got < 0) {
302 return got;
303 }
304 }
305
306 output_processor->written(got);
307
308 input_processor->drop_audio_if_needed();
309
310 /* Process the output. If not enough frames have been returned from the
311 * callback, drain the processors. */
312 got = output_processor->output(out_buffer, output_frames_needed);
313
314 output_processor->drop_audio_if_needed();
315
316 return got;
317 }
318
319 /* Resampler C API */
320
321 cubeb_resampler *
cubeb_resampler_create(cubeb_stream * stream,cubeb_stream_params * input_params,cubeb_stream_params * output_params,unsigned int target_rate,cubeb_data_callback callback,void * user_ptr,cubeb_resampler_quality quality)322 cubeb_resampler_create(cubeb_stream * stream,
323 cubeb_stream_params * input_params,
324 cubeb_stream_params * output_params,
325 unsigned int target_rate, cubeb_data_callback callback,
326 void * user_ptr, cubeb_resampler_quality quality)
327 {
328 cubeb_sample_format format;
329
330 assert(input_params || output_params);
331
332 if (input_params) {
333 format = input_params->format;
334 } else {
335 format = output_params->format;
336 }
337
338 switch (format) {
339 case CUBEB_SAMPLE_S16NE:
340 return cubeb_resampler_create_internal<short>(stream, input_params,
341 output_params, target_rate,
342 callback, user_ptr, quality);
343 case CUBEB_SAMPLE_FLOAT32NE:
344 return cubeb_resampler_create_internal<float>(stream, input_params,
345 output_params, target_rate,
346 callback, user_ptr, quality);
347 default:
348 assert(false);
349 return nullptr;
350 }
351 }
352
353 long
cubeb_resampler_fill(cubeb_resampler * resampler,void * input_buffer,long * input_frames_count,void * output_buffer,long output_frames_needed)354 cubeb_resampler_fill(cubeb_resampler * resampler, void * input_buffer,
355 long * input_frames_count, void * output_buffer,
356 long output_frames_needed)
357 {
358 return resampler->fill(input_buffer, input_frames_count, output_buffer,
359 output_frames_needed);
360 }
361
362 void
cubeb_resampler_destroy(cubeb_resampler * resampler)363 cubeb_resampler_destroy(cubeb_resampler * resampler)
364 {
365 delete resampler;
366 }
367
368 long
cubeb_resampler_latency(cubeb_resampler * resampler)369 cubeb_resampler_latency(cubeb_resampler * resampler)
370 {
371 return resampler->latency();
372 }
373