| Index: chromecast/media/cma/backend/alsa/filter_group.cc | 
| diff --git a/chromecast/media/cma/backend/alsa/filter_group.cc b/chromecast/media/cma/backend/alsa/filter_group.cc | 
| index 1fa4df6952b435096a288b02e31cad404cfc3bf0..08796942dcd21ee48343772106f06484eaf909d7 100644 | 
| --- a/chromecast/media/cma/backend/alsa/filter_group.cc | 
| +++ b/chromecast/media/cma/backend/alsa/filter_group.cc | 
| @@ -3,6 +3,9 @@ | 
| // found in the LICENSE file. | 
|  | 
| #include "chromecast/media/cma/backend/alsa/filter_group.h" | 
| + | 
| +#include "base/memory/ptr_util.h" | 
| +#include "chromecast/media/cma/backend/alsa/post_processing_pipeline.h" | 
| #include "media/base/audio_bus.h" | 
|  | 
| namespace chromecast { | 
| @@ -12,30 +15,28 @@ namespace { | 
|  | 
| // How many seconds of silence should be passed to the filters to flush them. | 
| const float kSilenceSecondsToFilter = 1.0f; | 
| -const int kNumOutputChannels = 2; | 
|  | 
| }  // namespace | 
|  | 
| FilterGroup::FilterGroup(const std::unordered_set<std::string>& input_types, | 
| -                         AudioFilterFactory::FilterType filter_type, | 
| -                         AudioContentType content_type) | 
| +                         AudioContentType content_type, | 
| +                         int channels, | 
| +                         const base::ListValue* filter_list) | 
| : input_types_(input_types), | 
| content_type_(content_type), | 
| +      channels_(channels), | 
| output_samples_per_second_(0), | 
| -      sample_format_(::media::SampleFormat::kUnknownSampleFormat), | 
| -      audio_filter_(AudioFilterFactory::MakeAudioFilter(filter_type)), | 
| +      post_processing_pipeline_( | 
| +          base::MakeUnique<PostProcessingPipeline>(filter_list, channels_)), | 
| silence_frames_filtered_(0) {} | 
|  | 
| FilterGroup::~FilterGroup() = default; | 
|  | 
| -void FilterGroup::Initialize(int output_samples_per_second, | 
| -                             ::media::SampleFormat format) { | 
| +void FilterGroup::Initialize(int output_samples_per_second) { | 
| output_samples_per_second_ = output_samples_per_second; | 
| -  sample_format_ = format; | 
| -  if (audio_filter_) { | 
| -    audio_filter_->SetSampleRateAndFormat(output_samples_per_second_, | 
| -                                          sample_format_); | 
| -  } | 
| +  post_processing_pipeline_->SetSampleRate(output_samples_per_second); | 
| +  silence_frames_to_filter_ = | 
| +      post_processing_pipeline_->GetRingingTimeInFrames(); | 
| silence_frames_filtered_ = 0; | 
| } | 
|  | 
| @@ -53,11 +54,8 @@ std::vector<uint8_t>* FilterGroup::GetInterleaved() { | 
|  | 
| bool FilterGroup::MixAndFilter(int chunk_size) { | 
| DCHECK_NE(output_samples_per_second_, 0); | 
| -  DCHECK_NE(sample_format_, ::media::SampleFormat::kUnknownSampleFormat); | 
| if (active_inputs_.empty()) { | 
| -    int silence_frames_to_filter = | 
| -        output_samples_per_second_ * kSilenceSecondsToFilter; | 
| -    if (audio_filter_ && silence_frames_filtered_ < silence_frames_to_filter) { | 
| +    if (silence_frames_filtered_ < silence_frames_to_filter_) { | 
| silence_frames_filtered_ += chunk_size; | 
| } else { | 
| return false;  // Output will be silence, no need to mix. | 
| @@ -71,7 +69,7 @@ bool FilterGroup::MixAndFilter(int chunk_size) { | 
| mixed_->ZeroFramesPartial(0, chunk_size); | 
| for (StreamMixerAlsa::InputQueue* input : active_inputs_) { | 
| input->GetResampledData(temp_.get(), chunk_size); | 
| -    for (int c = 0; c < kNumOutputChannels; ++c) { | 
| +    for (int c = 0; c < channels_; ++c) { | 
| input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size, | 
| mixed_->channel(c)); | 
| } | 
| @@ -79,30 +77,29 @@ bool FilterGroup::MixAndFilter(int chunk_size) { | 
|  | 
| mixed_->ToInterleaved(chunk_size, BytesPerOutputFormatSample(), | 
| interleaved_.data()); | 
| -  if (audio_filter_) { | 
| -    audio_filter_->ProcessInterleaved(interleaved_.data(), chunk_size, volume_); | 
| -  } | 
| +  post_processing_pipeline_->ProcessFrames(interleaved_.data(), chunk_size, | 
| +                                           volume_); | 
|  | 
| return true; | 
| } | 
|  | 
| void FilterGroup::ClearInterleaved(int chunk_size) { | 
| ResizeBuffersIfNecessary(chunk_size); | 
| -  memset(interleaved_.data(), 0, static_cast<size_t>(chunk_size) * | 
| -                                     kNumOutputChannels * | 
| -                                     BytesPerOutputFormatSample()); | 
| +  memset(interleaved_.data(), 0, | 
| +         static_cast<size_t>(chunk_size) * channels_ * | 
| +             BytesPerOutputFormatSample()); | 
| } | 
|  | 
| void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) { | 
| if (!mixed_ || mixed_->frames() < chunk_size) { | 
| -    mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); | 
| +    mixed_ = ::media::AudioBus::Create(channels_, chunk_size); | 
| } | 
| if (!temp_ || temp_->frames() < chunk_size) { | 
| -    temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); | 
| +    temp_ = ::media::AudioBus::Create(channels_, chunk_size); | 
| } | 
|  | 
| -  size_t interleaved_size = static_cast<size_t>(chunk_size) * | 
| -                            kNumOutputChannels * BytesPerOutputFormatSample(); | 
| +  size_t interleaved_size = static_cast<size_t>(chunk_size) * channels_ * | 
| +                            BytesPerOutputFormatSample(); | 
|  | 
| if (interleaved_.size() < interleaved_size) { | 
| interleaved_.resize(interleaved_size); | 
| @@ -110,7 +107,7 @@ void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) { | 
| } | 
|  | 
| int FilterGroup::BytesPerOutputFormatSample() { | 
| -  return ::media::SampleFormatToBytesPerChannel(sample_format_); | 
| +  return sizeof(int32_t); | 
| } | 
|  | 
| void FilterGroup::ClearActiveInputs() { | 
|  |