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

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

Issue 2738873002: [Chromecast] Implement new volume control API (Closed)
Patch Set: no need for ALSA volume control 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/stream_mixer_alsa.h" 5 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 #include <limits> 9 #include <limits>
10 #include <unordered_set> 10 #include <unordered_set>
11 #include <utility> 11 #include <utility>
12 12
13 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
14 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
16 #include "base/memory/ptr_util.h" 16 #include "base/memory/ptr_util.h"
17 #include "base/memory/weak_ptr.h" 17 #include "base/memory/weak_ptr.h"
18 #include "base/numerics/saturated_arithmetic.h" 18 #include "base/numerics/saturated_arithmetic.h"
19 #include "base/single_thread_task_runner.h" 19 #include "base/single_thread_task_runner.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/threading/platform_thread.h" 20 #include "base/threading/platform_thread.h"
22 #include "base/threading/thread_task_runner_handle.h" 21 #include "base/threading/thread_task_runner_handle.h"
23 #include "chromecast/base/chromecast_switches.h" 22 #include "chromecast/base/chromecast_switches.h"
24 #include "chromecast/media/base/audio_device_ids.h" 23 #include "chromecast/media/base/audio_device_ids.h"
25 #include "chromecast/media/cma/backend/alsa/alsa_wrapper.h" 24 #include "chromecast/media/cma/backend/alsa/alsa_wrapper.h"
26 #include "chromecast/media/cma/backend/alsa/audio_filter_factory.h" 25 #include "chromecast/media/cma/backend/alsa/audio_filter_factory.h"
27 #include "chromecast/media/cma/backend/alsa/filter_group.h" 26 #include "chromecast/media/cma/backend/alsa/filter_group.h"
28 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h" 27 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h"
29 #include "media/audio/audio_device_description.h" 28 #include "media/audio/audio_device_description.h"
30 #include "media/base/audio_bus.h" 29 #include "media/base/audio_bus.h"
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 SND_PCM_FORMAT_S16}; 118 SND_PCM_FORMAT_S16};
120 119
121 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); 120 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min();
122 121
123 int64_t TimespecToMicroseconds(struct timespec time) { 122 int64_t TimespecToMicroseconds(struct timespec time) {
124 return static_cast<int64_t>(time.tv_sec) * 123 return static_cast<int64_t>(time.tv_sec) *
125 base::Time::kMicrosecondsPerSecond + 124 base::Time::kMicrosecondsPerSecond +
126 time.tv_nsec / 1000; 125 time.tv_nsec / 1000;
127 } 126 }
128 127
129 bool GetSwitchValueAsInt(const std::string& switch_name,
130 int default_value,
131 int* value) {
132 DCHECK(value);
133 *value = default_value;
134 if (!base::CommandLine::InitializedForCurrentProcess()) {
135 LOG(WARNING) << "No CommandLine for current process.";
136 return false;
137 }
138 const base::CommandLine* command_line =
139 base::CommandLine::ForCurrentProcess();
140 if (!command_line->HasSwitch(switch_name)) {
141 return false;
142 }
143
144 int arg_value;
145 if (!base::StringToInt(command_line->GetSwitchValueASCII(switch_name),
146 &arg_value)) {
147 LOG(DFATAL) << "--" << switch_name << " only accepts integers as arguments";
148 return false;
149 }
150 *value = arg_value;
151 return true;
152 }
153
154 bool GetSwitchValueAsNonNegativeInt(const std::string& switch_name,
155 int default_value,
156 int* value) {
157 DCHECK_GE(default_value, 0) << "--" << switch_name
158 << " must have a non-negative default value";
159 DCHECK(value);
160
161 if (!GetSwitchValueAsInt(switch_name, default_value, value)) {
162 return false;
163 }
164
165 if (*value < 0) {
166 LOG(DFATAL) << "--" << switch_name << " must have a non-negative value";
167 *value = default_value;
168 return false;
169 }
170 return true;
171 }
172
173 void VectorAccumulate(const int32_t* source, size_t size, int32_t* dest) { 128 void VectorAccumulate(const int32_t* source, size_t size, int32_t* dest) {
174 for (size_t i = 0; i < size; ++i) { 129 for (size_t i = 0; i < size; ++i) {
175 dest[i] = base::SaturatedAddition(source[i], dest[i]); 130 dest[i] = base::SaturatedAddition(source[i], dest[i]);
176 } 131 }
177 } 132 }
178 133
179 class StreamMixerAlsaInstance : public StreamMixerAlsa { 134 class StreamMixerAlsaInstance : public StreamMixerAlsa {
180 public: 135 public:
181 StreamMixerAlsaInstance() {} 136 StreamMixerAlsaInstance() {}
182 ~StreamMixerAlsaInstance() override {} 137 ~StreamMixerAlsaInstance() override {}
(...skipping 24 matching lines...) Expand all
207 StreamMixerAlsa::StreamMixerAlsa() 162 StreamMixerAlsa::StreamMixerAlsa()
208 : mixer_thread_(new base::Thread("ALSA CMA mixer thread")), 163 : mixer_thread_(new base::Thread("ALSA CMA mixer thread")),
209 mixer_task_runner_(nullptr), 164 mixer_task_runner_(nullptr),
210 requested_output_samples_per_second_(kInvalidSampleRate), 165 requested_output_samples_per_second_(kInvalidSampleRate),
211 output_samples_per_second_(kInvalidSampleRate), 166 output_samples_per_second_(kInvalidSampleRate),
212 pcm_(nullptr), 167 pcm_(nullptr),
213 pcm_hw_params_(nullptr), 168 pcm_hw_params_(nullptr),
214 pcm_status_(nullptr), 169 pcm_status_(nullptr),
215 pcm_format_(SND_PCM_FORMAT_UNKNOWN), 170 pcm_format_(SND_PCM_FORMAT_UNKNOWN),
216 alsa_buffer_size_(0), 171 alsa_buffer_size_(0),
217 alsa_period_explicitly_set(false),
218 alsa_period_size_(0), 172 alsa_period_size_(0),
219 alsa_start_threshold_(0), 173 alsa_start_threshold_(0),
220 alsa_avail_min_(0), 174 alsa_avail_min_(0),
221 state_(kStateUninitialized), 175 state_(kStateUninitialized),
222 retry_write_frames_timer_(new base::Timer(false, false)), 176 retry_write_frames_timer_(new base::Timer(false, false)),
223 check_close_timeout_(kDefaultCheckCloseTimeoutMs), 177 check_close_timeout_(kDefaultCheckCloseTimeoutMs),
224 check_close_timer_(new base::Timer(false, false)) { 178 check_close_timer_(new base::Timer(false, false)) {
179 for (auto type : {AudioContentType::kMedia, AudioContentType::kAlarm,
slan 2017/03/13 22:09:51 Perhaps we should use a static assert in here to m
kmackay 2017/03/14 00:20:59 Done.
180 AudioContentType::kCommunication}) {
181 volume_[type] = 1.0f;
182 volume_limit_[type] = 1.0f;
183 muted_[type] = false;
184 }
185
225 if (single_threaded_for_test_) { 186 if (single_threaded_for_test_) {
226 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 187 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get();
227 } else { 188 } else {
228 base::Thread::Options options; 189 base::Thread::Options options;
229 options.priority = base::ThreadPriority::REALTIME_AUDIO; 190 options.priority = base::ThreadPriority::REALTIME_AUDIO;
230 mixer_thread_->StartWithOptions(options); 191 mixer_thread_->StartWithOptions(options);
231 mixer_task_runner_ = mixer_thread_->task_runner(); 192 mixer_task_runner_ = mixer_thread_->task_runner();
232 } 193 }
233 194
234 alsa_device_name_ = kOutputDeviceDefaultName; 195 alsa_device_name_ = kOutputDeviceDefaultName;
235 if (base::CommandLine::InitializedForCurrentProcess() && 196 if (base::CommandLine::InitializedForCurrentProcess() &&
236 base::CommandLine::ForCurrentProcess()->HasSwitch( 197 base::CommandLine::ForCurrentProcess()->HasSwitch(
237 switches::kAlsaOutputDevice)) { 198 switches::kAlsaOutputDevice)) {
238 alsa_device_name_ = 199 alsa_device_name_ =
239 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 200 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
240 switches::kAlsaOutputDevice); 201 switches::kAlsaOutputDevice);
241 } 202 }
242 203
243 int fixed_samples_per_second; 204 int fixed_samples_per_second = GetSwitchValueNonNegativeInt(
244 GetSwitchValueAsNonNegativeInt(switches::kAlsaFixedOutputSampleRate, 205 switches::kAlsaFixedOutputSampleRate, kInvalidSampleRate);
245 kInvalidSampleRate, &fixed_samples_per_second);
246 if (fixed_samples_per_second != kInvalidSampleRate) { 206 if (fixed_samples_per_second != kInvalidSampleRate) {
247 LOG(INFO) << "Setting fixed sample rate to " << fixed_samples_per_second; 207 LOG(INFO) << "Setting fixed sample rate to " << fixed_samples_per_second;
248 } 208 }
249 209
250 fixed_output_samples_per_second_ = fixed_samples_per_second; 210 fixed_output_samples_per_second_ = fixed_samples_per_second;
251 211
252 low_sample_rate_cutoff_ = 212 low_sample_rate_cutoff_ =
253 chromecast::GetSwitchValueBoolean(switches::kAlsaEnableUpsampling, false) 213 chromecast::GetSwitchValueBoolean(switches::kAlsaEnableUpsampling, false)
254 ? kLowSampleRateCutoff 214 ? kLowSampleRateCutoff
255 : 0; 215 : 0;
256 216
257 // Create filter groups. 217 // Create filter groups.
258 // TODO(bshaya): Switch to filter groups based on AudioContentType. 218 // TODO(bshaya): Switch to filter groups based on AudioContentType.
259 filter_groups_.push_back(base::MakeUnique<FilterGroup>( 219 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
260 std::unordered_set<std::string>( 220 std::unordered_set<std::string>(
261 {::media::AudioDeviceDescription::kCommunicationsDeviceId}), 221 {::media::AudioDeviceDescription::kCommunicationsDeviceId}),
262 AudioFilterFactory::COMMUNICATION_AUDIO_FILTER)); 222 AudioFilterFactory::COMMUNICATION_AUDIO_FILTER,
223 AudioContentType::kMedia));
263 filter_groups_.push_back(base::MakeUnique<FilterGroup>( 224 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
264 std::unordered_set<std::string>({kAlarmAudioDeviceId}), 225 std::unordered_set<std::string>({kAlarmAudioDeviceId}),
265 AudioFilterFactory::ALARM_AUDIO_FILTER)); 226 AudioFilterFactory::ALARM_AUDIO_FILTER, AudioContentType::kAlarm));
266 filter_groups_.push_back(base::MakeUnique<FilterGroup>( 227 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
267 std::unordered_set<std::string>({kTtsAudioDeviceId}), 228 std::unordered_set<std::string>({kTtsAudioDeviceId}),
268 AudioFilterFactory::TTS_AUDIO_FILTER)); 229 AudioFilterFactory::TTS_AUDIO_FILTER, AudioContentType::kCommunication));
269 filter_groups_.push_back(base::MakeUnique<FilterGroup>( 230 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
270 std::unordered_set<std::string>( 231 std::unordered_set<std::string>(
271 {::media::AudioDeviceDescription::kDefaultDeviceId, 232 {::media::AudioDeviceDescription::kDefaultDeviceId,
272 kLocalAudioDeviceId, ""}), 233 kLocalAudioDeviceId, ""}),
273 AudioFilterFactory::MEDIA_AUDIO_FILTER)); 234 AudioFilterFactory::MEDIA_AUDIO_FILTER, AudioContentType::kMedia));
274 235
275 DefineAlsaParameters(); 236 DefineAlsaParameters();
276 } 237 }
277 238
278 void StreamMixerAlsa::ResetTaskRunnerForTest() { 239 void StreamMixerAlsa::ResetTaskRunnerForTest() {
279 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 240 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get();
280 } 241 }
281 242
282 void StreamMixerAlsa::DefineAlsaParameters() { 243 void StreamMixerAlsa::DefineAlsaParameters() {
283 // Get the ALSA output configuration from the command line. 244 // Get the ALSA output configuration from the command line.
284 int buffer_size; 245 alsa_buffer_size_ = GetSwitchValueNonNegativeInt(
285 GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputBufferSize, 246 switches::kAlsaOutputBufferSize, kDefaultOutputBufferSizeFrames);
286 kDefaultOutputBufferSizeFrames, &buffer_size);
287 alsa_buffer_size_ = buffer_size;
288 247
289 int period_size; 248 alsa_period_size_ = GetSwitchValueNonNegativeInt(
290 if (GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputPeriodSize, 249 switches::kAlsaOutputPeriodSize, alsa_buffer_size_ / 16);
291 alsa_buffer_size_ / 16, &period_size)) { 250 if (alsa_period_size_ >= alsa_buffer_size_) {
292 if (period_size >= buffer_size) { 251 LOG(DFATAL) << "ALSA period size must be smaller than the buffer size";
293 LOG(DFATAL) << "ALSA period size must be smaller than the buffer size"; 252 alsa_period_size_ = alsa_buffer_size_ / 2;
294 period_size = buffer_size / 2;
295 } else {
296 alsa_period_explicitly_set = true;
297 }
298 } 253 }
299 alsa_period_size_ = period_size;
300 254
301 int start_threshold; 255 alsa_start_threshold_ = GetSwitchValueNonNegativeInt(
302 GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputStartThreshold, 256 switches::kAlsaOutputStartThreshold,
303 (buffer_size / period_size) * period_size, 257 (alsa_buffer_size_ / alsa_period_size_) * alsa_period_size_);
304 &start_threshold); 258 if (alsa_start_threshold_ > alsa_buffer_size_) {
305 if (start_threshold > buffer_size) {
306 LOG(DFATAL) << "ALSA start threshold must be no larger than " 259 LOG(DFATAL) << "ALSA start threshold must be no larger than "
307 << "the buffer size"; 260 << "the buffer size";
308 start_threshold = (buffer_size / period_size) * period_size; 261 alsa_start_threshold_ =
262 (alsa_buffer_size_ / alsa_period_size_) * alsa_period_size_;
309 } 263 }
310 alsa_start_threshold_ = start_threshold;
311 264
312 // By default, allow the transfer when at least period_size samples can be 265 // By default, allow the transfer when at least period_size samples can be
313 // processed. 266 // processed.
314 int avail_min; 267 alsa_avail_min_ = GetSwitchValueNonNegativeInt(switches::kAlsaOutputAvailMin,
315 GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputAvailMin, period_size, 268 alsa_period_size_);
316 &avail_min); 269 if (alsa_avail_min_ > alsa_buffer_size_) {
317 if (avail_min > buffer_size) {
318 LOG(DFATAL) << "ALSA avail min must be no larger than the buffer size"; 270 LOG(DFATAL) << "ALSA avail min must be no larger than the buffer size";
319 avail_min = alsa_period_size_; 271 alsa_avail_min_ = alsa_period_size_;
320 } 272 }
321 alsa_avail_min_ = avail_min;
322 273
323 // --accept-resource-provider should imply a check close timeout of 0. 274 // --accept-resource-provider should imply a check close timeout of 0.
324 int default_close_timeout = chromecast::GetSwitchValueBoolean( 275 int default_close_timeout = chromecast::GetSwitchValueBoolean(
325 switches::kAcceptResourceProvider, false) 276 switches::kAcceptResourceProvider, false)
326 ? 0 277 ? 0
327 : kDefaultCheckCloseTimeoutMs; 278 : kDefaultCheckCloseTimeoutMs;
328 GetSwitchValueAsInt(switches::kAlsaCheckCloseTimeout, default_close_timeout, 279 check_close_timeout_ = GetSwitchValueInt(switches::kAlsaCheckCloseTimeout,
329 &check_close_timeout_); 280 default_close_timeout);
330 } 281 }
331 282
332 unsigned int StreamMixerAlsa::DetermineOutputRate(unsigned int requested_rate) { 283 unsigned int StreamMixerAlsa::DetermineOutputRate(unsigned int requested_rate) {
333 if (fixed_output_samples_per_second_ != kInvalidSampleRate) { 284 if (fixed_output_samples_per_second_ != kInvalidSampleRate) {
334 LOG(INFO) << "Requested output rate is " << requested_rate; 285 LOG(INFO) << "Requested output rate is " << requested_rate;
335 LOG(INFO) << "Cannot change rate since it is fixed to " 286 LOG(INFO) << "Cannot change rate since it is fixed to "
336 << fixed_output_samples_per_second_; 287 << fixed_output_samples_per_second_;
337 return fixed_output_samples_per_second_; 288 return fixed_output_samples_per_second_;
338 } 289 }
339 290
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 snd_pcm_uframes_t requested_buffer_size = alsa_buffer_size_; 386 snd_pcm_uframes_t requested_buffer_size = alsa_buffer_size_;
436 RETURN_ERROR_CODE(PcmHwParamsSetBufferSizeNear, pcm_, pcm_hw_params_, 387 RETURN_ERROR_CODE(PcmHwParamsSetBufferSizeNear, pcm_, pcm_hw_params_,
437 &alsa_buffer_size_); 388 &alsa_buffer_size_);
438 if (requested_buffer_size != alsa_buffer_size_) { 389 if (requested_buffer_size != alsa_buffer_size_) {
439 LOG(WARNING) << "Requested buffer size (" << requested_buffer_size 390 LOG(WARNING) << "Requested buffer size (" << requested_buffer_size
440 << " frames) does not match the actual buffer size (" 391 << " frames) does not match the actual buffer size ("
441 << alsa_buffer_size_ 392 << alsa_buffer_size_
442 << " frames). This may lead to an increase in " 393 << " frames). This may lead to an increase in "
443 "either audio latency or audio underruns."; 394 "either audio latency or audio underruns.";
444 395
445 // Always try to use the value for period_size that was passed in on the 396 if (alsa_period_size_ >= alsa_buffer_size_) {
446 // command line, if any.
447 if (!alsa_period_explicitly_set) {
448 alsa_period_size_ = alsa_buffer_size_ / 16;
449 } else if (alsa_period_size_ >= alsa_buffer_size_) {
450 snd_pcm_uframes_t new_period_size = alsa_buffer_size_ / 2; 397 snd_pcm_uframes_t new_period_size = alsa_buffer_size_ / 2;
451 LOG(DFATAL) << "Configured period size (" << alsa_period_size_ 398 LOG(DFATAL) << "Configured period size (" << alsa_period_size_
452 << ") is >= actual buffer size (" << alsa_buffer_size_ 399 << ") is >= actual buffer size (" << alsa_buffer_size_
453 << "); reducing to " << new_period_size; 400 << "); reducing to " << new_period_size;
454 alsa_period_size_ = new_period_size; 401 alsa_period_size_ = new_period_size;
455 } 402 }
456 // Scale the start threshold and avail_min based on the new buffer size. 403 // Scale the start threshold and avail_min based on the new buffer size.
457 float original_buffer_size = static_cast<float>(requested_buffer_size); 404 float original_buffer_size = static_cast<float>(requested_buffer_size);
458 float avail_min_ratio = original_buffer_size / alsa_avail_min_; 405 float avail_min_ratio = original_buffer_size / alsa_avail_min_;
459 alsa_avail_min_ = alsa_buffer_size_ / avail_min_ratio; 406 alsa_avail_min_ = alsa_buffer_size_ / avail_min_ratio;
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 DCHECK(input); 600 DCHECK(input);
654 601
655 // If the new input is a primary one, we may need to change the output 602 // If the new input is a primary one, we may need to change the output
656 // sample rate to match its input sample rate. 603 // sample rate to match its input sample rate.
657 // We only change the output rate if it is not set to a fixed value. 604 // We only change the output rate if it is not set to a fixed value.
658 if (input->primary() && 605 if (input->primary() &&
659 fixed_output_samples_per_second_ == kInvalidSampleRate) { 606 fixed_output_samples_per_second_ == kInvalidSampleRate) {
660 CheckChangeOutputRate(input->input_samples_per_second()); 607 CheckChangeOutputRate(input->input_samples_per_second());
661 } 608 }
662 609
610 auto type = input->content_type();
611 if (input->primary()) {
612 input->SetContentTypeVolume(std::min(volume_limit_[type], volume_[type]));
613 } else {
614 input->SetContentTypeVolume(volume_[type]);
615 }
616 input->SetMuted(muted_[type]);
617
663 check_close_timer_->Stop(); 618 check_close_timer_->Stop();
664 switch (state_) { 619 switch (state_) {
665 case kStateUninitialized: 620 case kStateUninitialized:
666 requested_output_samples_per_second_ = input->input_samples_per_second(); 621 requested_output_samples_per_second_ = input->input_samples_per_second();
667 Start(); 622 Start();
668 // Fallthrough intended 623 // Fallthrough intended
669 case kStateNormalPlayback: { 624 case kStateNormalPlayback: {
670 bool found_filter_group = false; 625 bool found_filter_group = false;
671 input->Initialize(rendering_delay_); 626 input->Initialize(rendering_delay_);
672 for (auto&& filter_group : filter_groups_) { 627 for (auto&& filter_group : filter_groups_) {
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 CastMediaShlib::LoopbackAudioObserver* observer) { 915 CastMediaShlib::LoopbackAudioObserver* observer) {
961 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::RemoveLoopbackAudioObserver, observer); 916 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::RemoveLoopbackAudioObserver, observer);
962 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(), 917 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(),
963 observer) != loopback_observers_.end()); 918 observer) != loopback_observers_.end());
964 loopback_observers_.erase(std::remove(loopback_observers_.begin(), 919 loopback_observers_.erase(std::remove(loopback_observers_.begin(),
965 loopback_observers_.end(), observer), 920 loopback_observers_.end(), observer),
966 loopback_observers_.end()); 921 loopback_observers_.end());
967 observer->OnRemoved(); 922 observer->OnRemoved();
968 } 923 }
969 924
925 void StreamMixerAlsa::SetVolume(AudioContentType type, float level) {
926 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::SetVolume, type, level);
927 volume_[type] = level;
928 float effective_volume = std::min(volume_limit_[type], level);
slan 2017/03/13 22:09:51 Regarding my earlier comment about using a VolumeC
kmackay 2017/03/14 00:20:59 Done.
929 for (auto&& input : inputs_) {
930 if (input->content_type() == type) {
931 if (input->primary()) {
932 input->SetContentTypeVolume(effective_volume);
933 } else {
934 // Volume limits don't apply to effects streams.
935 input->SetContentTypeVolume(level);
936 }
937 }
938 }
939
940 for (auto&& filter : filter_groups_) {
941 if (filter->content_type() == type) {
942 filter->set_volume(effective_volume);
943 }
944 }
945 }
946
947 void StreamMixerAlsa::SetMuted(AudioContentType type, bool muted) {
948 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::SetMuted, type, muted);
949 muted_[type] = muted;
950 for (auto&& input : inputs_) {
951 if (input->content_type() == type) {
952 input->SetMuted(muted);
953 }
954 }
955 }
956
957 void StreamMixerAlsa::SetOutputLimit(AudioContentType type, float limit) {
958 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::SetOutputLimit, type, limit);
959 LOG(INFO) << "Set volume limit for " << static_cast<int>(type) << " to "
960 << limit;
961 volume_limit_[type] = limit;
962 float effective_volume = std::min(volume_[type], limit);
963 for (auto&& input : inputs_) {
964 // Volume limits don't apply to effects streams.
965 if (input->primary() && input->content_type() == type) {
966 input->SetContentTypeVolume(effective_volume);
967 }
968 }
969
970 for (auto&& filter : filter_groups_) {
971 if (filter->content_type() == type) {
972 filter->set_volume(effective_volume);
973 }
974 }
975 }
976
970 } // namespace media 977 } // namespace media
971 } // namespace chromecast 978 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698