Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 | 127 |
| 128 float GetVolume(AudioContentType type) { | 128 float GetVolume(AudioContentType type) { |
| 129 base::AutoLock lock(volume_lock_); | 129 base::AutoLock lock(volume_lock_); |
| 130 return volumes_[type]; | 130 return volumes_[type]; |
| 131 } | 131 } |
| 132 | 132 |
| 133 void SetVolume(AudioContentType type, float level) { | 133 void SetVolume(AudioContentType type, float level) { |
| 134 level = std::max(0.0f, std::min(level, 1.0f)); | 134 level = std::max(0.0f, std::min(level, 1.0f)); |
| 135 thread_.task_runner()->PostTask( | 135 thread_.task_runner()->PostTask( |
| 136 FROM_HERE, base::Bind(&VolumeControlInternal::SetVolumeOnThread, | 136 FROM_HERE, base::Bind(&VolumeControlInternal::SetVolumeOnThread, |
| 137 base::Unretained(this), type, level)); | 137 base::Unretained(this), type, level, false)); |
|
kmackay
2017/03/24 04:02:50
false /* from_alsa */
gfhuang
2017/03/24 06:29:59
Done.
| |
| 138 } | 138 } |
| 139 | 139 |
| 140 bool IsMuted(AudioContentType type) { | 140 bool IsMuted(AudioContentType type) { |
| 141 base::AutoLock lock(volume_lock_); | 141 base::AutoLock lock(volume_lock_); |
| 142 return muted_[type]; | 142 return muted_[type]; |
| 143 } | 143 } |
| 144 | 144 |
| 145 void SetMuted(AudioContentType type, bool muted) { | 145 void SetMuted(AudioContentType type, bool muted) { |
| 146 thread_.task_runner()->PostTask( | 146 thread_.task_runner()->PostTask( |
| 147 FROM_HERE, base::Bind(&VolumeControlInternal::SetMutedOnThread, | 147 FROM_HERE, base::Bind(&VolumeControlInternal::SetMutedOnThread, |
| 148 base::Unretained(this), type, muted)); | 148 base::Unretained(this), type, muted, false)); |
|
kmackay
2017/03/24 04:02:50
/* from_alsa */
gfhuang
2017/03/24 06:30:00
Done.
| |
| 149 } | 149 } |
| 150 | 150 |
| 151 void SetOutputLimit(AudioContentType type, float limit) { | 151 void SetOutputLimit(AudioContentType type, float limit) { |
| 152 if (BUILDFLAG(ALSA_CONTROLS_VOLUME)) { | 152 if (BUILDFLAG(ALSA_OWNS_VOLUME)) { |
| 153 return; | 153 return; |
| 154 } | 154 } |
| 155 limit = std::max(0.0f, std::min(limit, 1.0f)); | 155 limit = std::max(0.0f, std::min(limit, 1.0f)); |
| 156 StreamMixerAlsa::Get()->SetOutputLimit( | 156 StreamMixerAlsa::Get()->SetOutputLimit( |
| 157 type, DbFsToScale(VolumeControl::VolumeToDbFS(limit))); | 157 type, DbFsToScale(VolumeControl::VolumeToDbFS(limit))); |
| 158 } | 158 } |
| 159 | 159 |
| 160 private: | 160 private: |
| 161 void InitializeOnThread() { | 161 void InitializeOnThread() { |
| 162 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); | 162 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); |
| 163 alsa_volume_control_ = base::MakeUnique<AlsaVolumeControl>(this); | 163 alsa_volume_control_ = base::MakeUnique<AlsaVolumeControl>(this); |
| 164 | 164 |
| 165 double dbfs; | 165 double dbfs; |
| 166 for (auto type : {AudioContentType::kMedia, AudioContentType::kAlarm, | 166 for (auto type : {AudioContentType::kMedia, AudioContentType::kAlarm, |
| 167 AudioContentType::kCommunication}) { | 167 AudioContentType::kCommunication}) { |
| 168 CHECK(stored_values_.GetDouble(ContentTypeToDbFSKey(type), &dbfs)); | 168 CHECK(stored_values_.GetDouble(ContentTypeToDbFSKey(type), &dbfs)); |
| 169 volumes_[type] = VolumeControl::DbFSToVolume(dbfs); | 169 volumes_[type] = VolumeControl::DbFSToVolume(dbfs); |
| 170 if (BUILDFLAG(ALSA_CONTROLS_VOLUME)) { | 170 if (BUILDFLAG(ALSA_OWNS_VOLUME)) { |
| 171 // If ALSA controls volume, our internal mixer should not apply any | 171 // If ALSA owns volume, our internal mixer should not apply any scaling |
| 172 // scaling multiplier. | 172 // multiplier. |
| 173 StreamMixerAlsa::Get()->SetVolume(type, 1.0f); | 173 StreamMixerAlsa::Get()->SetVolume(type, 1.0f); |
| 174 } else { | 174 } else { |
| 175 StreamMixerAlsa::Get()->SetVolume(type, DbFsToScale(dbfs)); | 175 StreamMixerAlsa::Get()->SetVolume(type, DbFsToScale(dbfs)); |
| 176 } | 176 } |
| 177 | 177 |
| 178 // Note that mute state is not persisted across reboots. | 178 // Note that mute state is not persisted across reboots. |
| 179 muted_[type] = false; | 179 muted_[type] = false; |
| 180 } | 180 } |
| 181 | 181 |
| 182 if (BUILDFLAG(ALSA_CONTROLS_VOLUME)) { | 182 if (BUILDFLAG(ALSA_OWNS_VOLUME)) { |
| 183 // If ALSA controls the volume, then read the current volume and mute | 183 // If ALSA owns the volume, then read the current volume and mute state |
| 184 // state from the ALSA mixer element(s). | 184 // from the ALSA mixer element(s). |
| 185 volumes_[AudioContentType::kMedia] = alsa_volume_control_->GetVolume(); | 185 volumes_[AudioContentType::kMedia] = alsa_volume_control_->GetVolume(); |
| 186 muted_[AudioContentType::kMedia] = alsa_volume_control_->IsMuted(); | 186 muted_[AudioContentType::kMedia] = alsa_volume_control_->IsMuted(); |
| 187 } else { | 187 } else { |
| 188 // Otherwise, make sure the ALSA mixer element correctly reflects the | 188 // Otherwise, make sure the ALSA mixer element correctly reflects the |
| 189 // current volume state. | 189 // current volume state. |
| 190 alsa_volume_control_->SetVolume(volumes_[AudioContentType::kMedia]); | 190 alsa_volume_control_->SetVolume(volumes_[AudioContentType::kMedia]); |
| 191 alsa_volume_control_->SetMuted(false); | 191 alsa_volume_control_->SetMuted(false); |
| 192 } | 192 } |
| 193 | 193 |
| 194 initialize_complete_event_.Signal(); | 194 initialize_complete_event_.Signal(); |
| 195 } | 195 } |
| 196 | 196 |
| 197 void SetVolumeOnThread(AudioContentType type, float level) { | 197 void SetVolumeOnThread(AudioContentType type, float level, bool from_alsa) { |
| 198 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); | 198 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); |
| 199 DCHECK(!from_alsa || type == AudioContentType::kMedia); | |
| 199 { | 200 { |
| 200 base::AutoLock lock(volume_lock_); | 201 base::AutoLock lock(volume_lock_); |
| 202 if (from_alsa && alsa_volume_control_->VolumeThroughAlsa( | |
| 203 volumes_[AudioContentType::kMedia]) == level) { | |
| 204 return; | |
| 205 } | |
| 201 if (level == volumes_[type]) { | 206 if (level == volumes_[type]) { |
| 202 return; | 207 return; |
| 203 } | 208 } |
| 204 volumes_[type] = level; | 209 volumes_[type] = level; |
| 205 } | 210 } |
| 206 | 211 |
| 207 float dbfs = VolumeControl::VolumeToDbFS(level); | 212 float dbfs = VolumeControl::VolumeToDbFS(level); |
| 208 if (!BUILDFLAG(ALSA_CONTROLS_VOLUME)) { | 213 if (!BUILDFLAG(ALSA_OWNS_VOLUME)) { |
| 209 StreamMixerAlsa::Get()->SetVolume(type, DbFsToScale(dbfs)); | 214 StreamMixerAlsa::Get()->SetVolume(type, DbFsToScale(dbfs)); |
| 210 } | 215 } |
| 211 | 216 |
| 212 if (type == AudioContentType::kMedia) { | 217 if (!from_alsa && type == AudioContentType::kMedia) { |
| 213 alsa_volume_control_->SetVolume(level); | 218 alsa_volume_control_->SetVolume(level); |
| 214 } | 219 } |
| 215 | 220 |
| 216 { | 221 { |
| 217 base::AutoLock lock(observer_lock_); | 222 base::AutoLock lock(observer_lock_); |
| 218 for (VolumeObserver* observer : volume_observers_) { | 223 for (VolumeObserver* observer : volume_observers_) { |
| 219 observer->OnVolumeChange(type, level); | 224 observer->OnVolumeChange(type, level); |
| 220 } | 225 } |
| 221 } | 226 } |
| 222 | 227 |
| 223 stored_values_.SetDouble(ContentTypeToDbFSKey(type), dbfs); | 228 stored_values_.SetDouble(ContentTypeToDbFSKey(type), dbfs); |
| 224 SerializeJsonToFile(storage_path_, stored_values_); | 229 SerializeJsonToFile(storage_path_, stored_values_); |
| 225 } | 230 } |
| 226 | 231 |
| 227 void SetMutedOnThread(AudioContentType type, bool muted) { | 232 void SetMutedOnThread(AudioContentType type, bool muted, bool from_alsa) { |
| 228 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); | 233 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); |
| 229 { | 234 { |
| 230 base::AutoLock lock(volume_lock_); | 235 base::AutoLock lock(volume_lock_); |
| 231 if (muted == muted_[type]) { | 236 if (muted == muted_[type]) { |
| 232 return; | 237 return; |
| 233 } | 238 } |
| 234 muted_[type] = muted; | 239 muted_[type] = muted; |
| 235 } | 240 } |
| 236 | 241 |
| 237 if (!BUILDFLAG(ALSA_CONTROLS_VOLUME)) { | 242 if (!BUILDFLAG(ALSA_OWNS_VOLUME)) { |
| 238 StreamMixerAlsa::Get()->SetMuted(type, muted); | 243 StreamMixerAlsa::Get()->SetMuted(type, muted); |
| 239 } | 244 } |
| 240 | 245 |
| 241 if (type == AudioContentType::kMedia) { | 246 if (!from_alsa && type == AudioContentType::kMedia) { |
| 242 alsa_volume_control_->SetMuted(muted); | 247 alsa_volume_control_->SetMuted(muted); |
| 243 } | 248 } |
| 244 | 249 |
| 245 { | 250 { |
| 246 base::AutoLock lock(observer_lock_); | 251 base::AutoLock lock(observer_lock_); |
| 247 for (VolumeObserver* observer : volume_observers_) { | 252 for (VolumeObserver* observer : volume_observers_) { |
| 248 observer->OnMuteChange(type, muted); | 253 observer->OnMuteChange(type, muted); |
| 249 } | 254 } |
| 250 } | 255 } |
| 251 } | 256 } |
| 252 | 257 |
| 253 // AlsaVolumeControl::Delegate implementation: | 258 // AlsaVolumeControl::Delegate implementation: |
| 254 void OnAlsaVolumeOrMuteChange(float new_volume, bool new_mute) override { | 259 void OnAlsaVolumeOrMuteChange(float new_volume, bool new_mute) override { |
| 255 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); | 260 DCHECK(thread_.task_runner()->BelongsToCurrentThread()); |
| 256 bool volume_changed = false; | 261 SetVolumeOnThread(AudioContentType::kMedia, new_volume, |
| 257 bool mute_changed = false; | 262 true /* from_alsa */); |
| 258 { | 263 SetMutedOnThread(AudioContentType::kMedia, new_mute, true /* from_alsa */); |
| 259 base::AutoLock lock(volume_lock_); | |
| 260 if (alsa_volume_control_->VolumeThroughAlsa( | |
| 261 volumes_[AudioContentType::kMedia]) != new_volume) { | |
| 262 volume_changed = true; | |
| 263 volumes_[AudioContentType::kMedia] = new_volume; | |
| 264 } | |
| 265 | |
| 266 if (muted_[AudioContentType::kMedia] != new_mute) { | |
| 267 mute_changed = true; | |
| 268 muted_[AudioContentType::kMedia] = new_mute; | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 if (!volume_changed && !mute_changed) { | |
| 273 return; | |
| 274 } | |
| 275 | |
| 276 { | |
| 277 base::AutoLock lock(observer_lock_); | |
| 278 if (volume_changed) { | |
| 279 for (VolumeObserver* observer : volume_observers_) { | |
| 280 observer->OnVolumeChange(AudioContentType::kMedia, new_volume); | |
| 281 } | |
| 282 } | |
| 283 if (mute_changed) { | |
| 284 for (VolumeObserver* observer : volume_observers_) { | |
| 285 observer->OnMuteChange(AudioContentType::kMedia, new_mute); | |
| 286 } | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 if (volume_changed) { | |
| 291 float dbfs = VolumeControl::VolumeToDbFS(new_volume); | |
| 292 stored_values_.SetDouble(ContentTypeToDbFSKey(AudioContentType::kMedia), | |
| 293 dbfs); | |
| 294 SerializeJsonToFile(storage_path_, stored_values_); | |
| 295 } | |
| 296 } | 264 } |
| 297 | 265 |
| 298 base::FilePath storage_path_; | 266 base::FilePath storage_path_; |
| 299 base::DictionaryValue stored_values_; | 267 base::DictionaryValue stored_values_; |
| 300 | 268 |
| 301 base::Lock volume_lock_; | 269 base::Lock volume_lock_; |
| 302 std::map<AudioContentType, float> volumes_; | 270 std::map<AudioContentType, float> volumes_; |
| 303 std::map<AudioContentType, bool> muted_; | 271 std::map<AudioContentType, bool> muted_; |
| 304 | 272 |
| 305 base::Lock observer_lock_; | 273 base::Lock observer_lock_; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 | 360 |
| 393 return kVolumeMap[i - 1].level + | 361 return kVolumeMap[i - 1].level + |
| 394 (db - kVolumeMap[i - 1].db) * y_diff / x_diff; | 362 (db - kVolumeMap[i - 1].db) * y_diff / x_diff; |
| 395 } | 363 } |
| 396 } | 364 } |
| 397 return kVolumeMap[arraysize(kVolumeMap) - 1].level; | 365 return kVolumeMap[arraysize(kVolumeMap) - 1].level; |
| 398 } | 366 } |
| 399 | 367 |
| 400 } // namespace media | 368 } // namespace media |
| 401 } // namespace chromecast | 369 } // namespace chromecast |
| OLD | NEW |