1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/audio_handler.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <math.h> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/singleton.h" 1172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/chromeos/audio_mixer_alsa.h" 12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chromeos { 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kMinVolumeDb = -90.0; 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Choosing 6.0dB here instead of 0dB to give user chance to amplify audio some 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// in case sounds or their setup is too quiet for them. 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kMaxVolumeDb = 6.0; 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A value of less than one adjusts quieter volumes in larger steps (giving 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// finer resolution in the higher volumes). 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kVolumeBias = 0.5; 253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// If a connection is lost, we try again this many times 263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kMaxReconnectTries = 4; 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// A flag to disable mixer. 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool g_disabled = false; 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// chromeos: This class will set the volume using ALSA to adjust volume and 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// mute, and handle the volume level logic. 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickdouble AudioHandler::GetVolumePercent() { 363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!VerifyMixerConnection()) 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return VolumeDbToPercent(mixer_->GetVolumeDb()); 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Set volume using our internal 0-100% range. Notice 0% is a special case of 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// silence, so we set the mixer volume to kSilenceDb instead of min_volume_db_. 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AudioHandler::SetVolumePercent(double volume_percent) { 453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!VerifyMixerConnection()) 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(volume_percent >= 0.0); 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double vol_db; 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (volume_percent <= 0) 5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen vol_db = AudioMixer::kSilenceDb; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch vol_db = PercentToVolumeDb(volume_percent); 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mixer_->SetVolumeDb(vol_db); 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AudioHandler::AdjustVolumeByPercent(double adjust_by_percent) { 593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!VerifyMixerConnection()) 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch DVLOG(1) << "Adjusting Volume by " << adjust_by_percent << " percent"; 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double volume = mixer_->GetVolumeDb(); 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double pct = VolumeDbToPercent(volume); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pct < 0) 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pct = 0; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pct = pct + adjust_by_percent; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pct > 100.0) 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pct = 100.0; 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double new_volume; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pct <= 0.1) 7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen new_volume = AudioMixer::kSilenceDb; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_volume = PercentToVolumeDb(pct); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (new_volume != volume) 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mixer_->SetVolumeDb(new_volume); 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool AudioHandler::IsMute() { 843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!VerifyMixerConnection()) 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return mixer_->IsMute(); 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AudioHandler::SetMute(bool do_mute) { 913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!VerifyMixerConnection()) 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch DVLOG(1) << "Setting Mute to " << do_mute; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mixer_->SetMute(do_mute); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid AudioHandler::Disconnect() { 9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen mixer_.reset(); 9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid AudioHandler::Disable() { 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen g_disabled = true; 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool AudioHandler::TryToConnect(bool async) { 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (mixer_type_ == MIXER_TYPE_ALSA) { 10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(1) << "Trying to connect to ALSA"; 10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen mixer_.reset(new AudioMixerAlsa()); 10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(1) << "Cannot find valid volume mixer"; 11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen mixer_.reset(); 11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (async) { 11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized)); 11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!mixer_->InitSync()) { 11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(1) << "Unable to reconnect to Mixer"; 12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic void ClipVolume(double* min_volume, double* max_volume) { 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (*min_volume < kMinVolumeDb) 12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *min_volume = kMinVolumeDb; 12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (*max_volume > kMaxVolumeDb) 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen *max_volume = kMaxVolumeDb; 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid AudioHandler::OnMixerInitialized(bool success) { 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch connected_ = success; 135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch DVLOG(1) << "OnMixerInitialized, success = " << success; 13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (connected_) { 13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (mixer_->GetVolumeLimits(&min_volume_db_, &max_volume_db_)) { 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ClipVolume(&min_volume_db_, &max_volume_db_); 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return; 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen VLOG(1) << "Unable to connect to mixer"; 145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen mixer_type_ = MIXER_TYPE_NONE; 14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // This frees the mixer on the UI thread 14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen BrowserThread::PostTask( 14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen BrowserThread::UI, FROM_HERE, 15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NewRunnableMethod(this, &AudioHandler::TryToConnect, true)); 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAudioHandler::AudioHandler() 1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick : connected_(false), 15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen reconnect_tries_(0), 15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen max_volume_db_(kMaxVolumeDb), 15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen min_volume_db_(kMinVolumeDb), 158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen mixer_type_(g_disabled ? MIXER_TYPE_NONE : MIXER_TYPE_ALSA) { 15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Start trying to connect to mixers asynchronously, starting with the current 16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // mixer_type_. If the connection fails, another TryToConnect() for the next 16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // mixer will be posted at that time. 16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TryToConnect(true); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochAudioHandler::~AudioHandler() { 16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Disconnect(); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool AudioHandler::VerifyMixerConnection() { 17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (mixer_ == NULL) 17172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AudioMixer::State mixer_state = mixer_->GetState(); 17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (mixer_state == AudioMixer::READY) 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (connected_) { 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Something happened and the mixer is no longer valid after having been 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // initialized earlier. 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick connected_ = false; 18072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(ERROR) << "Lost connection to mixer"; 1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick LOG(ERROR) << "Mixer not valid"; 1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if ((mixer_state == AudioMixer::INITIALIZING) || 18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (mixer_state == AudioMixer::SHUTTING_DOWN)) 1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (reconnect_tries_ < kMaxReconnectTries) { 1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick reconnect_tries_++; 19172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen VLOG(1) << "Re-connecting to mixer attempt " << reconnect_tries_ << "/" 192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch << kMaxReconnectTries; 19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen connected_ = TryToConnect(false); 19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (connected_) { 1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick reconnect_tries_ = 0; 1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 20072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(ERROR) << "Unable to re-connect to mixer"; 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// VolumeDbToPercent() and PercentToVolumeDb() conversion functions allow us 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// complete control over how the 0 to 100% range is mapped to actual loudness. 20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Volume range is from min_volume_db_ at just above 0% to max_volume_db_ 20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// at 100% with a special case at 0% which maps to kSilenceDb. 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The mapping is confined to these two functions to make it easy to adjust and 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// have everything else just work. The range is biased to give finer resolution 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// in the higher volumes if kVolumeBias is less than 1.0. 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsendouble AudioHandler::VolumeDbToPercent(double volume_db) const { 21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (volume_db < min_volume_db_) 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return 100.0 * pow((volume_db - min_volume_db_) / 21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (max_volume_db_ - min_volume_db_), 1/kVolumeBias); 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsendouble AudioHandler::PercentToVolumeDb(double volume_percent) const { 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return pow(volume_percent / 100.0, kVolumeBias) * 22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (max_volume_db_ - min_volume_db_) + min_volume_db_; 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// static 22921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenAudioHandler* AudioHandler::GetInstance() { 23021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return Singleton<AudioHandler>::get(); 23121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 23221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace chromeos 234