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

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: Suffix governor with _1.0 Created 3 years, 8 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 "base/values.h"
9 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline.h"
6 #include "media/base/audio_bus.h" 10 #include "media/base/audio_bus.h"
7 11
8 namespace chromecast { 12 namespace chromecast {
9 namespace media { 13 namespace media {
10 14
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, 15 FilterGroup::FilterGroup(const std::unordered_set<std::string>& input_types,
20 AudioFilterFactory::FilterType filter_type, 16 AudioContentType content_type,
21 AudioContentType content_type) 17 int channels,
18 const base::ListValue* filter_list)
22 : input_types_(input_types), 19 : input_types_(input_types),
23 content_type_(content_type), 20 content_type_(content_type),
21 channels_(channels),
24 output_samples_per_second_(0), 22 output_samples_per_second_(0),
25 sample_format_(::media::SampleFormat::kUnknownSampleFormat), 23 post_processing_pipeline_(
26 audio_filter_(AudioFilterFactory::MakeAudioFilter(filter_type)), 24 base::MakeUnique<PostProcessingPipeline>(filter_list, channels_)) {}
27 silence_frames_filtered_(0) {}
28 25
29 FilterGroup::~FilterGroup() = default; 26 FilterGroup::~FilterGroup() = default;
30 27
31 void FilterGroup::Initialize(int output_samples_per_second, 28 void FilterGroup::Initialize(int output_samples_per_second) {
32 ::media::SampleFormat format) {
33 output_samples_per_second_ = output_samples_per_second; 29 output_samples_per_second_ = output_samples_per_second;
34 sample_format_ = format; 30 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 } 31 }
41 32
42 bool FilterGroup::CanProcessInput(StreamMixerAlsa::InputQueue* input) { 33 bool FilterGroup::CanProcessInput(StreamMixerAlsa::InputQueue* input) {
43 return !(input_types_.find(input->device_id()) == input_types_.end()); 34 return !(input_types_.find(input->device_id()) == input_types_.end());
44 } 35 }
45 36
46 void FilterGroup::AddActiveInput(StreamMixerAlsa::InputQueue* input) { 37 void FilterGroup::AddActiveInput(StreamMixerAlsa::InputQueue* input) {
47 active_inputs_.push_back(input); 38 active_inputs_.push_back(input);
48 } 39 }
49 40
50 std::vector<uint8_t>* FilterGroup::GetInterleaved() { 41 std::vector<uint8_t>* FilterGroup::GetInterleaved() {
51 return &interleaved_; 42 return &interleaved_;
52 } 43 }
53 44
54 bool FilterGroup::MixAndFilter(int chunk_size) { 45 bool FilterGroup::MixAndFilter(int chunk_size) {
55 DCHECK_NE(output_samples_per_second_, 0); 46 DCHECK_NE(output_samples_per_second_, 0);
56 DCHECK_NE(sample_format_, ::media::SampleFormat::kUnknownSampleFormat); 47 if (active_inputs_.empty() && !post_processing_pipeline_->IsRinging()) {
57 if (active_inputs_.empty()) { 48 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 } 49 }
68 50
69 ResizeBuffersIfNecessary(chunk_size); 51 ResizeBuffersIfNecessary(chunk_size);
70 52
71 mixed_->ZeroFramesPartial(0, chunk_size); 53 mixed_->ZeroFramesPartial(0, chunk_size);
72 for (StreamMixerAlsa::InputQueue* input : active_inputs_) { 54 for (StreamMixerAlsa::InputQueue* input : active_inputs_) {
73 input->GetResampledData(temp_.get(), chunk_size); 55 input->GetResampledData(temp_.get(), chunk_size);
74 for (int c = 0; c < kNumOutputChannels; ++c) { 56 for (int c = 0; c < channels_; ++c) {
75 input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size, 57 input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size,
76 mixed_->channel(c)); 58 mixed_->channel(c));
77 } 59 }
78 } 60 }
79 61
80 mixed_->ToInterleaved(chunk_size, BytesPerOutputFormatSample(), 62 mixed_->ToInterleaved(chunk_size, BytesPerOutputFormatSample(),
81 interleaved_.data()); 63 interleaved_.data());
82 if (audio_filter_) { 64 post_processing_pipeline_->ProcessFrames(interleaved_.data(), chunk_size,
83 audio_filter_->ProcessInterleaved(interleaved_.data(), chunk_size, volume_); 65 volume_, active_inputs_.empty());
84 }
85 66
86 return true; 67 return true;
87 } 68 }
88 69
89 void FilterGroup::ClearInterleaved(int chunk_size) { 70 void FilterGroup::ClearInterleaved(int chunk_size) {
90 ResizeBuffersIfNecessary(chunk_size); 71 ResizeBuffersIfNecessary(chunk_size);
91 memset(interleaved_.data(), 0, static_cast<size_t>(chunk_size) * 72 memset(interleaved_.data(), 0,
92 kNumOutputChannels * 73 static_cast<size_t>(chunk_size) * channels_ *
93 BytesPerOutputFormatSample()); 74 BytesPerOutputFormatSample());
94 } 75 }
95 76
96 void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) { 77 void FilterGroup::ResizeBuffersIfNecessary(int chunk_size) {
97 if (!mixed_ || mixed_->frames() < chunk_size) { 78 if (!mixed_ || mixed_->frames() < chunk_size) {
98 mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); 79 mixed_ = ::media::AudioBus::Create(channels_, chunk_size);
99 } 80 }
100 if (!temp_ || temp_->frames() < chunk_size) { 81 if (!temp_ || temp_->frames() < chunk_size) {
101 temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); 82 temp_ = ::media::AudioBus::Create(channels_, chunk_size);
102 } 83 }
103 84
104 size_t interleaved_size = static_cast<size_t>(chunk_size) * 85 size_t interleaved_size = static_cast<size_t>(chunk_size) * channels_ *
105 kNumOutputChannels * BytesPerOutputFormatSample(); 86 BytesPerOutputFormatSample();
106 87
107 if (interleaved_.size() < interleaved_size) { 88 if (interleaved_.size() < interleaved_size) {
108 interleaved_.resize(interleaved_size); 89 interleaved_.resize(interleaved_size);
109 } 90 }
110 } 91 }
111 92
112 int FilterGroup::BytesPerOutputFormatSample() { 93 int FilterGroup::BytesPerOutputFormatSample() {
113 return ::media::SampleFormatToBytesPerChannel(sample_format_); 94 return sizeof(int32_t);
114 } 95 }
115 96
116 void FilterGroup::ClearActiveInputs() { 97 void FilterGroup::ClearActiveInputs() {
117 active_inputs_.clear(); 98 active_inputs_.clear();
118 } 99 }
119 100
120 } // namespace media 101 } // namespace media
121 } // namespace chromecast 102 } // namespace chromecast
OLDNEW
« no previous file with comments | « chromecast/media/cma/backend/alsa/filter_group.h ('k') | chromecast/media/cma/backend/alsa/post_processing_pipeline.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698