OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |