brillo: Add binder interfaces for volume control.

Add binder interfaces for volume control to brilloaudioservice so the
client library can communicate to it.

BUG=27976764
TEST=none

Change-Id: I14dde5215ffb3116ea4d5cedc7110dec0c9fb173
diff --git a/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IAudioServiceCallback.aidl b/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IAudioServiceCallback.aidl
index 01e8ba2..841c4ae 100644
--- a/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IAudioServiceCallback.aidl
+++ b/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IAudioServiceCallback.aidl
@@ -27,4 +27,9 @@
 
   // Oneway call triggered when audio devices are disconnected from the system.
   oneway void OnAudioDevicesDisconnected(in int[] removed_devices);
+
+  // Oneway call triggered when the volume is changed. If there are
+  // multiple active streams, this call will be called multiple times.
+  oneway void OnVolumeChanged(
+      int stream_type, int old_volume_index, int new_volume_index);
 }
diff --git a/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IBrilloAudioService.aidl b/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IBrilloAudioService.aidl
index 745541e..209b651 100644
--- a/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IBrilloAudioService.aidl
+++ b/brillo/audio/audioservice/aidl/android/brillo/brilloaudioservice/IBrilloAudioService.aidl
@@ -21,13 +21,18 @@
 
 /*
  * Interface for BrilloAudioService that clients can use to get the list of
- * devices currently connected to the system as well as to register callbacks to
- * be notified when the device state changes.
+ * devices currently connected to the system as well as to control volume.
+ * Clients can also register callbacks to be notified about changes.
  */
 interface IBrilloAudioService {
+  // Constants for device enumeration.
   const int GET_DEVICES_INPUTS = 1;
   const int GET_DEVICES_OUTPUTS = 2;
 
+  // Constants for volume control.
+  const int VOLUME_BUTTON_PRESS_DOWN = 1;
+  const int VOLUME_BUTTON_PRESS_UP = 2;
+
   // Get the list of devices connected. If flag is GET_DEVICES_INPUTS, then
   // return input devices. Otherwise, return output devices.
   int[] GetDevices(int flag);
@@ -37,6 +42,30 @@
   // config is an int of type audio_policy_forced_cfg_t.
   void SetDevice(int usage, int config);
 
+  // Get the maximum number of steps used for a given stream.
+  int GetMaxVolumeSteps(int stream);
+
+  // Set the maximum number of steps to use for a given stream.
+  void SetMaxVolumeSteps(int stream, int max_steps);
+
+  // Set the volume for a given (stream, device) tuple.
+  void SetVolumeIndex(int stream, int device, int index);
+
+  // Get the current volume for a given (stream, device) tuple.
+  int GetVolumeIndex(int stream, int device);
+
+  // Get stream used when volume buttons are pressed.
+  int GetVolumeControlStream();
+
+  // Set default stream to use when volume buttons are pressed.
+  void SetVolumeControlStream(int stream);
+
+  // Increment volume.
+  void IncrementVolume();
+
+  // Decrement volume.
+  void DecrementVolume();
+
   // Register a callback object with the service.
   void RegisterServiceCallback(IAudioServiceCallback callback);
 
diff --git a/brillo/audio/audioservice/audio_daemon.cpp b/brillo/audio/audioservice/audio_daemon.cpp
index e737790..08ff548 100644
--- a/brillo/audio/audioservice/audio_daemon.cpp
+++ b/brillo/audio/audioservice/audio_daemon.cpp
@@ -46,12 +46,15 @@
 
   // Register a callback with the audio device handler to call when device state
   // changes.
-  base::Callback<void(AudioDeviceHandler::DeviceConnectionState,
-                      const std::vector<int>&)> device_callback = base::Bind(
-                          &AudioDaemon::DeviceCallback,
-                          weak_ptr_factory_.GetWeakPtr());
+  auto device_callback =
+      base::Bind(&AudioDaemon::DeviceCallback, weak_ptr_factory_.GetWeakPtr());
   audio_device_handler_->RegisterDeviceCallback(device_callback);
 
+  // Register a callback with the audio volume handler.
+  auto volume_callback =
+      base::Bind(&AudioDaemon::VolumeCallback, weak_ptr_factory_.GetWeakPtr());
+  audio_volume_handler_->RegisterCallback(volume_callback);
+
   audio_device_handler_->Init(aps_);
   audio_volume_handler_->Init(aps_);
 
@@ -85,8 +88,9 @@
 
 void AudioDaemon::InitializeBrilloAudioService() {
   brillo_audio_service_ = new BrilloAudioServiceImpl();
-  brillo_audio_service_->RegisterDeviceHandler(
-      std::weak_ptr<AudioDeviceHandler>(audio_device_handler_));
+  brillo_audio_service_->RegisterHandlers(
+      std::weak_ptr<AudioDeviceHandler>(audio_device_handler_),
+      std::weak_ptr<AudioVolumeHandler>(audio_volume_handler_));
   android::BinderWrapper::Get()->RegisterService(kServiceName,
                                                  brillo_audio_service_);
   VLOG(1) << "Registered brilloaudioservice with the service manager.";
@@ -170,4 +174,18 @@
     brillo_audio_service_->OnDevicesDisconnected(devices);
 }
 
+void AudioDaemon::VolumeCallback(audio_stream_type_t stream,
+                                 int previous_index,
+                                 int current_index) {
+  VLOG(1) << "Triggering volume button press callback.";
+  if (!brillo_audio_service_.get()) {
+    LOG(ERROR) << "The Brillo audio service object is unavailble. Will try to "
+               << "call the clients again once the service is up.";
+    InitializeBrilloAudioService();
+    VolumeCallback(stream, previous_index, current_index);
+    return;
+  }
+  brillo_audio_service_->OnVolumeChanged(stream, previous_index, current_index);
+}
+
 }  // namespace brillo
