LCOV - code coverage report
Current view: top level - media/libcubeb/src - cubeb_resampler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 100 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 51 0.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13