Revert of Cleanup NQE (patchset #5 id:80001 of https://codereview.chromium.org/127748...
[chromium-blink-merge.git] / media / base / multi_channel_resampler.cc
blob4ec44d8ede906fe5e41b51b7c6a0e9a6df87a8fe
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/base/multi_channel_resampler.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/logging.h"
10 #include "media/base/audio_bus.h"
12 namespace media {
14 MultiChannelResampler::MultiChannelResampler(int channels,
15 double io_sample_rate_ratio,
16 size_t request_size,
17 const ReadCB& read_cb)
18 : read_cb_(read_cb),
19 wrapped_resampler_audio_bus_(AudioBus::CreateWrapper(channels)),
20 output_frames_ready_(0) {
21 // Allocate each channel's resampler.
22 resamplers_.reserve(channels);
23 for (int i = 0; i < channels; ++i) {
24 resamplers_.push_back(new SincResampler(
25 io_sample_rate_ratio, request_size, base::Bind(
26 &MultiChannelResampler::ProvideInput, base::Unretained(this), i)));
29 // Setup the wrapped AudioBus for channel data.
30 wrapped_resampler_audio_bus_->set_frames(request_size);
32 // Allocate storage for all channels except the first, which will use the
33 // |destination| provided to ProvideInput() directly.
34 if (channels > 1) {
35 resampler_audio_bus_ = AudioBus::Create(channels - 1, request_size);
36 for (int i = 0; i < resampler_audio_bus_->channels(); ++i) {
37 wrapped_resampler_audio_bus_->SetChannelData(
38 i + 1, resampler_audio_bus_->channel(i));
43 MultiChannelResampler::~MultiChannelResampler() {}
45 void MultiChannelResampler::Resample(int frames, AudioBus* audio_bus) {
46 DCHECK_EQ(static_cast<size_t>(audio_bus->channels()), resamplers_.size());
48 // Optimize the single channel case to avoid the chunking process below.
49 if (audio_bus->channels() == 1) {
50 resamplers_[0]->Resample(frames, audio_bus->channel(0));
51 return;
54 // We need to ensure that SincResampler only calls ProvideInput once for each
55 // channel. To ensure this, we chunk the number of requested frames into
56 // SincResampler::ChunkSize() sized chunks. SincResampler guarantees it will
57 // only call ProvideInput() once when we resample this way.
58 output_frames_ready_ = 0;
59 while (output_frames_ready_ < frames) {
60 int chunk_size = resamplers_[0]->ChunkSize();
61 int frames_this_time = std::min(frames - output_frames_ready_, chunk_size);
63 // Resample each channel.
64 for (size_t i = 0; i < resamplers_.size(); ++i) {
65 DCHECK_EQ(chunk_size, resamplers_[i]->ChunkSize());
67 // Depending on the sample-rate scale factor, and the internal buffering
68 // used in a SincResampler kernel, this call to Resample() will only
69 // sometimes call ProvideInput(). However, if it calls ProvideInput() for
70 // the first channel, then it will call it for the remaining channels,
71 // since they all buffer in the same way and are processing the same
72 // number of frames.
73 resamplers_[i]->Resample(
74 frames_this_time, audio_bus->channel(i) + output_frames_ready_);
77 output_frames_ready_ += frames_this_time;
81 void MultiChannelResampler::ProvideInput(int channel,
82 int frames,
83 float* destination) {
84 // Get the data from the multi-channel provider when the first channel asks
85 // for it. For subsequent channels, we can just dish out the channel data
86 // from that (stored in |resampler_audio_bus_|).
87 if (channel == 0) {
88 wrapped_resampler_audio_bus_->SetChannelData(0, destination);
89 read_cb_.Run(output_frames_ready_, wrapped_resampler_audio_bus_.get());
90 } else {
91 // All channels must ask for the same amount. This should always be the
92 // case, but let's just make sure.
93 DCHECK_EQ(frames, wrapped_resampler_audio_bus_->frames());
95 // Copy the channel data from what we received from |read_cb_|.
96 memcpy(destination, wrapped_resampler_audio_bus_->channel(channel),
97 sizeof(*wrapped_resampler_audio_bus_->channel(channel)) * frames);
101 void MultiChannelResampler::Flush() {
102 for (size_t i = 0; i < resamplers_.size(); ++i)
103 resamplers_[i]->Flush();
106 void MultiChannelResampler::SetRatio(double io_sample_rate_ratio) {
107 for (size_t i = 0; i < resamplers_.size(); ++i)
108 resamplers_[i]->SetRatio(io_sample_rate_ratio);
111 int MultiChannelResampler::ChunkSize() const {
112 DCHECK(!resamplers_.empty());
113 return resamplers_[0]->ChunkSize();
117 double MultiChannelResampler::BufferedFrames() const {
118 DCHECK(!resamplers_.empty());
119 return resamplers_[0]->BufferedFrames();
122 void MultiChannelResampler::PrimeWithSilence() {
123 DCHECK(!resamplers_.empty());
124 for (size_t i = 0; i < resamplers_.size(); ++i)
125 resamplers_[i]->PrimeWithSilence();
128 } // namespace media