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
29 namespace brillo {
30
31 static const char kVolumeStateFilePath[] =
32 "/data/misc/brilloaudioservice/volume.dat";
33
AudioVolumeHandler()34 AudioVolumeHandler::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
~AudioVolumeHandler()42 AudioVolumeHandler::~AudioVolumeHandler() {}
43
APSDisconnect()44 void AudioVolumeHandler::APSDisconnect() { aps_.clear(); }
45
APSConnect(android::sp<android::IAudioPolicyService> aps)46 void AudioVolumeHandler::APSConnect(
47 android::sp<android::IAudioPolicyService> aps) {
48 aps_ = aps;
49 InitAPSAllStreams();
50 }
51
RegisterCallback(base::Callback<void (audio_stream_type_t,int,int)> & callback)52 void AudioVolumeHandler::RegisterCallback(
53 base::Callback<void(audio_stream_type_t, int, int)>& callback) {
54 callback_ = callback;
55 }
56
ConvertToUserDefinedIndex(audio_stream_type_t stream,int index)57 int AudioVolumeHandler::ConvertToUserDefinedIndex(audio_stream_type_t stream,
58 int index) {
59 return index / step_sizes_[stream];
60 }
61
ConvertToInternalIndex(audio_stream_type_t stream,int index)62 int AudioVolumeHandler::ConvertToInternalIndex(audio_stream_type_t stream,
63 int index) {
64 return index * step_sizes_[stream];
65 }
66
TriggerCallback(audio_stream_type_t stream,int previous_index,int current_index)67 void 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
GenerateVolumeFile()80 void 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
GetVolumeMaxSteps(audio_stream_type_t stream)91 int AudioVolumeHandler::GetVolumeMaxSteps(audio_stream_type_t stream) {
92 return ConvertToUserDefinedIndex(stream, kMaxIndex_);
93 }
94
SetVolumeMaxSteps(audio_stream_type_t stream,int max_steps)95 int 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
GetVolumeCurrentIndex(audio_stream_type_t stream,audio_devices_t device)103 int 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
GetVolumeIndex(audio_stream_type_t stream,audio_devices_t device)112 int AudioVolumeHandler::GetVolumeIndex(audio_stream_type_t stream,
113 audio_devices_t device) {
114 return ConvertToUserDefinedIndex(stream,
115 GetVolumeCurrentIndex(stream, device));
116 }
117
SetVolumeIndex(audio_stream_type_t stream,audio_devices_t device,int index)118 int 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
PersistVolumeConfiguration(audio_stream_type_t stream,audio_devices_t device,int index)131 void 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
InitAPSAllStreams()140 void 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
SetVolumeFilePathForTesting(const base::FilePath & path)150 void AudioVolumeHandler::SetVolumeFilePathForTesting(
151 const base::FilePath& path) {
152 volume_state_file_ = path;
153 }
154
Init(android::sp<android::IAudioPolicyService> aps)155 void 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
GetVolumeControlStream()172 audio_stream_type_t AudioVolumeHandler::GetVolumeControlStream() {
173 return selected_stream_;
174 }
175
SetVolumeControlStream(audio_stream_type_t stream)176 void AudioVolumeHandler::SetVolumeControlStream(audio_stream_type_t stream) {
177 selected_stream_ = stream;
178 }
179
GetNewVolumeIndex(int previous_index,int direction,audio_stream_type_t stream)180 int 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
AdjustStreamVolume(audio_stream_type_t stream,int direction)192 void 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
AdjustVolumeActiveStreams(int direction)206 void 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
ProcessEvent(const struct input_event & event)219 void 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