1// Copyright 2016 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15 16// Implementation of audio_volume_handler.h 17 18#include "audio_volume_handler.h" 19 20#include <base/files/file.h> 21#include <base/files/file_util.h> 22#include <base/logging.h> 23#include <brillo/map_utils.h> 24#include <brillo/message_loops/message_loop.h> 25#include <brillo/strings/string_utils.h> 26 27#include "audio_device_handler.h" 28 29namespace brillo { 30 31static const char kVolumeStateFilePath[] = 32 "/data/misc/brilloaudioservice/volume.dat"; 33 34AudioVolumeHandler::AudioVolumeHandler() { 35 for (auto stream : kSupportedStreams_) { 36 step_sizes_.emplace(stream, kDefaultStepSize_); 37 } 38 selected_stream_ = AUDIO_STREAM_DEFAULT; 39 volume_state_file_ = base::FilePath(kVolumeStateFilePath); 40} 41 42AudioVolumeHandler::~AudioVolumeHandler() {} 43 44void AudioVolumeHandler::APSDisconnect() { aps_.clear(); } 45 46void AudioVolumeHandler::APSConnect( 47 android::sp<android::IAudioPolicyService> aps) { 48 aps_ = aps; 49 InitAPSAllStreams(); 50} 51 52void AudioVolumeHandler::RegisterCallback( 53 base::Callback<void(audio_stream_type_t, int, int)>& callback) { 54 callback_ = callback; 55} 56 57int AudioVolumeHandler::ConvertToUserDefinedIndex(audio_stream_type_t stream, 58 int index) { 59 return index / step_sizes_[stream]; 60} 61 62int AudioVolumeHandler::ConvertToInternalIndex(audio_stream_type_t stream, 63 int index) { 64 return index * step_sizes_[stream]; 65} 66 67void AudioVolumeHandler::TriggerCallback(audio_stream_type_t stream, 68 int previous_index, 69 int current_index) { 70 int user_defined_previous_index = 71 ConvertToUserDefinedIndex(stream, previous_index); 72 int user_defined_current_index = 73 ConvertToUserDefinedIndex(stream, current_index); 74 MessageLoop::current()->PostTask(base::Bind(callback_, 75 stream, 76 user_defined_previous_index, 77 user_defined_current_index)); 78} 79 80void AudioVolumeHandler::GenerateVolumeFile() { 81 for (auto stream : kSupportedStreams_) { 82 for (auto device : AudioDeviceHandler::kSupportedOutputDevices_) { 83 PersistVolumeConfiguration(stream, device, kDefaultCurrentIndex_); 84 } 85 } 86 if (!kv_store_->Save(volume_state_file_)) { 87 LOG(ERROR) << "Could not save volume data file!"; 88 } 89} 90 91int AudioVolumeHandler::GetVolumeMaxSteps(audio_stream_type_t stream) { 92 return ConvertToUserDefinedIndex(stream, kMaxIndex_); 93} 94 95int AudioVolumeHandler::SetVolumeMaxSteps(audio_stream_type_t stream, 96 int max_steps) { 97 if (max_steps <= kMinIndex_ || max_steps > kMaxIndex_) 98 return EINVAL; 99 step_sizes_[stream] = kMaxIndex_ / max_steps; 100 return 0; 101} 102 103int AudioVolumeHandler::GetVolumeCurrentIndex(audio_stream_type_t stream, 104 audio_devices_t device) { 105 auto key = kCurrentIndexKey_ + "." + string_utils::ToString(stream) + "." + 106 string_utils::ToString(device); 107 std::string value; 108 kv_store_->GetString(key, &value); 109 return std::stoi(value); 110} 111 112int AudioVolumeHandler::GetVolumeIndex(audio_stream_type_t stream, 113 audio_devices_t device) { 114 return ConvertToUserDefinedIndex(stream, 115 GetVolumeCurrentIndex(stream, device)); 116} 117 118int AudioVolumeHandler::SetVolumeIndex(audio_stream_type_t stream, 119 audio_devices_t device, 120 int index) { 121 if (index < kMinIndex_ || 122 index > ConvertToUserDefinedIndex(stream, kMaxIndex_)) 123 return EINVAL; 124 int previous_index = GetVolumeCurrentIndex(stream, device); 125 int current_absolute_index = ConvertToInternalIndex(stream, index); 126 PersistVolumeConfiguration(stream, device, current_absolute_index); 127 TriggerCallback(stream, previous_index, current_absolute_index); 128 return 0; 129} 130 131void AudioVolumeHandler::PersistVolumeConfiguration(audio_stream_type_t stream, 132 audio_devices_t device, 133 int index) { 134 auto key = kCurrentIndexKey_ + "." + string_utils::ToString(stream) + "." + 135 string_utils::ToString(device); 136 kv_store_->SetString(key, string_utils::ToString(index)); 137 kv_store_->Save(volume_state_file_); 138} 139 140void AudioVolumeHandler::InitAPSAllStreams() { 141 for (auto stream : kSupportedStreams_) { 142 aps_->initStreamVolume(stream, kMinIndex_, kMaxIndex_); 143 for (auto device : AudioDeviceHandler::kSupportedOutputDevices_) { 144 int current_index = GetVolumeCurrentIndex(stream, device); 145 aps_->setStreamVolumeIndex(stream, current_index, device); 146 } 147 } 148} 149 150void AudioVolumeHandler::SetVolumeFilePathForTesting( 151 const base::FilePath& path) { 152 volume_state_file_ = path; 153} 154 155void AudioVolumeHandler::Init(android::sp<android::IAudioPolicyService> aps) { 156 aps_ = aps; 157 kv_store_ = std::unique_ptr<KeyValueStore>(new KeyValueStore()); 158 if (!base::PathExists(volume_state_file_)) { 159 // Generate key-value store and save it to a file. 160 GenerateVolumeFile(); 161 } else { 162 // Load the file. If loading fails, generate the file. 163 if (!kv_store_->Load(volume_state_file_)) { 164 LOG(ERROR) << "Could not load volume data file!"; 165 GenerateVolumeFile(); 166 } 167 } 168 // Inform APS. 169 InitAPSAllStreams(); 170} 171 172audio_stream_type_t AudioVolumeHandler::GetVolumeControlStream() { 173 return selected_stream_; 174} 175 176void AudioVolumeHandler::SetVolumeControlStream(audio_stream_type_t stream) { 177 selected_stream_ = stream; 178} 179 180int AudioVolumeHandler::GetNewVolumeIndex(int previous_index, int direction, 181 audio_stream_type_t stream) { 182 int current_index = 183 previous_index + ConvertToInternalIndex(stream, direction); 184 if (current_index < kMinIndex_) { 185 return kMinIndex_; 186 } else if (current_index > kMaxIndex_) { 187 return kMaxIndex_; 188 } else 189 return current_index; 190} 191 192void AudioVolumeHandler::AdjustStreamVolume(audio_stream_type_t stream, 193 int direction) { 194 VLOG(1) << "Adjusting volume of stream " << selected_stream_ 195 << " in direction " << direction; 196 auto device = aps_->getDevicesForStream(stream); 197 int previous_index = GetVolumeCurrentIndex(stream, device); 198 int current_index = GetNewVolumeIndex(previous_index, direction, stream); 199 VLOG(1) << "Current index is " << current_index << " for stream " << stream 200 << " and device " << device; 201 aps_->setStreamVolumeIndex(stream, current_index, device); 202 PersistVolumeConfiguration(selected_stream_, device, current_index); 203 TriggerCallback(stream, previous_index, current_index); 204} 205 206void AudioVolumeHandler::AdjustVolumeActiveStreams(int direction) { 207 if (selected_stream_ != AUDIO_STREAM_DEFAULT) { 208 AdjustStreamVolume(selected_stream_, direction); 209 return; 210 } 211 for (auto stream : kSupportedStreams_) { 212 if (aps_->isStreamActive(stream)) { 213 AdjustStreamVolume(stream, direction); 214 return; 215 } 216 } 217} 218 219void AudioVolumeHandler::ProcessEvent(const struct input_event& event) { 220 VLOG(1) << event.type << " " << event.code << " " << event.value; 221 if (event.type == EV_KEY) { 222 switch (event.code) { 223 case KEY_VOLUMEDOWN: 224 AdjustVolumeActiveStreams(-1); 225 break; 226 case KEY_VOLUMEUP: 227 AdjustVolumeActiveStreams(1); 228 break; 229 default: 230 // This event code is not supported by this handler. 231 break; 232 } 233 } 234} 235 236} // namespace brillo 237