diff --git a/brillo/audio/audioservice/audio_daemon.h b/brillo/audio/audioservice/audio_daemon.h
index 0d0bf20..5fc01fd 100644
--- a/brillo/audio/audioservice/audio_daemon.h
+++ b/brillo/audio/audioservice/audio_daemon.h
@@ -40,7 +40,7 @@
   virtual ~AudioDaemon();
 
  protected:
-  // Initialize the audio device handler and start pollig the files in
+  // Initialize the audio daemon handlers and start pollig the files in
   // /dev/input.
   int OnInit() override;
 
@@ -62,6 +62,15 @@
   void DeviceCallback(AudioDeviceHandler::DeviceConnectionState,
                       const std::vector<int>& devices);
 
+  // Callback function when volume changes.
+  //
+  // |stream| is an audio_stream_type_t representing the stream.
+  // |previous_index| is the volume index before the key press.
+  // |current_index| is the volume index after the key press.
+  void VolumeCallback(audio_stream_type_t stream,
+                      int previous_index,
+                      int current_index);
+
   // Callback function for audio policy service death notification.
   void OnAPSDisconnected();
 
@@ -85,7 +94,7 @@
   // Handler for audio device input events.
   std::shared_ptr<AudioDeviceHandler> audio_device_handler_;
   // Handler for volume key press input events.
-  std::unique_ptr<AudioVolumeHandler> audio_volume_handler_;
+  std::shared_ptr<AudioVolumeHandler> audio_volume_handler_;
   // Used to generate weak_ptr to AudioDaemon for use in base::Bind.
   base::WeakPtrFactory<AudioDaemon> weak_ptr_factory_{this};
   // Pointer to the audio policy service.
diff --git a/brillo/audio/audioservice/audio_volume_handler.cpp b/brillo/audio/audioservice/audio_volume_handler.cpp
index 7fac388..d95b2c2 100644
--- a/brillo/audio/audioservice/audio_volume_handler.cpp
+++ b/brillo/audio/audioservice/audio_volume_handler.cpp
@@ -21,6 +21,7 @@
 #include <base/files/file_util.h>
 #include <base/logging.h>
 #include <brillo/map_utils.h>
+#include <brillo/message_loops/message_loop.h>
 #include <brillo/strings/string_utils.h>
 
 #include "audio_device_handler.h"
@@ -48,10 +49,38 @@
   InitAPSAllStreams();
 }
 
+void AudioVolumeHandler::RegisterCallback(
+    base::Callback<void(audio_stream_type_t, int, int)>& callback) {
+  callback_ = callback;
+}
+
+int AudioVolumeHandler::ConvertToUserDefinedIndex(audio_stream_type_t stream,
+                                                  int index) {
+  return index / step_sizes_[stream];
+}
+
+int AudioVolumeHandler::ConvertToInternalIndex(audio_stream_type_t stream,
+                                               int index) {
+  return index * step_sizes_[stream];
+}
+
+void AudioVolumeHandler::TriggerCallback(audio_stream_type_t stream,
+                                         int previous_index,
+                                         int current_index) {
+  int user_defined_previous_index =
+      ConvertToUserDefinedIndex(stream, previous_index);
+  int user_defined_current_index =
+      ConvertToUserDefinedIndex(stream, current_index);
+  MessageLoop::current()->PostTask(base::Bind(callback_,
+                                              stream,
+                                              user_defined_previous_index,
+                                              user_defined_current_index));
+}
+
 void AudioVolumeHandler::GenerateVolumeFile() {
   for (auto stream : kSupportedStreams_) {
     for (auto device : AudioDeviceHandler::kSupportedOutputDevices_) {
-      SetVolumeCurrentIndex(stream, device, kDefaultCurrentIndex_);
+      PersistVolumeConfiguration(stream, device, kDefaultCurrentIndex_);
     }
   }
   if (!kv_store_->Save(volume_state_file_)) {
@@ -59,6 +88,18 @@
   }
 }
 
