tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cubeb_resampler.cpp (13209B)


      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 }
    374 
    375 cubeb_resampler_stats
    376 cubeb_resampler_stats_get(cubeb_resampler * resampler)
    377 {
    378  return resampler->stats();
    379 }