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