// 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