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..b79249000df2beaeb83a045f517d94eabaf944d1 |
--- /dev/null |
+++ b/chromecast/media/cma/backend/alsa/filter_group.cc |
@@ -0,0 +1,116 @@ |
+// 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), |
+ output_samples_per_second_(0), |
+ sample_format_(::media::SampleFormat::kUnknownSampleFormat), |
+ audio_filter_(AudioFilterFactory::MakeAudioFilter(filter_type)), |
+ silence_frames_filtered_(0) {} |
+ |
+void FilterGroup::Initialize(int output_samples_per_second, |
+ ::media::SampleFormat format) { |
+ output_samples_per_second_ = output_samples_per_second; |
+ sample_format_ = format; |
+ audio_filter_->SetSampleRateAndFormat(output_samples_per_second_, |
+ sample_format_); |
+ silence_frames_filtered_ = 0; |
+} |
+ |
+bool FilterGroup::CanProcessInput(StreamMixerAlsa::InputQueue* input) { |
+ if (input_types_.find(input->device_id()) == input_types_.end()) { |
+ return false; |
+ } |
+ active_inputs_.push_back(input); |
kmackay
2017/02/24 18:03:55
Don't add to active_inputs_ here
bshaya
2017/02/27 17:00:14
Done.
|
+ return true; |
+} |
+ |
+void FilterGroup::AddActiveInput(StreamMixerAlsa::InputQueue* input) { |
+ active_inputs_.push_back(input); |
+} |
+ |
+std::vector<uint8_t>* FilterGroup::GetInterleaved() { |
+ return &interleaved_; |
+} |
+ |
+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 (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, BytesPerOutputFormatSample(), |
+ 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 * |
+ BytesPerOutputFormatSample()); |
+} |
+ |
+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 * BytesPerOutputFormatSample(); |
+ |
+ if (interleaved_.size() < interleaved_size) { |
+ interleaved_.resize(interleaved_size); |
+ } |
+} |
+ |
+int FilterGroup::BytesPerOutputFormatSample() { |
+ return ::media::SampleFormatToBytesPerChannel(sample_format_); |
+} |
+ |
+} // namespace media |
+} // namespace chromecast |