+int AudioVolumeHandler::GetVolumeMaxSteps(audio_stream_type_t stream) {
+  return ConvertToUserDefinedIndex(stream, kMaxIndex_);
+}
+
+int AudioVolumeHandler::SetVolumeMaxSteps(audio_stream_type_t stream,
+                                          int max_steps) {
+  if (max_steps <= kMinIndex_ || max_steps > kMaxIndex_)
+    return EINVAL;
+  step_sizes_[stream] = kMaxIndex_ / max_steps;
+  return 0;
+}
+
 int AudioVolumeHandler::GetVolumeCurrentIndex(audio_stream_type_t stream,
                                               audio_devices_t device) {
   auto key = kCurrentIndexKey_ + "." + string_utils::ToString(stream) + "." +
@@ -68,18 +109,32 @@
   return std::stoi(value);
 }
 
-int AudioVolumeHandler::GetVolumeForKey(const std::string& key) {
-  std::string value;
-  kv_store_->GetString(key, &value);
-  return std::stoi(value);
+int AudioVolumeHandler::GetVolumeIndex(audio_stream_type_t stream,
+                                       audio_devices_t device) {
+  return ConvertToUserDefinedIndex(stream,
+                                   GetVolumeCurrentIndex(stream, device));
 }
 
-void AudioVolumeHandler::SetVolumeCurrentIndex(audio_stream_type_t stream,
-                                               audio_devices_t device,
-                                               int index) {
+int AudioVolumeHandler::SetVolumeIndex(audio_stream_type_t stream,
+                                       audio_devices_t device,
+                                       int index) {
+  if (index < kMinIndex_ ||
+      index > ConvertToUserDefinedIndex(stream, kMaxIndex_))
+    return EINVAL;
+  int previous_index = GetVolumeCurrentIndex(stream, device);
+  int current_absolute_index = ConvertToInternalIndex(stream, index);
+  PersistVolumeConfiguration(stream, device, current_absolute_index);
+  TriggerCallback(stream, previous_index, current_absolute_index);
+  return 0;
+}
+
+void AudioVolumeHandler::PersistVolumeConfiguration(audio_stream_type_t stream,
+                                                    audio_devices_t device,
+                                                    int index) {
   auto key = kCurrentIndexKey_ + "." + string_utils::ToString(stream) + "." +
              string_utils::ToString(device);
   kv_store_->SetString(key, string_utils::ToString(index));
+  kv_store_->Save(volume_state_file_);
 }
 
 void AudioVolumeHandler::InitAPSAllStreams() {
@@ -114,13 +169,18 @@
   InitAPSAllStreams();
 }
 
+audio_stream_type_t AudioVolumeHandler::GetVolumeControlStream() {
+  return selected_stream_;
+}
+
 void AudioVolumeHandler::SetVolumeControlStream(audio_stream_type_t stream) {
   selected_stream_ = stream;
 }
 
 int AudioVolumeHandler::GetNewVolumeIndex(int previous_index, int direction,
                                           audio_stream_type_t stream) {
-  int current_index = previous_index + direction * step_sizes_.at(stream);
+  int current_index =
+      previous_index + ConvertToInternalIndex(stream, direction);
   if (current_index < kMinIndex_) {
     return kMinIndex_;
   } else if (current_index > kMaxIndex_) {
@@ -139,7 +199,8 @@
   VLOG(1) << "Current index is " << current_index << " for stream " << stream
           << " and device " << device;
   aps_->setStreamVolumeIndex(stream, current_index, device);
-  SetVolumeCurrentIndex(selected_stream_, device, current_index);
+  PersistVolumeConfiguration(selected_stream_, device, current_index);
+  TriggerCallback(stream, previous_index, current_index);
 }
 
 void AudioVolumeHandler::AdjustVolumeActiveStreams(int direction) {
diff --git a/brillo/audio/audioservice/audio_volume_handler.h b/brillo/audio/audioservice/audio_volume_handler.h
index da9f141..fb95c2f 100644
--- a/brillo/audio/audioservice/audio_volume_handler.h
+++ b/brillo/audio/audioservice/audio_volume_handler.h
@@ -19,6 +19,7 @@
 #ifndef BRILLO_AUDIO_AUDIOSERVICE_AUDIO_VOLUME_HANDLER_H_
 #define BRILLO_AUDIO_AUDIOSERVICE_AUDIO_VOLUME_HANDLER_H_
 
+#include <base/bind.h>
 #include <base/files/file_path.h>
 #include <brillo/key_value_store.h>
 #include <gtest/gtest_prod.h>
@@ -58,30 +59,39 @@
   virtual void APSConnect(
       android::sp<android::IAudioPolicyService> aps) override;
 
+  // Get the stream used when volume buttons are pressed.
+  //
+  // Returns an audio_stream_t representing the stream. If
+  // SetVolumeControlStream isn't called before calling this method,
+  // STREAM_DEFAULT is returned.
+  audio_stream_type_t GetVolumeControlStream();
+
   // Set the stream to use when volume buttons are pressed.
   //
   // |stream| is an int representing the stream. Passing STREAM_DEFAULT to this
   // method can be used to reset selected_stream_.
   void SetVolumeControlStream(audio_stream_type_t stream);
 
- private:
-  friend class AudioVolumeHandlerTest;
-  FRIEND_TEST(AudioVolumeHandlerTest, FileGeneration);
-  FRIEND_TEST(AudioVolumeHandlerTest, GetVolumeForKey);
-  FRIEND_TEST(AudioVolumeHandlerTest, GetVolumeForStreamDeviceTuple);
-  FRIEND_TEST(AudioVolumeHandlerTest, SetVolumeForStreamDeviceTuple);
-  FRIEND_TEST(AudioVolumeHandlerTest, InitNoFile);
-  FRIEND_TEST(AudioVolumeHandlerTest, InitFilePresent);
-  FRIEND_TEST(AudioVolumeHandlerTest, ProcessEventEmpty);
-  FRIEND_TEST(AudioVolumeHandlerTest, ProcessEventKeyUp);
-  FRIEND_TEST(AudioVolumeHandlerTest, ProcessEventKeyDown);
-  FRIEND_TEST(AudioVolumeHandlerTest, SelectStream);
-  FRIEND_TEST(AudioVolumeHandlerTest, ComputeNewVolume);
-
-  // Read the initial volume of audio streams.
+  // Register a callback to be triggered when keys are pressed.
   //
-  // |path| is the file that contains the initial volume state.
-  void GetInitialVolumeState(const base::FilePath& path);
+  // |callback| is an object of type base::Callback.
+  void RegisterCallback(
+      base::Callback<void(audio_stream_type_t, int, int)>& callback);
+
+  // Set the max steps for an audio stream.
+  //
+  // |stream| is an int representing the stream.
+  // |max_index| is an int representing the maximum index to set for |stream|.
+  //
+  // Returns 0 on success and errno on failure.
+  int SetVolumeMaxSteps(audio_stream_type_t stream, int max_steps);
+
+  // Get the max steps for an audio stream.
+  //
+  // |stream| is an int representing the stream.
+  //
+  // Returns the maximum possible index for |stream|.
+  int GetVolumeMaxSteps(audio_stream_type_t stream);
 
   // Get the volume of a given key.
   //
@@ -91,20 +101,25 @@
   // Returns an int which corresponds to the current index.
   int GetVolumeCurrentIndex(audio_stream_type_t stream, audio_devices_t device);
 
-  // Get the volume of a given key.
-  //
-  // |key| is a string representing key in the key-value file.
-  //
-  // Returns an int which corresponds to the index.
-  int GetVolumeForKey(const std::string& key);
-
   // Set the volume for a given (stream, device) tuple.
   //
   // |stream| is an int representing the stream.
   // |device| is an int representing the device.
   // |index| is an int representing the volume.
-  void SetVolumeCurrentIndex(audio_stream_type_t stream, audio_devices_t device,
-                             int index);
+  //
+  // Returns 0 on success and errno on failure.
+  int SetVolumeIndex(audio_stream_type_t stream,
+                     audio_devices_t device,
+                     int index);
+
+  // Get the volume for a given (stream, device) tuple.
+  //
+  // |stream| is an int representing the stream.
+  // |device| is an int representing the device.
+  //
+  // Returns the index for the (stream, device) tuple. This index is between 0
+  // and the user defined maximum value.
+  int GetVolumeIndex(audio_stream_type_t stream, audio_devices_t device);
 
   // Update the volume index for a given stream.
   //
@@ -120,12 +135,40 @@
 
   // Adjust the volume of the active streams in the direction indicated. If
   // SetDefaultStream() is called, then only the volume for that stream will be
-  // changed.
+  // changed. Calling this method always triggers a callback.
   //
   // |direction| is an int which is multiplied to step_. +1 for volume up and -1
   // for volume down.
   virtual void AdjustVolumeActiveStreams(int direction);
 
+ private:
+  friend class AudioVolumeHandlerTest;
+  FRIEND_TEST(AudioVolumeHandlerTest, FileGeneration);
+  FRIEND_TEST(AudioVolumeHandlerTest, GetVolumeForStreamDeviceTuple);
+  FRIEND_TEST(AudioVolumeHandlerTest, SetVolumeForStreamDeviceTuple);
+  FRIEND_TEST(AudioVolumeHandlerTest, InitNoFile);
+  FRIEND_TEST(AudioVolumeHandlerTest, InitFilePresent);
+  FRIEND_TEST(AudioVolumeHandlerTest, ProcessEventEmpty);
+  FRIEND_TEST(AudioVolumeHandlerTest, ProcessEventKeyUp);
+  FRIEND_TEST(AudioVolumeHandlerTest, ProcessEventKeyDown);
+  FRIEND_TEST(AudioVolumeHandlerTest, SelectStream);
+  FRIEND_TEST(AudioVolumeHandlerTest, ComputeNewVolume);
+  FRIEND_TEST(AudioVolumeHandlerTest, GetSetVolumeIndex);
+
+  // Save the volume for a given (stream, device) tuple.
+  //
+  // |stream| is an int representing the stream.
+  // |device| is an int representing the device.
+  // |index| is an int representing the volume.
+  void PersistVolumeConfiguration(audio_stream_type_t stream,
+                                  audio_devices_t device,
+                                  int index);
+
+  // Read the initial volume of audio streams.
+  //
+  // |path| is the file that contains the initial volume state.
+  void GetInitialVolumeState(const base::FilePath& path);
+
   // Adjust the volume of a given stream in the direction specified.
   //
   // |stream| is an int representing the stream.
@@ -144,6 +187,35 @@
   // Generate the volume config file.
   void GenerateVolumeFile();
 
+  // Trigger a callback when a volume button is pressed.
+  //
+  // |stream| is an audio_stream_t representing the stream.
+  // |previous_index| is the volume index before the key press. This is an
+  // absolute index from 0 - 100.
+  // |current_index| is the volume index after the key press. This is an
+  // absolute index from 0 - 100.
+  virtual void TriggerCallback(audio_stream_type_t stream,
+                               int previous_index,
+                               int current_index);
+
+  // Convert internal index to user defined index scale.
+  //
+  // |stream| is an audio_stream_t representing the stream.
+  // |index| is the volume index before the key press. This is an absolute
+  // index from 0 - 100.
+  //
+  // Returns an int between 0 and the user defined max.
+  int ConvertToUserDefinedIndex(audio_stream_type_t stream, int index);
+
+  // Convert user defined index to internal index scale.
+  //
+  // |stream| is an audio_stream_t representing the stream.
+  // |index| is the volume index before the key press. This is an index from 0
+  // and the user defined max.
+  //
+  // Returns an int between 0 and 100.
+  int ConvertToInternalIndex(audio_stream_type_t stream, int index);
+
   // Stream to use for volume control.
   audio_stream_type_t selected_stream_;
   // File backed key-value store of the current index (as seen by the audio
@@ -158,7 +230,9 @@
   // stream ranges and the range as seen by audio policy service. This value is
   // not file-backed and is intended to be re-applied by the user on reboots and
   // brilloaudioservice crashes.
-  std::map<audio_stream_type_t, int> step_sizes_;
+  std::map<audio_stream_type_t, double> step_sizes_;
+  // Callback to call when volume buttons are pressed.
+  base::Callback<void(audio_stream_type_t, int, int)> callback_;
   // Key indicies.
   const std::string kCurrentIndexKey_ = "current_index";
   // Default values.
diff --git a/brillo/audio/audioservice/brillo_audio_service.h b/brillo/audio/audioservice/brillo_audio_service.h
index c3cbc8c..87ca0d7 100644
--- a/brillo/audio/audioservice/brillo_audio_service.h
+++ b/brillo/audio/audioservice/brillo_audio_service.h
@@ -24,8 +24,9 @@
 
 #include <binder/Status.h>
 
-#include "audio_device_handler.h"
 #include "android/brillo/brilloaudioservice/IAudioServiceCallback.h"
+#include "audio_device_handler.h"
+#include "audio_volume_handler.h"
 
 using android::binder::Status;
 using android::brillo::brilloaudioservice::BnBrilloAudioService;
@@ -40,16 +41,26 @@
   // From AIDL.
   virtual Status GetDevices(int flag, std::vector<int>* _aidl_return) = 0;
   virtual Status SetDevice(int usage, int config) = 0;
+  virtual Status GetMaxVolumeSteps(int stream, int* _aidl_return) = 0;
+  virtual Status SetMaxVolumeSteps(int stream, int max_steps) = 0;
+  virtual Status SetVolumeIndex(int stream, int device, int index) = 0;
+  virtual Status GetVolumeIndex(int stream, int device, int* _aidl_return) = 0;
+  virtual Status GetVolumeControlStream(int* _aidl_return) = 0;
+  virtual Status SetVolumeControlStream(int stream) = 0;
+  virtual Status IncrementVolume() = 0;
+  virtual Status DecrementVolume() = 0;
   virtual Status RegisterServiceCallback(
       const android::sp<IAudioServiceCallback>& callback) = 0;
   virtual Status UnregisterServiceCallback(
       const android::sp<IAudioServiceCallback>& callback) = 0;
 
-  // Register a device handler.
+  // Register daemon handlers.
   //
   // |audio_device_handler| is a weak pointer to an audio device handler object.
-  virtual void RegisterDeviceHandler(
-      std::weak_ptr<AudioDeviceHandler> audio_device_handler) = 0;
+  // |audio_volume_handler| is a weak pointer to an audio volume handler object.
+  virtual void RegisterHandlers(
+      std::weak_ptr<AudioDeviceHandler> audio_device_handler,
+      std::weak_ptr<AudioVolumeHandler> audio_volume_handler) = 0;
 
   // Callback to be called when a device is connected.
   //
@@ -60,6 +71,15 @@
   //
   // |devices| is a vector of ints representing the audio_devices_t.
   virtual void OnDevicesDisconnected(const std::vector<int>& device) = 0;
+
+  // Callback to be called when the volume is changed.
+  //
+  // |stream| is an audio_stream_type_t representing the stream.
+  // |previous_index| is the volume index before the key press.
+  // |current_index| is the volume index after the key press.
+  virtual void OnVolumeChanged(audio_stream_type_t stream,
+                               int previous_index,
+                               int current_index) = 0;
 };
 
 }  // namespace brillo
diff --git a/brillo/audio/audioservice/brillo_audio_service_impl.cpp b/brillo/audio/audioservice/brillo_audio_service_impl.cpp
index 9aa7c9b..d108a4a 100644
--- a/brillo/audio/audioservice/brillo_audio_service_impl.cpp
+++ b/brillo/audio/audioservice/brillo_audio_service_impl.cpp
@@ -64,9 +64,108 @@
   return Status::ok();
 }
 
-void BrilloAudioServiceImpl::RegisterDeviceHandler(
-    std::weak_ptr<AudioDeviceHandler> audio_device_handler) {
+void BrilloAudioServiceImpl::RegisterHandlers(
+    std::weak_ptr<AudioDeviceHandler> audio_device_handler,
+    std::weak_ptr<AudioVolumeHandler> audio_volume_handler) {
   audio_device_handler_ = audio_device_handler;
+  audio_volume_handler_ = audio_volume_handler;
+}
+
+Status BrilloAudioServiceImpl::GetMaxVolumeSteps(int stream,
+                                                 int* _aidl_return) {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  *_aidl_return = volume_handler->GetVolumeMaxSteps(
+      static_cast<audio_stream_type_t>(stream));
+  return Status::ok();
+}
+
+Status BrilloAudioServiceImpl::SetMaxVolumeSteps(int stream, int max_steps) {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  int rc = volume_handler->SetVolumeMaxSteps(
+      static_cast<audio_stream_type_t>(stream), max_steps);
+  if (rc)
+    return Status::fromServiceSpecificError(rc);
+  return Status::ok();
+}
+
+Status BrilloAudioServiceImpl::SetVolumeIndex(int stream,
+                                              int device,
+                                              int index) {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  int rc =
+      volume_handler->SetVolumeIndex(static_cast<audio_stream_type_t>(stream),
+                                     static_cast<audio_devices_t>(device),
+                                     index);
+  if (rc)
+    return Status::fromServiceSpecificError(rc);
+  return Status::ok();
+}
+
+Status BrilloAudioServiceImpl::GetVolumeIndex(int stream,
+                                              int device,
+                                              int* _aidl_return) {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  *_aidl_return =
+      volume_handler->GetVolumeIndex(static_cast<audio_stream_type_t>(stream),
+                                     static_cast<audio_devices_t>(device));
+  return Status::ok();
+}
+
+Status BrilloAudioServiceImpl::IncrementVolume() {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  volume_handler->AdjustVolumeActiveStreams(1);
+  return Status::ok();
+}
+
+Status BrilloAudioServiceImpl::GetVolumeControlStream(int* _aidl_return) {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  *_aidl_return = volume_handler->GetVolumeControlStream();
+  return Status::ok();
+}
+
+Status BrilloAudioServiceImpl::SetVolumeControlStream(int stream) {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  volume_handler->SetVolumeControlStream(
+      static_cast<audio_stream_type_t>(stream));
+  return Status::ok();
+}
+
+Status BrilloAudioServiceImpl::DecrementVolume() {
+  auto volume_handler = audio_volume_handler_.lock();
+  if (!volume_handler) {
+    return Status::fromServiceSpecificError(
+        EREMOTEIO, android::String8("The audio volume handler died."));
+  }
+  volume_handler->AdjustVolumeActiveStreams(-1);
+  return Status::ok();
 }
 
 void BrilloAudioServiceImpl::OnDevicesConnected(
@@ -83,4 +182,12 @@
   }
 }
 
+void BrilloAudioServiceImpl::OnVolumeChanged(audio_stream_type_t stream,
+                                             int previous_index,
+                                             int current_index) {
+  for (auto callback : callbacks_set_) {
+    callback->OnVolumeChanged(stream, previous_index, current_index);
+  }
+}
+
 }  // namespace brillo
