15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/multi_channel_resampler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/audio_bus.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiChannelResampler::MultiChannelResampler(int channels, 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double io_sample_rate_ratio, 16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t request_size, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ReadCB& read_cb) 18a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) : read_cb_(read_cb), 19a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) wrapped_resampler_audio_bus_(AudioBus::CreateWrapper(channels)), 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output_frames_ready_(0) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allocate each channel's resampler. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resamplers_.reserve(channels); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < channels; ++i) { 24b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) resamplers_.push_back(new SincResampler( 25b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) io_sample_rate_ratio, request_size, base::Bind( 26b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) &MultiChannelResampler::ProvideInput, base::Unretained(this), i))); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Setup the wrapped AudioBus for channel data. 30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) wrapped_resampler_audio_bus_->set_frames(request_size); 31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Allocate storage for all channels except the first, which will use the 33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // |destination| provided to ProvideInput() directly. 34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (channels > 1) { 35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_audio_bus_ = AudioBus::Create(channels - 1, request_size); 36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) for (int i = 0; i < resampler_audio_bus_->channels(); ++i) { 37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) wrapped_resampler_audio_bus_->SetChannelData( 38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) i + 1, resampler_audio_bus_->channel(i)); 39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiChannelResampler::~MultiChannelResampler() {} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void MultiChannelResampler::Resample(int frames, AudioBus* audio_bus) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(static_cast<size_t>(audio_bus->channels()), resamplers_.size()); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 48b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Optimize the single channel case to avoid the chunking process below. 49b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (audio_bus->channels() == 1) { 50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) resamplers_[0]->Resample(frames, audio_bus->channel(0)); 51b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return; 52b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to ensure that SincResampler only calls ProvideInput once for each 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // channel. To ensure this, we chunk the number of requested frames into 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SincResampler::ChunkSize() sized chunks. SincResampler guarantees it will 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // only call ProvideInput() once when we resample this way. 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output_frames_ready_ = 0; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (output_frames_ready_ < frames) { 60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int chunk_size = resamplers_[0]->ChunkSize(); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int frames_this_time = std::min(frames - output_frames_ready_, chunk_size); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Resample each channel. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < resamplers_.size(); ++i) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(chunk_size, resamplers_[i]->ChunkSize()); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Depending on the sample-rate scale factor, and the internal buffering 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used in a SincResampler kernel, this call to Resample() will only 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sometimes call ProvideInput(). However, if it calls ProvideInput() for 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the first channel, then it will call it for the remaining channels, 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // since they all buffer in the same way and are processing the same 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // number of frames. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resamplers_[i]->Resample( 74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) frames_this_time, audio_bus->channel(i) + output_frames_ready_); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output_frames_ready_ += frames_this_time; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void MultiChannelResampler::ProvideInput(int channel, 82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) int frames, 83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) float* destination) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the data from the multi-channel provider when the first channel asks 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for it. For subsequent channels, we can just dish out the channel data 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from that (stored in |resampler_audio_bus_|). 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (channel == 0) { 88a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) wrapped_resampler_audio_bus_->SetChannelData(0, destination); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) read_cb_.Run(output_frames_ready_, wrapped_resampler_audio_bus_.get()); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All channels must ask for the same amount. This should always be the 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // case, but let's just make sure. 93a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DCHECK_EQ(frames, wrapped_resampler_audio_bus_->frames()); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy the channel data from what we received from |read_cb_|. 96a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) memcpy(destination, wrapped_resampler_audio_bus_->channel(channel), 97a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) sizeof(*wrapped_resampler_audio_bus_->channel(channel)) * frames); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiChannelResampler::Flush() { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < resamplers_.size(); ++i) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resamplers_[i]->Flush(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MultiChannelResampler::SetRatio(double io_sample_rate_ratio) { 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < resamplers_.size(); ++i) 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) resamplers_[i]->SetRatio(io_sample_rate_ratio); 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 11123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)int MultiChannelResampler::ChunkSize() const { 11223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DCHECK(!resamplers_.empty()); 11323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return resamplers_[0]->ChunkSize(); 11423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)} 11523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 117