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 <algorithm>
12 #include <cmath>
13 #include <cassert>
14 #include <cstring>
15 #include <cstddef>
16 #include <cstdio>
17 #include "cubeb_resampler.h"
18 #include "cubeb-speex-resampler.h"
19 #include "cubeb_resampler_internal.h"
20 #include "cubeb_utils.h"
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
min_buffered_audio_frame(uint32_t sample_rate)38 uint32_t min_buffered_audio_frame(uint32_t sample_rate)
39 {
40 return sample_rate / 20;
41 }
42
43 template<typename T>
passthrough_resampler(cubeb_stream * s,cubeb_data_callback cb,void * ptr,uint32_t input_channels,uint32_t sample_rate)44 passthrough_resampler<T>::passthrough_resampler(cubeb_stream * s,
45 cubeb_data_callback cb,
46 void * ptr,
47 uint32_t input_channels,
48 uint32_t sample_rate)
49 : processor(input_channels)
50 , stream(s)
51 , data_callback(cb)
52 , user_ptr(ptr)
53 , sample_rate(sample_rate)
54 {
55 }
56
57 template<typename T>
fill(void * input_buffer,long * input_frames_count,void * output_buffer,long output_frames)58 long passthrough_resampler<T>::fill(void * input_buffer, long * input_frames_count,
59 void * output_buffer, long output_frames)
60 {
61 if (input_buffer) {
62 assert(input_frames_count);
63 }
64 assert((input_buffer && output_buffer &&
65 *input_frames_count + static_cast<int>(samples_to_frames(internal_input_buffer.length())) >= output_frames) ||
66 (output_buffer && !input_buffer && (!input_frames_count || *input_frames_count == 0)) ||
67 (input_buffer && !output_buffer && output_frames == 0));
68
69 if (input_buffer) {
70 if (!output_buffer) {
71 output_frames = *input_frames_count;
72 }
73 internal_input_buffer.push(static_cast<T*>(input_buffer),
74 frames_to_samples(*input_frames_count));
75 }
76
77 long rv = data_callback(stream, user_ptr, internal_input_buffer.data(),
78 output_buffer, output_frames);
79
80 if (input_buffer) {
81 internal_input_buffer.pop(nullptr, frames_to_samples(output_frames));
82 *input_frames_count = output_frames;
83 drop_audio_if_needed();
84 }
85
86 return rv;
87 }
88
89 template<typename T, typename InputProcessor, typename OutputProcessor>
90 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
cubeb_resampler_speex(InputProcessor * input_processor,OutputProcessor * output_processor,cubeb_stream * s,cubeb_data_callback cb,void * ptr)91 ::cubeb_resampler_speex(InputProcessor * input_processor,
92 OutputProcessor * output_processor,
93 cubeb_stream * s,
94 cubeb_data_callback cb,
95 void * ptr)
96 : input_processor(input_processor)
97 , output_processor(output_processor)
98 , stream(s)
99 , data_callback(cb)
100 , user_ptr(ptr)
101 {
102 if (input_processor && output_processor) {
103 // Add some delay on the processor that has the lowest delay so that the
104 // streams are synchronized.
105 uint32_t in_latency = input_processor->latency();
106 uint32_t out_latency = output_processor->latency();
107 if (in_latency > out_latency) {
108 uint32_t latency_diff = in_latency - out_latency;
109 output_processor->add_latency(latency_diff);
110 } else if (in_latency < out_latency) {
111 uint32_t latency_diff = out_latency - in_latency;
112 input_processor->add_latency(latency_diff);
113 }
114 fill_internal = &cubeb_resampler_speex::fill_internal_duplex;
115 } else if (input_processor) {
116 fill_internal = &cubeb_resampler_speex::fill_internal_input;
117 } else if (output_processor) {
118 fill_internal = &cubeb_resampler_speex::fill_internal_output;
119 }
120 }
121
122 template<typename T, typename InputProcessor, typename OutputProcessor>
123 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
~cubeb_resampler_speex()124 ::~cubeb_resampler_speex()
125 { }
126
127 template<typename T, typename InputProcessor, typename OutputProcessor>
128 long
129 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
fill(void * input_buffer,long * input_frames_count,void * output_buffer,long output_frames_needed)130 ::fill(void * input_buffer, long * input_frames_count,
131 void * output_buffer, long output_frames_needed)
132 {
133 /* Input and output buffers, typed */
134 T * in_buffer = reinterpret_cast<T*>(input_buffer);
135 T * out_buffer = reinterpret_cast<T*>(output_buffer);
136 return (this->*fill_internal)(in_buffer, input_frames_count,
137 out_buffer, output_frames_needed);
138 }
139
140 template<typename T, typename InputProcessor, typename OutputProcessor>
141 long
142 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
fill_internal_output(T * input_buffer,long * input_frames_count,T * output_buffer,long output_frames_needed)143 ::fill_internal_output(T * input_buffer, long * input_frames_count,
144 T * output_buffer, long output_frames_needed)
145 {
146 assert(!input_buffer && (!input_frames_count || *input_frames_count == 0) &&
147 output_buffer && output_frames_needed);
148
149 if (!draining) {
150 long got = 0;
151 T * out_unprocessed = nullptr;
152 long output_frames_before_processing = 0;
153
154 /* fill directly the input buffer of the output processor to save a copy */
155 output_frames_before_processing =
156 output_processor->input_needed_for_output(output_frames_needed);
157
158 out_unprocessed =
159 output_processor->input_buffer(output_frames_before_processing);
160
161 got = data_callback(stream, user_ptr,
162 nullptr, out_unprocessed,
163 output_frames_before_processing);
164
165 if (got < output_frames_before_processing) {
166 draining = true;
167
168 if (got < 0) {
169 return got;
170 }
171 }
172
173 output_processor->written(got);
174 }
175
176 /* Process the output. If not enough frames have been returned from the
177 * callback, drain the processors. */
178 return output_processor->output(output_buffer, output_frames_needed);
179 }
180
181 template<typename T, typename InputProcessor, typename OutputProcessor>
182 long
183 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
fill_internal_input(T * input_buffer,long * input_frames_count,T * output_buffer,long)184 ::fill_internal_input(T * input_buffer, long * input_frames_count,
185 T * output_buffer, long /*output_frames_needed*/)
186 {
187 assert(input_buffer && input_frames_count && *input_frames_count &&
188 !output_buffer);
189
190 /* The input data, after eventual resampling. This is passed to the callback. */
191 T * resampled_input = nullptr;
192 uint32_t resampled_frame_count = input_processor->output_for_input(*input_frames_count);
193
194 /* process the input, and present exactly `output_frames_needed` in the
195 * callback. */
196 input_processor->input(input_buffer, *input_frames_count);
197
198 size_t frames_resampled = 0;
199 resampled_input = input_processor->output(resampled_frame_count, &frames_resampled);
200 *input_frames_count = frames_resampled;
201
202 long got = data_callback(stream, user_ptr,
203 resampled_input, nullptr, resampled_frame_count);
204
205 /* Return the number of initial input frames or part of it.
206 * Since output_frames_needed == 0 in input scenario, the only
207 * available number outside resampler is the initial number of frames. */
208 return (*input_frames_count) * (got / resampled_frame_count);
209 }
210
211 template<typename T, typename InputProcessor, typename OutputProcessor>
212 long
213 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
fill_internal_duplex(T * in_buffer,long * input_frames_count,T * out_buffer,long output_frames_needed)214 ::fill_internal_duplex(T * in_buffer, long * input_frames_count,
215 T * out_buffer, long output_frames_needed)
216 {
217 if (draining) {
218 // discard input and drain any signal remaining in the resampler.
219 return output_processor->output(out_buffer, output_frames_needed);
220 }
221
222 /* The input data, after eventual resampling. This is passed to the callback. */
223 T * resampled_input = nullptr;
224 /* The output buffer passed down in the callback, that might be resampled. */
225 T * out_unprocessed = nullptr;
226 long output_frames_before_processing = 0;
227 /* The number of frames returned from the callback. */
228 long got = 0;
229
230 /* We need to determine how much frames to present to the consumer.
231 * - If we have a two way stream, but we're only resampling input, we resample
232 * the input to the number of output frames.
233 * - If we have a two way stream, but we're only resampling the output, we
234 * resize the input buffer of the output resampler to the number of input
235 * frames, and we resample it afterwards.
236 * - If we resample both ways, we resample the input to the number of frames
237 * we would need to pass down to the consumer (before resampling the output),
238 * get the output data, and resample it to the number of frames needed by the
239 * caller. */
240
241 output_frames_before_processing =
242 output_processor->input_needed_for_output(output_frames_needed);
243 /* fill directly the input buffer of the output processor to save a copy */
244 out_unprocessed =
245 output_processor->input_buffer(output_frames_before_processing);
246
247 if (in_buffer) {
248 /* process the input, and present exactly `output_frames_needed` in the
249 * callback. */
250 input_processor->input(in_buffer, *input_frames_count);
251
252 size_t frames_resampled = 0;
253 resampled_input =
254 input_processor->output(output_frames_before_processing, &frames_resampled);
255 *input_frames_count = frames_resampled;
256 } else {
257 resampled_input = nullptr;
258 }
259
260 got = data_callback(stream, user_ptr,
261 resampled_input, out_unprocessed,
262 output_frames_before_processing);
263
264 if (got < output_frames_before_processing) {
265 draining = true;
266
267 if (got < 0) {
268 return got;
269 }
270 }
271
272 output_processor->written(got);
273
274 input_processor->drop_audio_if_needed();
275
276 /* Process the output. If not enough frames have been returned from the
277 * callback, drain the processors. */
278 got = output_processor->output(out_buffer, output_frames_needed);
279
280 output_processor->drop_audio_if_needed();
281
282 return got;
283 }
284
285 /* Resampler C API */
286
287 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)288 cubeb_resampler_create(cubeb_stream * stream,
289 cubeb_stream_params * input_params,
290 cubeb_stream_params * output_params,
291 unsigned int target_rate,
292 cubeb_data_callback callback,
293 void * user_ptr,
294 cubeb_resampler_quality quality)
295 {
296 cubeb_sample_format format;
297
298 assert(input_params || output_params);
299
300 if (input_params) {
301 format = input_params->format;
302 } else {
303 format = output_params->format;
304 }
305
306 switch(format) {
307 case CUBEB_SAMPLE_S16NE:
308 return cubeb_resampler_create_internal<short>(stream,
309 input_params,
310 output_params,
311 target_rate,
312 callback,
313 user_ptr,
314 quality);
315 case CUBEB_SAMPLE_FLOAT32NE:
316 return cubeb_resampler_create_internal<float>(stream,
317 input_params,
318 output_params,
319 target_rate,
320 callback,
321 user_ptr,
322 quality);
323 default:
324 assert(false);
325 return nullptr;
326 }
327 }
328
329 long
cubeb_resampler_fill(cubeb_resampler * resampler,void * input_buffer,long * input_frames_count,void * output_buffer,long output_frames_needed)330 cubeb_resampler_fill(cubeb_resampler * resampler,
331 void * input_buffer,
332 long * input_frames_count,
333 void * output_buffer,
334 long output_frames_needed)
335 {
336 return resampler->fill(input_buffer, input_frames_count,
337 output_buffer, output_frames_needed);
338 }
339
340 void
cubeb_resampler_destroy(cubeb_resampler * resampler)341 cubeb_resampler_destroy(cubeb_resampler * resampler)
342 {
343 delete resampler;
344 }
345
346 long
cubeb_resampler_latency(cubeb_resampler * resampler)347 cubeb_resampler_latency(cubeb_resampler * resampler)
348 {
349 return resampler->latency();
350 }
351