diff --git a/brillo/audio/audioservice/brillo_audio_service_impl.h b/brillo/audio/audioservice/brillo_audio_service_impl.h
index d1e170b..af53b66 100644
--- a/brillo/audio/audioservice/brillo_audio_service_impl.h
+++ b/brillo/audio/audioservice/brillo_audio_service_impl.h
@@ -29,16 +29,26 @@
   // From AIDL.
   Status GetDevices(int flag, std::vector<int>* _aidl_return) override;
   Status SetDevice(int usage, int config) override;
+  Status GetMaxVolumeSteps(int stream, int* _aidl_return) override;
+  Status SetMaxVolumeSteps(int stream, int max_steps) override;
+  Status SetVolumeIndex(int stream, int device, int index) override;
+  Status GetVolumeIndex(int stream, int device, int* _aidl_return) override;
+  Status GetVolumeControlStream(int* _aidl_return) override;
+  Status SetVolumeControlStream(int stream) override;
+  Status IncrementVolume() override;
+  Status DecrementVolume() override;
   Status RegisterServiceCallback(
       const android::sp<IAudioServiceCallback>& callback) override;
   Status UnregisterServiceCallback(
       const android::sp<IAudioServiceCallback>& callback) override;
 
-  // Register a device handler.
+  // Register daemon handlers.
   //
   // |audio_device_handler| is a weak pointer to an audio device handler object.
