| /* | 
 |  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "common_audio/resampler/push_sinc_resampler.h" | 
 |  | 
 | #include <cstdint> | 
 | #include <cstring> | 
 |  | 
 | #include "common_audio/include/audio_util.h" | 
 | #include "common_audio/resampler/sinc_resampler.h" | 
 | #include "rtc_base/checks.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | PushSincResampler::PushSincResampler(size_t source_frames, | 
 |                                      size_t destination_frames) | 
 |     : resampler_(new SincResampler(source_frames * 1.0 / destination_frames, | 
 |                                    source_frames, | 
 |                                    this)), | 
 |       source_ptr_(nullptr), | 
 |       source_ptr_int_(nullptr), | 
 |       destination_frames_(destination_frames), | 
 |       first_pass_(true), | 
 |       source_available_(0) {} | 
 |  | 
 | PushSincResampler::~PushSincResampler() {} | 
 |  | 
 | size_t PushSincResampler::Resample(const int16_t* source, | 
 |                                    size_t source_length, | 
 |                                    int16_t* destination, | 
 |                                    size_t /* destination_capacity */) { | 
 |   if (!float_buffer_.get()) | 
 |     float_buffer_.reset(new float[destination_frames_]); | 
 |  | 
 |   source_ptr_int_ = source; | 
 |   // Pass nullptr as the float source to have Run() read from the int16 source. | 
 |   Resample(nullptr, source_length, float_buffer_.get(), destination_frames_); | 
 |   FloatS16ToS16(float_buffer_.get(), destination_frames_, destination); | 
 |   source_ptr_int_ = nullptr; | 
 |   return destination_frames_; | 
 | } | 
 |  | 
 | size_t PushSincResampler::Resample(const float* source, | 
 |                                    size_t source_length, | 
 |                                    float* destination, | 
 |                                    size_t destination_capacity) { | 
 |   RTC_CHECK_EQ(source_length, resampler_->request_frames()); | 
 |   RTC_CHECK_GE(destination_capacity, destination_frames_); | 
 |   // Cache the source pointer. Calling Resample() will immediately trigger | 
 |   // the Run() callback whereupon we provide the cached value. | 
 |   source_ptr_ = source; | 
 |   source_available_ = source_length; | 
 |  | 
 |   // On the first pass, we call Resample() twice. During the first call, we | 
 |   // provide dummy input and discard the output. This is done to prime the | 
 |   // SincResampler buffer with the correct delay (half the kernel size), thereby | 
 |   // ensuring that all later Resample() calls will only result in one input | 
 |   // request through Run(). | 
 |   // | 
 |   // If this wasn't done, SincResampler would call Run() twice on the first | 
 |   // pass, and we'd have to introduce an entire `source_frames` of delay, rather | 
 |   // than the minimum half kernel. | 
 |   // | 
 |   // It works out that ChunkSize() is exactly the amount of output we need to | 
 |   // request in order to prime the buffer with a single Run() request for | 
 |   // `source_frames`. | 
 |   if (first_pass_) | 
 |     resampler_->Resample(resampler_->ChunkSize(), destination); | 
 |  | 
 |   resampler_->Resample(destination_frames_, destination); | 
 |   source_ptr_ = nullptr; | 
 |   return destination_frames_; | 
 | } | 
 |  | 
 | void PushSincResampler::Run(size_t frames, float* destination) { | 
 |   // Ensure we are only asked for the available samples. This would fail if | 
 |   // Run() was triggered more than once per Resample() call. | 
 |   RTC_CHECK_EQ(source_available_, frames); | 
 |  | 
 |   if (first_pass_) { | 
 |     // Provide dummy input on the first pass, the output of which will be | 
 |     // discarded, as described in Resample(). | 
 |     std::memset(destination, 0, frames * sizeof(*destination)); | 
 |     first_pass_ = false; | 
 |     return; | 
 |   } | 
 |  | 
 |   if (source_ptr_) { | 
 |     std::memcpy(destination, source_ptr_, frames * sizeof(*destination)); | 
 |   } else { | 
 |     for (size_t i = 0; i < frames; ++i) | 
 |       destination[i] = static_cast<float>(source_ptr_int_[i]); | 
 |   } | 
 |   source_available_ -= frames; | 
 | } | 
 |  | 
 | }  // namespace webrtc |