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