-  void RegisterDeviceHandler(
-      std::weak_ptr<AudioDeviceHandler> audio_device_handler) override;
+  // |audio_volume_handler| is a weak pointer to an audio volume handler object.
+  void RegisterHandlers(
+      std::weak_ptr<AudioDeviceHandler> audio_device_handler,
+      std::weak_ptr<AudioVolumeHandler> audio_volume_handler) override;
 
   // Callback to be called when a device is connected.
   //
@@ -50,9 +60,20 @@
   // |devices| is a vector of ints representing the audio_devices_t.
   void OnDevicesDisconnected(const std::vector<int>& device) override;
 
+  // Callback to be called when volume is changed.
+  //
+  // |stream| is an int representing the stream.
+  // |previous_index| is the volume index before the key press.
+  // |current_index| is the volume index after the key press.
+  void OnVolumeChanged(audio_stream_type_t stream,
+                       int previous_index,
+                       int current_index) override;
+
  private:
   // A weak pointer to the audio device handler.
   std::weak_ptr<AudioDeviceHandler> audio_device_handler_;
+  // A weak pointer to the audio volume handler.
+  std::weak_ptr<AudioVolumeHandler> audio_volume_handler_;
   // List of all callbacks objects registered with the service.
   std::set<android::sp<IAudioServiceCallback> > callbacks_set_;
 };
