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