| 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
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5d1d89d634986d891421185d12d1c3135be559c4
|
| --- /dev/null
|
| +++ b/chromecast/media/cma/backend/alsa/filter_group.cc
|
| @@ -0,0 +1,105 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chromecast/media/cma/backend/alsa/filter_group.h"
|
| +#include "media/base/audio_bus.h"
|
| +
|
| +namespace chromecast {
|
| +namespace media {
|
| +
|
| +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)
|
| + : input_types_(input_types),
|
| + audio_filter_(AudioFilterFactory::MakeAudioFilter(filter_type)) {}
|
| +
|
| +void FilterGroup::Initialize(int output_samples_per_second,
|
| + ::media::SampleFormat format,
|
| + ssize_t bytes_per_output_format_sample) {
|
| + output_samples_per_second_ = output_samples_per_second;
|
| + sample_format_ = format;
|
| + bytes_per_output_format_sample_ = bytes_per_output_format_sample;
|
| + audio_filter_->SetSampleRateAndFormat(output_samples_per_second_,
|
| + sample_format_);
|
| +}
|
| +
|
| +bool FilterGroup::TryAddActiveInput(StreamMixerAlsa::InputQueue* input) {
|
| + if (input_types_.find(input->name()) == input_types_.end()) {
|
| + return false;
|
| + }
|
| + active_inputs_.push_back(input);
|
| + return true;
|
| +}
|
| +
|
| +std::vector<uint8_t>* FilterGroup::GetInterleaved() {
|
| + return &interleaved_;
|
| +}
|
| +
|
| +bool FilterGroup::MixAndFilter(int chunk_size) {
|
| + if (active_inputs_.empty()) {
|
| + int silence_frames_to_filter =
|
| + output_samples_per_second_ * kSilenceSecondsToFilter;
|
| + if (silence_frames_filtered_ < silence_frames_to_filter) {
|
| + silence_frames_filtered_ += chunk_size;
|
| + } else {
|
| + return false; // Output will be silence, no need to mix.
|
| + }
|
| + } else {
|
| + silence_frames_filtered_ = 0;
|
| + }
|
| +
|
| + ResizeBuffersIfNecessary(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) {
|
| + input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size,
|
| + mixed_->channel(c));
|
| + }
|
| + }
|
| +
|
| + active_inputs_.clear();
|
| + mixed_->ToInterleaved(chunk_size, bytes_per_output_format_sample_,
|
| + interleaved_.data());
|
| + if (audio_filter_) {
|
| + audio_filter_->ProcessInterleaved(interleaved_.data(), chunk_size);
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void FilterGroup::ClearInterleaved(int chunk_size) {
|
| + ResizeBuffersIfNecessary(chunk_size);
|
| + memset(interleaved_.data(), 0, static_cast<size_t>(chunk_size) *
|
| + kNumOutputChannels *
|
| + bytes_per_output_format_sample_);
|
| +}
|
| +
|
| +void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) {
|
| + if (!mixed_ || mixed_->frames() < chunk_size) {
|
| + mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
|
| + }
|
| + if (!temp_ || temp_->frames() < chunk_size) {
|
| + temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
|
| + }
|
| +
|
| + size_t interleaved_size = static_cast<size_t>(chunk_size) *
|
| + kNumOutputChannels *
|
| + bytes_per_output_format_sample_;
|
| +
|
| + if (interleaved_.size() < interleaved_size) {
|
| + interleaved_.resize(interleaved_size);
|
| + }
|
| +}
|
| +
|
| +} // namespace media
|
| +} // namespace chromecast
|
|
|