diff --git a/brillo/audio/audioservice/test/audio_volume_handler_mock.h b/brillo/audio/audioservice/test/audio_volume_handler_mock.h
index 19168f6..32028ca 100644
--- a/brillo/audio/audioservice/test/audio_volume_handler_mock.h
+++ b/brillo/audio/audioservice/test/audio_volume_handler_mock.h
@@ -43,7 +43,9 @@
   FRIEND_TEST(AudioVolumeHandlerTest, ProcessEventKeyDown);
   FRIEND_TEST(AudioVolumeHandlerTest, SelectStream);
   FRIEND_TEST(AudioVolumeHandlerTest, ComputeNewVolume);
+  FRIEND_TEST(AudioVolumeHandlerTest, GetSetVolumeIndex);
 
+  MOCK_METHOD3(TriggerCallback, void(audio_stream_type_t, int, int));
   MOCK_METHOD0(InitAPSAllStreams, void());
   MOCK_METHOD1(AdjustVolumeActiveStreams, void(int));
 };
diff --git a/brillo/audio/audioservice/test/audio_volume_handler_test.cpp b/brillo/audio/audioservice/test/audio_volume_handler_test.cpp
index c4e2f0d..47ef236 100644
--- a/brillo/audio/audioservice/test/audio_volume_handler_test.cpp
+++ b/brillo/audio/audioservice/test/audio_volume_handler_test.cpp
@@ -47,6 +47,11 @@
     handler_.SetVolumeFilePathForTesting(volume_file_path_);
   }
 
