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

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

Issue 2958393002: Add a simple, safe gain PostProcessor. (Closed)
Patch Set: Move cast_audio.json filepath string to a separate file Created 3 years, 5 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/public/volume_control.h" 5 #include "chromecast/public/volume_control.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 #include <map> 9 #include <map>
10 #include <memory> 10 #include <memory>
(...skipping 14 matching lines...) Expand all
25 #include "base/synchronization/lock.h" 25 #include "base/synchronization/lock.h"
26 #include "base/synchronization/waitable_event.h" 26 #include "base/synchronization/waitable_event.h"
27 #include "base/threading/thread.h" 27 #include "base/threading/thread.h"
28 #include "base/values.h" 28 #include "base/values.h"
29 #include "chromecast/base/init_command_line_shlib.h" 29 #include "chromecast/base/init_command_line_shlib.h"
30 #include "chromecast/base/serializers.h" 30 #include "chromecast/base/serializers.h"
31 #include "chromecast/media/cma/backend/alsa/alsa_features.h" 31 #include "chromecast/media/cma/backend/alsa/alsa_features.h"
32 #include "chromecast/media/cma/backend/alsa/alsa_volume_control.h" 32 #include "chromecast/media/cma/backend/alsa/alsa_volume_control.h"
33 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline_parser.h" 33 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline_parser.h"
34 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h" 34 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h"
35 #include "chromecast/media/cma/backend/alsa/volume_map.h"
35 36
36 namespace chromecast { 37 namespace chromecast {
37 namespace media { 38 namespace media {
38 39
39 namespace { 40 namespace {
40 41
41 constexpr float kDefaultMediaDbFS = -25.0f; 42 constexpr float kDefaultMediaDbFS = -25.0f;
42 constexpr float kDefaultAlarmDbFS = -20.0f; 43 constexpr float kDefaultAlarmDbFS = -20.0f;
43 constexpr float kDefaultCommunicationDbFS = -25.0f; 44 constexpr float kDefaultCommunicationDbFS = -25.0f;
44 45
45 constexpr float kMinDbFS = -120.0f; 46 constexpr float kMinDbFS = -120.0f;
46 47
47 constexpr char kKeyMediaDbFS[] = "dbfs.media"; 48 constexpr char kKeyMediaDbFS[] = "dbfs.media";
48 constexpr char kKeyAlarmDbFS[] = "dbfs.alarm"; 49 constexpr char kKeyAlarmDbFS[] = "dbfs.alarm";
49 constexpr char kKeyCommunicationDbFS[] = "dbfs.communication"; 50 constexpr char kKeyCommunicationDbFS[] = "dbfs.communication";
50 constexpr char kKeyVolumeMap[] = "volume_map";
51 constexpr char kKeyLevel[] = "level";
52 constexpr char kKeyDb[] = "db";
53
54 struct LevelToDb {
55 float level;
56 float db;
57 };
58
59 const LevelToDb kDefaultVolumeMap[] = {{0.0f, kMinDbFS},
60 {0.01f, -58.0f},
61 {0.090909f, -48.0f},
62 {0.818182f, -8.0f},
63 {1.0f, 0.0f}};
64 51
65 float DbFsToScale(float db) { 52 float DbFsToScale(float db) {
66 if (db <= kMinDbFS) { 53 if (db <= kMinDbFS) {
67 return 0.0f; 54 return 0.0f;
68 } 55 }
69 return std::pow(10, db / 20); 56 return std::pow(10, db / 20);
70 } 57 }
71 58
72 std::string ContentTypeToDbFSKey(AudioContentType type) { 59 std::string ContentTypeToDbFSKey(AudioContentType type) {
73 switch (type) { 60 switch (type) {
74 case AudioContentType::kAlarm: 61 case AudioContentType::kAlarm:
75 return kKeyAlarmDbFS; 62 return kKeyAlarmDbFS;
76 case AudioContentType::kCommunication: 63 case AudioContentType::kCommunication:
77 return kKeyCommunicationDbFS; 64 return kKeyCommunicationDbFS;
78 default: 65 default:
79 return kKeyMediaDbFS; 66 return kKeyMediaDbFS;
80 } 67 }
81 } 68 }
82 69
83 class VolumeMap {
84 public:
85 VolumeMap() {
86 auto cast_audio_config = DeserializeJsonFromFile(
87 base::FilePath(PostProcessingPipelineParser::GetFilePath()));
88 const base::DictionaryValue* cast_audio_dict;
89 if (!cast_audio_config ||
90 !cast_audio_config->GetAsDictionary(&cast_audio_dict)) {
91 LOG(WARNING) << "No cast audio config found; using default volume map.";
92 volume_map_.insert(volume_map_.end(), kDefaultVolumeMap,
93 kDefaultVolumeMap + arraysize(kDefaultVolumeMap));
94 return;
95 }
96
97 const base::ListValue* volume_map_list;
98 if (!cast_audio_dict->GetList(kKeyVolumeMap, &volume_map_list)) {
99 LOG(WARNING) << "No volume map found; using default volume map.";
100 volume_map_.insert(volume_map_.end(), kDefaultVolumeMap,
101 kDefaultVolumeMap + arraysize(kDefaultVolumeMap));
102 return;
103 }
104
105 double prev_level = -1.0;
106 for (size_t i = 0; i < volume_map_list->GetSize(); ++i) {
107 const base::DictionaryValue* volume_map_entry;
108 CHECK(volume_map_list->GetDictionary(i, &volume_map_entry));
109
110 double level;
111 CHECK(volume_map_entry->GetDouble(kKeyLevel, &level));
112 CHECK_GE(level, 0.0);
113 CHECK_LE(level, 1.0);
114 CHECK_GT(level, prev_level);
115 prev_level = level;
116
117 double db;
118 CHECK(volume_map_entry->GetDouble(kKeyDb, &db));
119 CHECK_LE(db, 0.0);
120 if (level == 1.0) {
121 CHECK_EQ(db, 0.0);
122 }
123
124 volume_map_.push_back({level, db});
125 }
126
127 if (volume_map_.empty()) {
128 LOG(FATAL) << "No entries in volume map.";
129 return;
130 }
131
132 if (volume_map_[0].level > 0.0) {
133 volume_map_.insert(volume_map_.begin(), {0.0, kMinDbFS});
134 }
135
136 if (volume_map_.rbegin()->level < 1.0) {
137 volume_map_.push_back({1.0, 0.0});
138 }
139 }
140
141 float VolumeToDbFS(float volume) {
142 if (volume <= volume_map_[0].level) {
143 return volume_map_[0].db;
144 }
145 for (size_t i = 1; i < volume_map_.size(); ++i) {
146 if (volume < volume_map_[i].level) {
147 const float x_range = volume_map_[i].level - volume_map_[i - 1].level;
148 const float y_range = volume_map_[i].db - volume_map_[i - 1].db;
149 const float x_pos = volume - volume_map_[i - 1].level;
150
151 return volume_map_[i - 1].db + x_pos * y_range / x_range;
152 }
153 }
154 return volume_map_[volume_map_.size() - 1].db;
155 }
156
157 // static
158 float DbFSToVolume(float db) {
159 if (db <= volume_map_[0].db) {
160 return volume_map_[0].level;
161 }
162 for (size_t i = 1; i < volume_map_.size(); ++i) {
163 if (db < volume_map_[i].db) {
164 const float x_range = volume_map_[i].db - volume_map_[i - 1].db;
165 const float y_range = volume_map_[i].level - volume_map_[i - 1].level;
166 const float x_pos = db - volume_map_[i - 1].db;
167
168 return volume_map_[i - 1].level + x_pos * y_range / x_range;
169 }
170 }
171 return volume_map_[volume_map_.size() - 1].level;
172 }
173
174 private:
175 std::vector<LevelToDb> volume_map_;
176
177 DISALLOW_COPY_AND_ASSIGN(VolumeMap);
178 };
179
180 base::LazyInstance<VolumeMap>::Leaky g_volume_map = LAZY_INSTANCE_INITIALIZER; 70 base::LazyInstance<VolumeMap>::Leaky g_volume_map = LAZY_INSTANCE_INITIALIZER;
181 71
182 class VolumeControlInternal : public AlsaVolumeControl::Delegate { 72 class VolumeControlInternal : public AlsaVolumeControl::Delegate {
183 public: 73 public:
184 VolumeControlInternal() 74 VolumeControlInternal()
185 : thread_("VolumeControl"), 75 : thread_("VolumeControl"),
186 initialize_complete_event_( 76 initialize_complete_event_(
187 base::WaitableEvent::ResetPolicy::MANUAL, 77 base::WaitableEvent::ResetPolicy::MANUAL,
188 base::WaitableEvent::InitialState::NOT_SIGNALED) { 78 base::WaitableEvent::InitialState::NOT_SIGNALED) {
189 // Load volume map to check that the config file is correct. 79 // Load volume map to check that the config file is correct.
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 return g_volume_map.Get().VolumeToDbFS(volume); 335 return g_volume_map.Get().VolumeToDbFS(volume);
446 } 336 }
447 337
448 // static 338 // static
449 float VolumeControl::DbFSToVolume(float db) { 339 float VolumeControl::DbFSToVolume(float db) {
450 return g_volume_map.Get().DbFSToVolume(db); 340 return g_volume_map.Get().DbFSToVolume(db);
451 } 341 }
452 342
453 } // namespace media 343 } // namespace media
454 } // namespace chromecast 344 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698