Chromium Code Reviews| Index: chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc |
| diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc |
| index 0430d330b69ef74c5e9805ed227392c2ff70f111..8d9bfea14f44327a9f53cc77ae3237154695eaa4 100644 |
| --- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc |
| +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc |
| @@ -17,7 +17,6 @@ |
| #include "base/memory/weak_ptr.h" |
| #include "base/numerics/saturated_arithmetic.h" |
| #include "base/single_thread_task_runner.h" |
| -#include "base/strings/string_number_conversions.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "chromecast/base/chromecast_switches.h" |
| @@ -126,50 +125,6 @@ int64_t TimespecToMicroseconds(struct timespec time) { |
| time.tv_nsec / 1000; |
| } |
| -bool GetSwitchValueAsInt(const std::string& switch_name, |
| - int default_value, |
| - int* value) { |
| - DCHECK(value); |
| - *value = default_value; |
| - if (!base::CommandLine::InitializedForCurrentProcess()) { |
| - LOG(WARNING) << "No CommandLine for current process."; |
| - return false; |
| - } |
| - const base::CommandLine* command_line = |
| - base::CommandLine::ForCurrentProcess(); |
| - if (!command_line->HasSwitch(switch_name)) { |
| - return false; |
| - } |
| - |
| - int arg_value; |
| - if (!base::StringToInt(command_line->GetSwitchValueASCII(switch_name), |
| - &arg_value)) { |
| - LOG(DFATAL) << "--" << switch_name << " only accepts integers as arguments"; |
| - return false; |
| - } |
| - *value = arg_value; |
| - return true; |
| -} |
| - |
| -bool GetSwitchValueAsNonNegativeInt(const std::string& switch_name, |
| - int default_value, |
| - int* value) { |
| - DCHECK_GE(default_value, 0) << "--" << switch_name |
| - << " must have a non-negative default value"; |
| - DCHECK(value); |
| - |
| - if (!GetSwitchValueAsInt(switch_name, default_value, value)) { |
| - return false; |
| - } |
| - |
| - if (*value < 0) { |
| - LOG(DFATAL) << "--" << switch_name << " must have a non-negative value"; |
| - *value = default_value; |
| - return false; |
| - } |
| - return true; |
| -} |
| - |
| void VectorAccumulate(const int32_t* source, size_t size, int32_t* dest) { |
| for (size_t i = 0; i < size; ++i) { |
| dest[i] = base::SaturatedAddition(source[i], dest[i]); |
| @@ -214,7 +169,6 @@ StreamMixerAlsa::StreamMixerAlsa() |
| pcm_status_(nullptr), |
| pcm_format_(SND_PCM_FORMAT_UNKNOWN), |
| alsa_buffer_size_(0), |
| - alsa_period_explicitly_set(false), |
| alsa_period_size_(0), |
| alsa_start_threshold_(0), |
| alsa_avail_min_(0), |
| @@ -222,6 +176,13 @@ StreamMixerAlsa::StreamMixerAlsa() |
| retry_write_frames_timer_(new base::Timer(false, false)), |
| check_close_timeout_(kDefaultCheckCloseTimeoutMs), |
| check_close_timer_(new base::Timer(false, false)) { |
| + 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.
|
| + AudioContentType::kCommunication}) { |
| + volume_[type] = 1.0f; |
| + volume_limit_[type] = 1.0f; |
| + muted_[type] = false; |
| + } |
| + |
| if (single_threaded_for_test_) { |
| mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| } else { |
| @@ -240,9 +201,8 @@ StreamMixerAlsa::StreamMixerAlsa() |
| switches::kAlsaOutputDevice); |
| } |
| - int fixed_samples_per_second; |
| - GetSwitchValueAsNonNegativeInt(switches::kAlsaFixedOutputSampleRate, |
| - kInvalidSampleRate, &fixed_samples_per_second); |
| + int fixed_samples_per_second = GetSwitchValueNonNegativeInt( |
| + switches::kAlsaFixedOutputSampleRate, kInvalidSampleRate); |
| if (fixed_samples_per_second != kInvalidSampleRate) { |
| LOG(INFO) << "Setting fixed sample rate to " << fixed_samples_per_second; |
| } |
| @@ -259,18 +219,19 @@ StreamMixerAlsa::StreamMixerAlsa() |
| filter_groups_.push_back(base::MakeUnique<FilterGroup>( |
| std::unordered_set<std::string>( |
| {::media::AudioDeviceDescription::kCommunicationsDeviceId}), |
| - AudioFilterFactory::COMMUNICATION_AUDIO_FILTER)); |
| + AudioFilterFactory::COMMUNICATION_AUDIO_FILTER, |
| + AudioContentType::kMedia)); |
| filter_groups_.push_back(base::MakeUnique<FilterGroup>( |
| std::unordered_set<std::string>({kAlarmAudioDeviceId}), |
| - AudioFilterFactory::ALARM_AUDIO_FILTER)); |
| + AudioFilterFactory::ALARM_AUDIO_FILTER, AudioContentType::kAlarm)); |
| filter_groups_.push_back(base::MakeUnique<FilterGroup>( |
| std::unordered_set<std::string>({kTtsAudioDeviceId}), |
| - AudioFilterFactory::TTS_AUDIO_FILTER)); |
| + AudioFilterFactory::TTS_AUDIO_FILTER, AudioContentType::kCommunication)); |
| filter_groups_.push_back(base::MakeUnique<FilterGroup>( |
| std::unordered_set<std::string>( |
| {::media::AudioDeviceDescription::kDefaultDeviceId, |
| kLocalAudioDeviceId, ""}), |
| - AudioFilterFactory::MEDIA_AUDIO_FILTER)); |
| + AudioFilterFactory::MEDIA_AUDIO_FILTER, AudioContentType::kMedia)); |
| DefineAlsaParameters(); |
| } |
| @@ -281,52 +242,42 @@ void StreamMixerAlsa::ResetTaskRunnerForTest() { |
| void StreamMixerAlsa::DefineAlsaParameters() { |
| // Get the ALSA output configuration from the command line. |
| - int buffer_size; |
| - GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputBufferSize, |
| - kDefaultOutputBufferSizeFrames, &buffer_size); |
| - alsa_buffer_size_ = buffer_size; |
| - |
| - int period_size; |
| - if (GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputPeriodSize, |
| - alsa_buffer_size_ / 16, &period_size)) { |
| - if (period_size >= buffer_size) { |
| - LOG(DFATAL) << "ALSA period size must be smaller than the buffer size"; |
| - period_size = buffer_size / 2; |
| - } else { |
| - alsa_period_explicitly_set = true; |
| - } |
| + alsa_buffer_size_ = GetSwitchValueNonNegativeInt( |
| + switches::kAlsaOutputBufferSize, kDefaultOutputBufferSizeFrames); |
| + |
| + alsa_period_size_ = GetSwitchValueNonNegativeInt( |
| + switches::kAlsaOutputPeriodSize, alsa_buffer_size_ / 16); |
| + if (alsa_period_size_ >= alsa_buffer_size_) { |
| + LOG(DFATAL) << "ALSA period size must be smaller than the buffer size"; |
| + alsa_period_size_ = alsa_buffer_size_ / 2; |
| } |
| - alsa_period_size_ = period_size; |
| - int start_threshold; |
| - GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputStartThreshold, |
| - (buffer_size / period_size) * period_size, |
| - &start_threshold); |
| - if (start_threshold > buffer_size) { |
| + alsa_start_threshold_ = GetSwitchValueNonNegativeInt( |
| + switches::kAlsaOutputStartThreshold, |
| + (alsa_buffer_size_ / alsa_period_size_) * alsa_period_size_); |
| + if (alsa_start_threshold_ > alsa_buffer_size_) { |
| LOG(DFATAL) << "ALSA start threshold must be no larger than " |
| << "the buffer size"; |
| - start_threshold = (buffer_size / period_size) * period_size; |
| + alsa_start_threshold_ = |
| + (alsa_buffer_size_ / alsa_period_size_) * alsa_period_size_; |
| } |
| - alsa_start_threshold_ = start_threshold; |
| // By default, allow the transfer when at least period_size samples can be |
| // processed. |
| - int avail_min; |
| - GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputAvailMin, period_size, |
| - &avail_min); |
| - if (avail_min > buffer_size) { |
| + alsa_avail_min_ = GetSwitchValueNonNegativeInt(switches::kAlsaOutputAvailMin, |
| + alsa_period_size_); |
| + if (alsa_avail_min_ > alsa_buffer_size_) { |
| LOG(DFATAL) << "ALSA avail min must be no larger than the buffer size"; |
| - avail_min = alsa_period_size_; |
| + alsa_avail_min_ = alsa_period_size_; |
| } |
| - alsa_avail_min_ = avail_min; |
| // --accept-resource-provider should imply a check close timeout of 0. |
| int default_close_timeout = chromecast::GetSwitchValueBoolean( |
| switches::kAcceptResourceProvider, false) |
| ? 0 |
| : kDefaultCheckCloseTimeoutMs; |
| - GetSwitchValueAsInt(switches::kAlsaCheckCloseTimeout, default_close_timeout, |
| - &check_close_timeout_); |
| + check_close_timeout_ = GetSwitchValueInt(switches::kAlsaCheckCloseTimeout, |
| + default_close_timeout); |
| } |
| unsigned int StreamMixerAlsa::DetermineOutputRate(unsigned int requested_rate) { |
| @@ -442,11 +393,7 @@ int StreamMixerAlsa::SetAlsaPlaybackParams() { |
| << " frames). This may lead to an increase in " |
| "either audio latency or audio underruns."; |
| - // Always try to use the value for period_size that was passed in on the |
| - // command line, if any. |
| - if (!alsa_period_explicitly_set) { |
| - alsa_period_size_ = alsa_buffer_size_ / 16; |
| - } else if (alsa_period_size_ >= alsa_buffer_size_) { |
| + if (alsa_period_size_ >= alsa_buffer_size_) { |
| snd_pcm_uframes_t new_period_size = alsa_buffer_size_ / 2; |
| LOG(DFATAL) << "Configured period size (" << alsa_period_size_ |
| << ") is >= actual buffer size (" << alsa_buffer_size_ |
| @@ -660,6 +607,14 @@ void StreamMixerAlsa::AddInput(std::unique_ptr<InputQueue> input) { |
| CheckChangeOutputRate(input->input_samples_per_second()); |
| } |
| + auto type = input->content_type(); |
| + if (input->primary()) { |
| + input->SetContentTypeVolume(std::min(volume_limit_[type], volume_[type])); |
| + } else { |
| + input->SetContentTypeVolume(volume_[type]); |
| + } |
| + input->SetMuted(muted_[type]); |
| + |
| check_close_timer_->Stop(); |
| switch (state_) { |
| case kStateUninitialized: |
| @@ -967,5 +922,57 @@ void StreamMixerAlsa::RemoveLoopbackAudioObserver( |
| observer->OnRemoved(); |
| } |
| +void StreamMixerAlsa::SetVolume(AudioContentType type, float level) { |
| + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::SetVolume, type, level); |
| + volume_[type] = level; |
| + 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.
|
| + for (auto&& input : inputs_) { |
| + if (input->content_type() == type) { |
| + if (input->primary()) { |
| + input->SetContentTypeVolume(effective_volume); |
| + } else { |
| + // Volume limits don't apply to effects streams. |
| + input->SetContentTypeVolume(level); |
| + } |
| + } |
| + } |
| + |
| + for (auto&& filter : filter_groups_) { |
| + if (filter->content_type() == type) { |
| + filter->set_volume(effective_volume); |
| + } |
| + } |
| +} |
| + |
| +void StreamMixerAlsa::SetMuted(AudioContentType type, bool muted) { |
| + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::SetMuted, type, muted); |
| + muted_[type] = muted; |
| + for (auto&& input : inputs_) { |
| + if (input->content_type() == type) { |
| + input->SetMuted(muted); |
| + } |
| + } |
| +} |
| + |
| +void StreamMixerAlsa::SetOutputLimit(AudioContentType type, float limit) { |
| + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::SetOutputLimit, type, limit); |
| + LOG(INFO) << "Set volume limit for " << static_cast<int>(type) << " to " |
| + << limit; |
| + volume_limit_[type] = limit; |
| + float effective_volume = std::min(volume_[type], limit); |
| + for (auto&& input : inputs_) { |
| + // Volume limits don't apply to effects streams. |
| + if (input->primary() && input->content_type() == type) { |
| + input->SetContentTypeVolume(effective_volume); |
| + } |
| + } |
| + |
| + for (auto&& filter : filter_groups_) { |
| + if (filter->content_type() == type) { |
| + filter->set_volume(effective_volume); |
| + } |
| + } |
| +} |
| + |
| } // namespace media |
| } // namespace chromecast |