+  void SetupHandlerVolumeFile() {
+    handler_.kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore);
+    handler_.GenerateVolumeFile();
+  }
+
   AudioVolumeHandlerMock handler_;
   FilePath volume_file_path_;
 
@@ -56,8 +61,7 @@
 
 // Test that the volume file is formatted correctly.
 TEST_F(AudioVolumeHandlerTest, FileGeneration) {
-  handler_.kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore);
-  handler_.GenerateVolumeFile();
+  SetupHandlerVolumeFile();
   KeyValueStore kv_store;
   kv_store.Load(volume_file_path_);
   for (auto stream : handler_.kSupportedStreams_) {
@@ -74,13 +78,6 @@
   }
 }
 
-// Test accessing the key-value store works.
-TEST_F(AudioVolumeHandlerTest, GetVolumeForKey) {
-  handler_.kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore);
-  handler_.kv_store_->SetString("foo", "100");
-  ASSERT_EQ(handler_.GetVolumeForKey("foo"), 100);
-}
-
 // Test GetVolumeCurrentIndex.
 TEST_F(AudioVolumeHandlerTest, GetVolumeForStreamDeviceTuple) {
   handler_.kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore);
@@ -93,7 +90,8 @@
 // Test SetVolumeCurrentIndex.
 TEST_F(AudioVolumeHandlerTest, SetVolumeForStreamDeviceTuple) {
   handler_.kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore);
-  handler_.SetVolumeCurrentIndex(static_cast<audio_stream_type_t>(1), 2, 100);
+  handler_.PersistVolumeConfiguration(
+      static_cast<audio_stream_type_t>(1), 2, 100);
   std::string value;
   auto key = handler_.kCurrentIndexKey_ + ".1.2";
   handler_.kv_store_->GetString(key, &value);
