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