Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(490)

Side by Side Diff: chromecast/media/cma/backend/alsa/filter_group.cc

Issue 2771143002: Implement runtime audio post-processing pipeline. See go/cast_audio.json (Closed)
Patch Set: Remove unordered_map of libraries. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chromecast/media/cma/backend/alsa/filter_group.h" 5 #include "chromecast/media/cma/backend/alsa/filter_group.h"
6
7 #include "base/memory/ptr_util.h"
8 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline.h"
6 #include "media/base/audio_bus.h" 9 #include "media/base/audio_bus.h"
7 10
8 namespace chromecast { 11 namespace chromecast {
9 namespace media { 12 namespace media {
10 13
11 namespace {
12
13 // How many seconds of silence should be passed to the filters to flush them.
14 const float kSilenceSecondsToFilter = 1.0f;
15 const int kNumOutputChannels = 2;
16
17 } // namespace
18
19 FilterGroup::FilterGroup(const std::unordered_set<std::string>& input_types, 14 FilterGroup::FilterGroup(const std::unordered_set<std::string>& input_types,
20 AudioFilterFactory::FilterType filter_type, 15 AudioContentType content_type,
21 AudioContentType content_type) 16 int channels,
17 const base::ListValue* filter_list)
22 : input_types_(input_types), 18 : input_types_(input_types),
23 content_type_(content_type), 19 content_type_(content_type),
20 channels_(channels),
24 output_samples_per_second_(0), 21 output_samples_per_second_(0),
25 sample_format_(::media::SampleFormat::kUnknownSampleFormat), 22 post_processing_pipeline_(
26 audio_filter_(AudioFilterFactory::MakeAudioFilter(filter_type)), 23 base::MakeUnique<PostProcessingPipeline>(filter_list, channels_)) {}
27 silence_frames_filtered_(0) {}
28 24
29 FilterGroup::~FilterGroup() = default; 25 FilterGroup::~FilterGroup() = default;
30 26
31 void FilterGroup::Initialize(int output_samples_per_second, 27 void FilterGroup::Initialize(int output_samples_per_second) {
32 ::media::SampleFormat format) {
33 output_samples_per_second_ = output_samples_per_second; 28 output_samples_per_second_ = output_samples_per_second;
34 sample_format_ = format; 29 post_processing_pipeline_->SetSampleRate(output_samples_per_second);
35 if (audio_filter_) {
36 audio_filter_->SetSampleRateAndFormat(output_samples_per_second_,
37 sample_format_);
38 }
39 silence_frames_filtered_ = 0;
40 } 30 }
41 31
42 bool FilterGroup::CanProcessInput(StreamMixerAlsa::InputQueue* input) { 32 bool FilterGroup::CanProcessInput(StreamMixerAlsa::InputQueue* input) {
43 return !(input_types_.find(input->device_id()) == input_types_.end()); 33 return !(input_types_.find(input->device_id()) == input_types_.end());
44 } 34 }
45 35
46 void FilterGroup::AddActiveInput(StreamMixerAlsa::InputQueue* input) { 36 void FilterGroup::AddActiveInput(StreamMixerAlsa::InputQueue* input) {
47 active_inputs_.push_back(input); 37 active_inputs_.push_back(input);
48 } 38 }
49 39
50 std::vector<uint8_t>* FilterGroup::GetInterleaved() { 40 std::vector<uint8_t>* FilterGroup::GetInterleaved() {
51 return &interleaved_; 41 return &interleaved_;
52 } 42 }
53 43
54 bool FilterGroup::MixAndFilter(int chunk_size) { 44 bool FilterGroup::MixAndFilter(int chunk_size) {
55 DCHECK_NE(output_samples_per_second_, 0); 45 DCHECK_NE(output_samples_per_second_, 0);
56 DCHECK_NE(sample_format_, ::media::SampleFormat::kUnknownSampleFormat); 46 if (active_inputs_.empty() && !post_processing_pipeline_->IsRinging()) {
57 if (active_inputs_.empty()) { 47 return false; // Output will be silence, no need to mix.
58 int silence_frames_to_filter =
59 output_samples_per_second_ * kSilenceSecondsToFilter;
60 if (audio_filter_ && silence_frames_filtered_ < silence_frames_to_filter) {
61 silence_frames_filtered_ += chunk_size;
62 } else {
63 return false; // Output will be silence, no need to mix.
64 }
65 } else {
66 silence_frames_filtered_ = 0;
67 } 48 }
68 49
69 ResizeBuffersIfNecessary(chunk_size); 50 ResizeBuffersIfNecessary(chunk_size);
70 51
71 mixed_->ZeroFramesPartial(0, chunk_size); 52 mixed_->ZeroFramesPartial(0, chunk_size);
72 for (StreamMixerAlsa::InputQueue* input : active_inputs_) { 53 for (StreamMixerAlsa::InputQueue* input : active_inputs_) {
73 input->GetResampledData(temp_.get(), chunk_size); 54 input->GetResampledData(temp_.get(), chunk_size);
74 for (int c = 0; c < kNumOutputChannels; ++c) { 55 for (int c = 0; c < channels_; ++c) {
75 input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size, 56 input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size,
76 mixed_->channel(c)); 57 mixed_->channel(c));
77 } 58 }
78 } 59 }
79 60
80 mixed_->ToInterleaved(chunk_size, BytesPerOutputFormatSample(), 61 mixed_->ToInterleaved(chunk_size, BytesPerOutputFormatSample(),
81 interleaved_.data()); 62 interleaved_.data());
82 if (audio_filter_) { 63 post_processing_pipeline_->ProcessFrames(interleaved_.data(), chunk_size,
kmackay 2017/03/24 22:15:54 Don't we need to use the return value of ProcessFr
bshaya 2017/03/24 22:55:49 Added TODO, will add in separate CL.
83 audio_filter_->ProcessInterleaved(interleaved_.data(), chunk_size, volume_); 64 volume_, active_inputs_.empty());
84 }
85 65
86 return true; 66 return true;
87 } 67 }
88 68
89 void FilterGroup::ClearInterleaved(int chunk_size) { 69 void FilterGroup::ClearInterleaved(int chunk_size) {
90 ResizeBuffersIfNecessary(chunk_size); 70 ResizeBuffersIfNecessary(chunk_size);
91 memset(interleaved_.data(), 0, static_cast<size_t>(chunk_size) * 71 memset(interleaved_.data(), 0,
92 kNumOutputChannels * 72 static_cast<size_t>(chunk_size) * channels_ *
93 BytesPerOutputFormatSample()); 73 BytesPerOutputFormatSample());
94 } 74 }
95 75
96 void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) { 76 void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) {
97 if (!mixed_ || mixed_->frames() < chunk_size) { 77 if (!mixed_ || mixed_->frames() < chunk_size) {
98 mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); 78 mixed_ = ::media::AudioBus::Create(channels_, chunk_size);
99 } 79 }
100 if (!temp_ || temp_->frames() < chunk_size) { 80 if (!temp_ || temp_->frames() < chunk_size) {
101 temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); 81 temp_ = ::media::AudioBus::Create(channels_, chunk_size);
102 } 82 }
103 83
104 size_t interleaved_size = static_cast<size_t>(chunk_size) * 84 size_t interleaved_size = static_cast<size_t>(chunk_size) * channels_ *
105 kNumOutputChannels * BytesPerOutputFormatSample(); 85 BytesPerOutputFormatSample();
106 86
107 if (interleaved_.size() < interleaved_size) { 87 if (interleaved_.size() < interleaved_size) {
108 interleaved_.resize(interleaved_size); 88 interleaved_.resize(interleaved_size);
109 } 89 }
110 } 90 }
111 91
112 int FilterGroup::BytesPerOutputFormatSample() { 92 int FilterGroup::BytesPerOutputFormatSample() {
113 return ::media::SampleFormatToBytesPerChannel(sample_format_); 93 return sizeof(int32_t);
114 } 94 }
115 95
116 void FilterGroup::ClearActiveInputs() { 96 void FilterGroup::ClearActiveInputs() {
117 active_inputs_.clear(); 97 active_inputs_.clear();
118 } 98 }
119 99
120 } // namespace media 100 } // namespace media
121 } // namespace chromecast 101 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698