@@ -148,9 +146,9 @@
 }
 
 TEST_F(AudioVolumeHandlerTest, SelectStream) {
-  EXPECT_EQ(handler_.selected_stream_, AUDIO_STREAM_DEFAULT);
+  EXPECT_EQ(handler_.GetVolumeControlStream(), AUDIO_STREAM_DEFAULT);
   handler_.SetVolumeControlStream(AUDIO_STREAM_MUSIC);
-  EXPECT_EQ(handler_.selected_stream_, AUDIO_STREAM_MUSIC);
+  EXPECT_EQ(handler_.GetVolumeControlStream(), AUDIO_STREAM_MUSIC);
 }
 
 TEST_F(AudioVolumeHandlerTest, ComputeNewVolume) {
@@ -159,10 +157,56 @@
   handler_.step_sizes_[AUDIO_STREAM_MUSIC] = 10;
   EXPECT_EQ(handler_.GetNewVolumeIndex(50, 1, AUDIO_STREAM_MUSIC), 60);
   EXPECT_EQ(handler_.GetNewVolumeIndex(50, -1, AUDIO_STREAM_MUSIC), 40);
-  handler_.kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore);
-  handler_.GenerateVolumeFile();
+  SetupHandlerVolumeFile();
   EXPECT_EQ(handler_.GetNewVolumeIndex(100, 1, AUDIO_STREAM_MUSIC), 100);
   EXPECT_EQ(handler_.GetNewVolumeIndex(0, -1, AUDIO_STREAM_MUSIC), 0);
 }
 
+TEST_F(AudioVolumeHandlerTest, GetSetMaxSteps) {
+  EXPECT_EQ(handler_.GetVolumeMaxSteps(AUDIO_STREAM_MUSIC), 100);
+  EXPECT_EQ(handler_.SetVolumeMaxSteps(AUDIO_STREAM_MUSIC, 0), EINVAL);
+  EXPECT_EQ(handler_.GetVolumeMaxSteps(AUDIO_STREAM_MUSIC), 100);
+  EXPECT_EQ(handler_.SetVolumeMaxSteps(AUDIO_STREAM_MUSIC, 100), 0);
+  EXPECT_EQ(handler_.GetVolumeMaxSteps(AUDIO_STREAM_MUSIC), 100);
+  EXPECT_EQ(handler_.SetVolumeMaxSteps(AUDIO_STREAM_MUSIC, -1), EINVAL);
+  EXPECT_EQ(handler_.SetVolumeMaxSteps(AUDIO_STREAM_MUSIC, 101), EINVAL);
+}
+
+TEST_F(AudioVolumeHandlerTest, GetSetVolumeIndex) {
+  SetupHandlerVolumeFile();
+  EXPECT_CALL(handler_, TriggerCallback(AUDIO_STREAM_MUSIC, _, 0));
+  EXPECT_EQ(handler_.SetVolumeIndex(
+                AUDIO_STREAM_MUSIC, AUDIO_DEVICE_OUT_WIRED_HEADSET, 0),
+            0);
+  EXPECT_CALL(handler_, TriggerCallback(AUDIO_STREAM_MUSIC, 0, 50));
+  EXPECT_EQ(handler_.SetVolumeIndex(
+                AUDIO_STREAM_MUSIC, AUDIO_DEVICE_OUT_WIRED_HEADSET, 50),
+            0);
+  EXPECT_CALL(handler_, TriggerCallback(AUDIO_STREAM_MUSIC, 50, 100));
+  EXPECT_EQ(handler_.SetVolumeIndex(
+                AUDIO_STREAM_MUSIC, AUDIO_DEVICE_OUT_WIRED_HEADSET, 100),
+            0);
+  EXPECT_EQ(handler_.SetVolumeIndex(
+                AUDIO_STREAM_MUSIC, AUDIO_DEVICE_OUT_WIRED_HEADSET, -1),
+            EINVAL);
+  EXPECT_EQ(handler_.SetVolumeIndex(
+                AUDIO_STREAM_MUSIC, AUDIO_DEVICE_OUT_WIRED_HEADSET, 101),
+            EINVAL);
+  EXPECT_EQ(handler_.SetVolumeMaxSteps(AUDIO_STREAM_MUSIC, 10), 0);
+  EXPECT_EQ(handler_.GetVolumeIndex(AUDIO_STREAM_MUSIC,
+                                    AUDIO_DEVICE_OUT_WIRED_HEADSET),
+            10);
+  EXPECT_EQ(handler_.SetVolumeIndex(
+                AUDIO_STREAM_MUSIC, AUDIO_DEVICE_OUT_WIRED_HEADSET, 11),
+            EINVAL);
+  EXPECT_CALL(handler_, TriggerCallback(AUDIO_STREAM_MUSIC, 100, 50));
+  EXPECT_EQ(handler_.SetVolumeIndex(
+                AUDIO_STREAM_MUSIC, AUDIO_DEVICE_OUT_WIRED_HEADSET, 5),
+            0);
+  EXPECT_EQ(handler_.SetVolumeMaxSteps(AUDIO_STREAM_MUSIC, 20), 0);
+  EXPECT_EQ(handler_.GetVolumeIndex(AUDIO_STREAM_MUSIC,
+                                    AUDIO_DEVICE_OUT_WIRED_HEADSET),
+            10);
+}
+
 }  // namespace brillo