cubeb_resampler.cpp (13098B)
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 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 39 min_buffered_audio_frame(uint32_t sample_rate) 40 { 41 return sample_rate / 20; 42 } 43 44 template <typename T> 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 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>:: 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, 149 OutputProcessor>::~cubeb_resampler_speex() 150 { 151 } 152 153 template <typename T, typename InputProcessor, typename OutputProcessor> 154 long 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 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 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 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 * 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 cubeb_resampler_reclock reclock) 328 { 329 cubeb_sample_format format; 330 331 assert(input_params || output_params); 332 333 if (input_params) { 334 format = input_params->format; 335 } else { 336 format = output_params->format; 337 } 338 339 switch (format) { 340 case CUBEB_SAMPLE_S16NE: 341 return cubeb_resampler_create_internal<short>( 342 stream, input_params, output_params, target_rate, callback, user_ptr, 343 quality, reclock); 344 case CUBEB_SAMPLE_FLOAT32NE: 345 return cubeb_resampler_create_internal<float>( 346 stream, input_params, output_params, target_rate, callback, user_ptr, 347 quality, reclock); 348 default: 349 assert(false); 350 return nullptr; 351 } 352 } 353 354 long 355 cubeb_resampler_fill(cubeb_resampler * resampler, void * input_buffer, 356 long * input_frames_count, void * output_buffer, 357 long output_frames_needed) 358 { 359 return resampler->fill(input_buffer, input_frames_count, output_buffer, 360 output_frames_needed); 361 } 362 363 void 364 cubeb_resampler_destroy(cubeb_resampler * resampler) 365 { 366 delete resampler; 367 } 368 369 long 370 cubeb_resampler_latency(cubeb_resampler * resampler) 371 { 372 return resampler->latency(); 373 }