// Copyright 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Implementation of audio_volume_handler.h
#include "audio_volume_handler.h"
#include <base/files/file.h>
#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"
namespace brillo {
static const char kVolumeStateFilePath[] =
"/data/misc/brilloaudioservice/volume.dat";
AudioVolumeHandler::AudioVolumeHandler() {
for (auto stream : kSupportedStreams_) {
step_sizes_.emplace(stream, kDefaultStepSize_);
}
selected_stream_ = AUDIO_STREAM_DEFAULT;
volume_state_file_ = base::FilePath(kVolumeStateFilePath);
}
AudioVolumeHandler::~AudioVolumeHandler() {}
void AudioVolumeHandler::APSDisconnect() { aps_.clear(); }
void AudioVolumeHandler::APSConnect(
android::sp<android::IAudioPolicyService> aps) {
aps_ = aps;
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_) {
PersistVolumeConfiguration(stream, device, kDefaultCurrentIndex_);
}
}
if (!kv_store_->Save(volume_state_file_)) {
LOG(ERROR) << "Could not save volume data file!";
}
}
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) + "." +
string_utils::ToString(device);
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));
}
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() {
for (auto stream : kSupportedStreams_) {
aps_->initStreamVolume(stream, kMinIndex_, kMaxIndex_);
for (auto device : AudioDeviceHandler::kSupportedOutputDevices_) {
int current_index = GetVolumeCurrentIndex(stream, device);
aps_->setStreamVolumeIndex(stream, current_index, device);
}
}
}
void AudioVolumeHandler::SetVolumeFilePathForTesting(
const base::FilePath& path) {
volume_state_file_ = path;
}
void AudioVolumeHandler::Init(android::sp<android::IAudioPolicyService> aps) {
aps_ = aps;
kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore());
if (!base::PathExists(volume_state_file_)) {
// Generate key-value store and save it to a file.
GenerateVolumeFile();
} else {
// Load the file. If loading fails, generate the file.
if (!kv_store_->Load(volume_state_file_)) {
LOG(ERROR) << "Could not load volume data file!";
GenerateVolumeFile();
}
}
// Inform APS.
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 + ConvertToInternalIndex(stream, direction);
if (current_index < kMinIndex_) {
return kMinIndex_;
} else if (current_index > kMaxIndex_) {
return kMaxIndex_;
} else
return current_index;
}
void AudioVolumeHandler::AdjustStreamVolume(audio_stream_type_t stream,
int direction) {
VLOG(1) << "Adjusting volume of stream " << selected_stream_
<< " in direction " << direction;
auto device = aps_->getDevicesForStream(stream);
int previous_index = GetVolumeCurrentIndex(stream, device);
int current_index = GetNewVolumeIndex(previous_index, direction, stream);
VLOG(1) << "Current index is " << current_index << " for stream " << stream
<< " and device " << device;
aps_->setStreamVolumeIndex(stream, current_index, device);
PersistVolumeConfiguration(selected_stream_, device, current_index);
TriggerCallback(stream, previous_index, current_index);
}
void AudioVolumeHandler::AdjustVolumeActiveStreams(int direction) {
if (selected_stream_ != AUDIO_STREAM_DEFAULT) {
AdjustStreamVolume(selected_stream_, direction);
return;
}
for (auto stream : kSupportedStreams_) {
if (aps_->isStreamActive(stream)) {
AdjustStreamVolume(stream, direction);
return;
}
}
}
void AudioVolumeHandler::ProcessEvent(const struct input_event& event) {
VLOG(1) << event.type << " " << event.code << " " << event.value;
if (event.type == EV_KEY) {
switch (event.code) {
case KEY_VOLUMEDOWN:
AdjustVolumeActiveStreams(-1);
break;
case KEY_VOLUMEUP:
AdjustVolumeActiveStreams(1);
break;
default:
// This event code is not supported by this handler.
break;
}
}
}
} // namespace brillo