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