1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "AudioPowerUsage"
19 #include <utils/Log.h>
20
21 #include "AudioAnalytics.h"
22 #include "MediaMetricsService.h"
23 #include "StringUtils.h"
24 #include <map>
25 #include <sstream>
26 #include <string>
27 #include <audio_utils/clock.h>
28 #include <cutils/properties.h>
29 #include <stats_media_metrics.h>
30 #include <sys/timerfd.h>
31 #include <system/audio.h>
32
33 // property to disable audio power use metrics feature, default is enabled
34 #define PROP_AUDIO_METRICS_DISABLED "persist.media.audio_metrics.power_usage_disabled"
35 #define AUDIO_METRICS_DISABLED_DEFAULT (false)
36
37 // property to set how long to send audio power use metrics data to statsd, default is 24hrs
38 #define PROP_AUDIO_METRICS_INTERVAL_HR "persist.media.audio_metrics.interval_hr"
39 #define INTERVAL_HR_DEFAULT (24)
40
41 // for Audio Power Usage Metrics
42 #define AUDIO_POWER_USAGE_KEY_AUDIO_USAGE "audio.power.usage"
43
44 #define AUDIO_POWER_USAGE_PROP_DEVICE "device" // int32
45 #define AUDIO_POWER_USAGE_PROP_DURATION_NS "durationNs" // int64
46 #define AUDIO_POWER_USAGE_PROP_TYPE "type" // int32
47 #define AUDIO_POWER_USAGE_PROP_VOLUME "volume" // double
48 #define AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS "minVolumeDurationNs" // int64
49 #define AUDIO_POWER_USAGE_PROP_MIN_VOLUME "minVolume" // double
50 #define AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS "maxVolumeDurationNs" // int64
51 #define AUDIO_POWER_USAGE_PROP_MAX_VOLUME "maxVolume" // double
52
53 namespace android::mediametrics {
54
55 /* static */
typeFromString(const std::string & type_string,int32_t & type)56 bool AudioPowerUsage::typeFromString(const std::string& type_string, int32_t& type) {
57 static std::map<std::string, int32_t> typeTable = {
58 { "AUDIO_STREAM_VOICE_CALL", VOIP_CALL_TYPE },
59 { "AUDIO_STREAM_SYSTEM", MEDIA_TYPE },
60 { "AUDIO_STREAM_RING", RINGTONE_NOTIFICATION_TYPE },
61 { "AUDIO_STREAM_MUSIC", MEDIA_TYPE },
62 { "AUDIO_STREAM_ALARM", ALARM_TYPE },
63 { "AUDIO_STREAM_NOTIFICATION", RINGTONE_NOTIFICATION_TYPE },
64
65 { "AUDIO_CONTENT_TYPE_SPEECH", VOIP_CALL_TYPE },
66 { "AUDIO_CONTENT_TYPE_MUSIC", MEDIA_TYPE },
67 { "AUDIO_CONTENT_TYPE_MOVIE", MEDIA_TYPE },
68 { "AUDIO_CONTENT_TYPE_SONIFICATION", RINGTONE_NOTIFICATION_TYPE },
69
70 { "AUDIO_USAGE_MEDIA", MEDIA_TYPE },
71 { "AUDIO_USAGE_VOICE_COMMUNICATION", VOIP_CALL_TYPE },
72 { "AUDIO_USAGE_ALARM", ALARM_TYPE },
73 { "AUDIO_USAGE_NOTIFICATION", RINGTONE_NOTIFICATION_TYPE },
74
75 { "AUDIO_SOURCE_CAMCORDER", CAMCORDER_TYPE },
76 { "AUDIO_SOURCE_VOICE_COMMUNICATION", VOIP_CALL_TYPE },
77 { "AUDIO_SOURCE_DEFAULT", RECORD_TYPE },
78 { "AUDIO_SOURCE_MIC", RECORD_TYPE },
79 { "AUDIO_SOURCE_UNPROCESSED", RECORD_TYPE },
80 { "AUDIO_SOURCE_VOICE_RECOGNITION", RECORD_TYPE },
81 };
82
83 auto it = typeTable.find(type_string);
84 if (it == typeTable.end()) {
85 type = UNKNOWN_TYPE;
86 return false;
87 }
88
89 type = it->second;
90 return true;
91 }
92
93 /* static */
deviceFromString(const std::string & device_string,int32_t & device)94 bool AudioPowerUsage::deviceFromString(const std::string& device_string, int32_t& device) {
95 static std::map<std::string, int32_t> deviceTable = {
96 { "AUDIO_DEVICE_OUT_EARPIECE", OUTPUT_EARPIECE },
97 { "AUDIO_DEVICE_OUT_SPEAKER_SAFE", OUTPUT_SPEAKER_SAFE },
98 { "AUDIO_DEVICE_OUT_SPEAKER", OUTPUT_SPEAKER },
99 { "AUDIO_DEVICE_OUT_WIRED_HEADSET", OUTPUT_WIRED_HEADSET },
100 { "AUDIO_DEVICE_OUT_WIRED_HEADPHONE", OUTPUT_WIRED_HEADSET },
101 { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO", OUTPUT_BLUETOOTH_SCO },
102 { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET", OUTPUT_BLUETOOTH_SCO },
103 { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP", OUTPUT_BLUETOOTH_A2DP },
104 { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES", OUTPUT_BLUETOOTH_A2DP },
105 { "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER", OUTPUT_BLUETOOTH_A2DP },
106 { "AUDIO_DEVICE_OUT_BLE_HEADSET", OUTPUT_BLUETOOTH_BLE },
107 { "AUDIO_DEVICE_OUT_BLE_SPEAKER", OUTPUT_BLUETOOTH_BLE },
108 { "AUDIO_DEVICE_OUT_BLE_BROADCAST", OUTPUT_BLUETOOTH_BLE },
109 { "AUDIO_DEVICE_OUT_USB_HEADSET", OUTPUT_USB_HEADSET },
110 { "AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET", OUTPUT_DOCK },
111 { "AUDIO_DEVICE_OUT_HDMI", OUTPUT_HDMI },
112
113 { "AUDIO_DEVICE_IN_BUILTIN_MIC", INPUT_BUILTIN_MIC },
114 { "AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET", INPUT_BLUETOOTH_SCO },
115 { "AUDIO_DEVICE_IN_BLUETOOTH_BLE", INPUT_BLUETOOTH_BLE },
116 { "AUDIO_DEVICE_IN_BLE_HEADSET", INPUT_BLUETOOTH_BLE },
117 { "AUDIO_DEVICE_IN_WIRED_HEADSET", INPUT_WIRED_HEADSET_MIC },
118 { "AUDIO_DEVICE_IN_USB_DEVICE", INPUT_USB_HEADSET_MIC },
119 { "AUDIO_DEVICE_IN_BACK_MIC", INPUT_BUILTIN_BACK_MIC },
120 };
121
122 auto it = deviceTable.find(device_string);
123 if (it == deviceTable.end()) {
124 device = 0;
125 return false;
126 }
127
128 device = it->second;
129 return true;
130 }
131
deviceFromStringPairs(const std::string & device_strings)132 int32_t AudioPowerUsage::deviceFromStringPairs(const std::string& device_strings) {
133 int32_t deviceMask = 0;
134 const auto devaddrvec = stringutils::getDeviceAddressPairs(device_strings);
135 for (const auto &[device, addr] : devaddrvec) {
136 int32_t combo_device = 0;
137 deviceFromString(device, combo_device);
138 deviceMask |= combo_device;
139 }
140 return deviceMask;
141 }
142
sendItem(const std::shared_ptr<const mediametrics::Item> & item) const143 void AudioPowerUsage::sendItem(const std::shared_ptr<const mediametrics::Item>& item) const
144 {
145 int32_t type;
146 if (!item->getInt32(AUDIO_POWER_USAGE_PROP_TYPE, &type)) return;
147
148 int32_t audio_device;
149 if (!item->getInt32(AUDIO_POWER_USAGE_PROP_DEVICE, &audio_device)) return;
150
151 int64_t duration_ns;
152 if (!item->getInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, &duration_ns)) return;
153
154 double volume;
155 if (!item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &volume)) return;
156
157 int64_t min_volume_duration_ns;
158 if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, &min_volume_duration_ns)) {
159 return;
160 }
161
162 double min_volume;
163 if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &min_volume)) return;
164
165 int64_t max_volume_duration_ns;
166 if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, &max_volume_duration_ns)) {
167 return;
168 }
169
170 double max_volume;
171 if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &max_volume)) return;
172
173 const int32_t duration_secs = (int32_t)(duration_ns / NANOS_PER_SECOND);
174 const int32_t min_volume_duration_secs = (int32_t)(min_volume_duration_ns / NANOS_PER_SECOND);
175 const int32_t max_volume_duration_secs = (int32_t)(max_volume_duration_ns / NANOS_PER_SECOND);
176 const int result = stats::media_metrics::stats_write(stats::media_metrics::AUDIO_POWER_USAGE_DATA_REPORTED,
177 audio_device,
178 duration_secs,
179 (float)volume,
180 type,
181 min_volume_duration_secs,
182 (float)min_volume,
183 max_volume_duration_secs,
184 (float)max_volume);
185
186 std::stringstream log;
187 log << "result:" << result << " {"
188 << " mediametrics_audio_power_usage_data_reported:"
189 << stats::media_metrics::AUDIO_POWER_USAGE_DATA_REPORTED
190 << " audio_device:" << audio_device
191 << " duration_secs:" << duration_secs
192 << " average_volume:" << (float)volume
193 << " type:" << type
194 << " min_volume_duration_secs:" << min_volume_duration_secs
195 << " min_volume:" << (float)min_volume
196 << " max_volume_duration_secs:" << max_volume_duration_secs
197 << " max_volume:" << (float)max_volume
198 << " }";
199 mStatsdLog->log(stats::media_metrics::AUDIO_POWER_USAGE_DATA_REPORTED, log.str());
200 }
201
updateMinMaxVolumeAndDuration(const int64_t cur_max_volume_duration_ns,const double cur_max_volume,const int64_t cur_min_volume_duration_ns,const double cur_min_volume,int64_t & f_max_volume_duration_ns,double & f_max_volume,int64_t & f_min_volume_duration_ns,double & f_min_volume)202 void AudioPowerUsage::updateMinMaxVolumeAndDuration(
203 const int64_t cur_max_volume_duration_ns, const double cur_max_volume,
204 const int64_t cur_min_volume_duration_ns, const double cur_min_volume,
205 int64_t& f_max_volume_duration_ns, double& f_max_volume,
206 int64_t& f_min_volume_duration_ns, double& f_min_volume)
207 {
208 if (f_min_volume > cur_min_volume) {
209 f_min_volume = cur_min_volume;
210 f_min_volume_duration_ns = cur_min_volume_duration_ns;
211 } else if (f_min_volume == cur_min_volume) {
212 f_min_volume_duration_ns += cur_min_volume_duration_ns;
213 }
214 if (f_max_volume < cur_max_volume) {
215 f_max_volume = cur_max_volume;
216 f_max_volume_duration_ns = cur_max_volume_duration_ns;
217 } else if (f_max_volume == cur_max_volume) {
218 f_max_volume_duration_ns += cur_max_volume_duration_ns;
219 }
220 }
221
saveAsItem_l(int32_t device,int64_t duration_ns,int32_t type,double average_vol,int64_t max_volume_duration_ns,double max_volume,int64_t min_volume_duration_ns,double min_volume)222 bool AudioPowerUsage::saveAsItem_l(
223 int32_t device, int64_t duration_ns, int32_t type, double average_vol,
224 int64_t max_volume_duration_ns, double max_volume,
225 int64_t min_volume_duration_ns, double min_volume)
226 {
227 ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
228 (long long)duration_ns, average_vol);
229 if (duration_ns == 0) {
230 return true; // skip duration 0 usage
231 }
232 if (device == 0) {
233 return true; //ignore unknown device
234 }
235
236 for (const auto& item : mItems) {
237 int32_t item_type = 0, item_device = 0;
238 double item_volume = 0.;
239 int64_t item_duration_ns = 0;
240 item->getInt32(AUDIO_POWER_USAGE_PROP_DEVICE, &item_device);
241 item->getInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, &item_duration_ns);
242 item->getInt32(AUDIO_POWER_USAGE_PROP_TYPE, &item_type);
243 item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &item_volume);
244
245 // aggregate by device and type
246 if (item_device == device && item_type == type) {
247 int64_t final_duration_ns = item_duration_ns + duration_ns;
248 double final_volume = (device & INPUT_DEVICE_BIT) ? 1.0:
249 ((item_volume * (double)item_duration_ns +
250 average_vol * (double)duration_ns) / (double)final_duration_ns);
251
252 item->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, final_duration_ns);
253 item->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, final_volume);
254 item->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
255
256 // Update the max/min volume and duration
257 int64_t final_min_volume_duration_ns;
258 int64_t final_max_volume_duration_ns;
259 double final_min_volume;
260 double final_max_volume;
261
262 item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
263 &final_min_volume_duration_ns);
264 item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &final_min_volume);
265 item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
266 &final_max_volume_duration_ns);
267 item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &final_max_volume);
268 updateMinMaxVolumeAndDuration(max_volume_duration_ns, max_volume,
269 min_volume_duration_ns, min_volume,
270 final_max_volume_duration_ns, final_max_volume,
271 final_min_volume_duration_ns, final_min_volume);
272 item->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
273 final_min_volume_duration_ns);
274 item->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, final_min_volume);
275 item->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
276 final_max_volume_duration_ns);
277 item->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, final_max_volume);
278
279 ALOGV("%s: update (%#x, %d, %lld, %f) --> (%lld, %f) min(%lld, %f) max(%lld, %f)",
280 __func__,
281 device, type,
282 (long long)item_duration_ns, item_volume,
283 (long long)final_duration_ns, final_volume,
284 (long long)final_min_volume_duration_ns, final_min_volume,
285 (long long)final_max_volume_duration_ns, final_max_volume);
286
287 return true;
288 }
289 }
290
291 auto sitem = std::make_shared<mediametrics::Item>(AUDIO_POWER_USAGE_KEY_AUDIO_USAGE);
292 sitem->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
293 sitem->setInt32(AUDIO_POWER_USAGE_PROP_DEVICE, device);
294 sitem->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, duration_ns);
295 sitem->setInt32(AUDIO_POWER_USAGE_PROP_TYPE, type);
296 sitem->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, average_vol);
297 sitem->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, min_volume_duration_ns);
298 sitem->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, min_volume);
299 sitem->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, max_volume_duration_ns);
300 sitem->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, max_volume);
301 mItems.emplace_back(sitem);
302 return true;
303 }
304
saveAsItems_l(int32_t device,int64_t duration_ns,int32_t type,double average_vol,int64_t max_volume_duration,double max_volume,int64_t min_volume_duration,double min_volume)305 bool AudioPowerUsage::saveAsItems_l(
306 int32_t device, int64_t duration_ns, int32_t type, double average_vol,
307 int64_t max_volume_duration, double max_volume,
308 int64_t min_volume_duration, double min_volume)
309 {
310 ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
311 (long long)duration_ns, average_vol );
312 if (duration_ns == 0) {
313 return true; // skip duration 0 usage
314 }
315 if (device == 0) {
316 return true; //ignore unknown device
317 }
318
319 bool ret = false;
320 const int32_t input_bit = device & INPUT_DEVICE_BIT;
321 int32_t device_bits = device ^ input_bit;
322
323 while (device_bits != 0) {
324 int32_t tmp_device = device_bits & -device_bits; // get lowest bit
325 device_bits ^= tmp_device; // clear lowest bit
326 tmp_device |= input_bit; // restore input bit
327 ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol,
328 max_volume_duration, max_volume,
329 min_volume_duration, min_volume);
330
331 ALOGV("%s: device %#x recorded, remaining device_bits = %#x", __func__,
332 tmp_device, device_bits);
333 }
334 return ret;
335 }
336
checkTrackRecord(const std::shared_ptr<const mediametrics::Item> & item,bool isTrack)337 void AudioPowerUsage::checkTrackRecord(
338 const std::shared_ptr<const mediametrics::Item>& item, bool isTrack)
339 {
340 const std::string key = item->getKey();
341
342 int64_t deviceTimeNs = 0;
343 if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs)) {
344 return;
345 }
346 double deviceVolume = 1.;
347 int64_t maxVolumeDurationNs = 0;
348 double maxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
349 int64_t minVolumeDurationNs = 0;
350 double minVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
351 if (isTrack) {
352 if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume)) {
353 return;
354 }
355 if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, &maxVolumeDurationNs)) {
356 return;
357 }
358 if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, &maxVolume)) {
359 return;
360 }
361 if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, &minVolumeDurationNs)) {
362 return;
363 }
364 if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, &minVolume)) {
365 return;
366 }
367 }
368
369 int32_t type = 0;
370 std::string type_string;
371 if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
372 key, AMEDIAMETRICS_PROP_STREAMTYPE, &type_string) == OK) ||
373 (!isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
374 key, AMEDIAMETRICS_PROP_SOURCE, &type_string) == OK)) {
375 typeFromString(type_string, type);
376
377 if (isTrack && type == UNKNOWN_TYPE &&
378 mAudioAnalytics->mAnalyticsState->timeMachine().get(
379 key, AMEDIAMETRICS_PROP_USAGE, &type_string) == OK) {
380 typeFromString(type_string, type);
381 }
382 if (isTrack && type == UNKNOWN_TYPE &&
383 mAudioAnalytics->mAnalyticsState->timeMachine().get(
384 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &type_string) == OK) {
385 typeFromString(type_string, type);
386 }
387 ALOGV("type = %s => %d", type_string.c_str(), type);
388 }
389
390 int32_t device = 0;
391 std::string device_strings;
392 if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
393 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &device_strings) == OK) ||
394 (!isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
395 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &device_strings) == OK)) {
396
397 device = deviceFromStringPairs(device_strings);
398 ALOGV("device = %s => %d", device_strings.c_str(), device);
399 }
400 std::lock_guard l(mLock);
401 saveAsItems_l(device, deviceTimeNs, type, deviceVolume,
402 maxVolumeDurationNs, maxVolume, minVolumeDurationNs, minVolume);
403 }
404
checkMode(const std::shared_ptr<const mediametrics::Item> & item)405 void AudioPowerUsage::checkMode(const std::shared_ptr<const mediametrics::Item>& item)
406 {
407 std::string mode;
408 if (!item->getString(AMEDIAMETRICS_PROP_AUDIOMODE, &mode)) return;
409
410 std::lock_guard l(mLock);
411 if (mode == mMode) return; // no change in mode.
412
413 if (mMode == "AUDIO_MODE_IN_CALL") { // leaving call mode
414 const int64_t endCallNs = item->getTimestamp();
415 const int64_t durationNs = endCallNs - mDeviceTimeNs;
416 const int64_t volumeDurationNs = endCallNs - mVolumeTimeNs;
417 if (durationNs > 0) {
418 mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
419 mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
420 updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
421 volumeDurationNs, mVoiceVolume,
422 mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
423 mMinVoiceVolumeDurationNs, mMinVoiceVolume);
424 saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
425 mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
426 mMinVoiceVolumeDurationNs, mMinVoiceVolume);
427 }
428 } else if (mode == "AUDIO_MODE_IN_CALL") { // entering call mode
429 mStartCallNs = item->getTimestamp(); // advisory only
430
431 mDeviceVolume = 0;
432 mVolumeTimeNs = mStartCallNs;
433 mDeviceTimeNs = mStartCallNs;
434 }
435 ALOGV("%s: new mode:%s old mode:%s", __func__, mode.c_str(), mMode.c_str());
436 mMode = mode;
437 }
438
checkVoiceVolume(const std::shared_ptr<const mediametrics::Item> & item)439 void AudioPowerUsage::checkVoiceVolume(const std::shared_ptr<const mediametrics::Item>& item)
440 {
441 double voiceVolume = 0.;
442 if (!item->getDouble(AMEDIAMETRICS_PROP_VOICEVOLUME, &voiceVolume)) return;
443
444 std::lock_guard l(mLock);
445 if (voiceVolume == mVoiceVolume) return; // no change in volume
446
447 // we only track average device volume when we are in-call
448 if (mMode == "AUDIO_MODE_IN_CALL") {
449 const int64_t timeNs = item->getTimestamp();
450 const int64_t durationNs = timeNs - mDeviceTimeNs;
451 const int64_t volumeDurationNs = timeNs - mVolumeTimeNs;
452 if (durationNs > 0) {
453 mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
454 mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
455 mVolumeTimeNs = timeNs;
456 updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
457 volumeDurationNs, mVoiceVolume,
458 mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
459 mMinVoiceVolumeDurationNs, mMinVoiceVolume);
460 }
461 }
462 ALOGV("%s: new voice volume:%lf old voice volume:%lf", __func__, voiceVolume, mVoiceVolume);
463 mVoiceVolume = voiceVolume;
464 }
465
checkCreatePatch(const std::shared_ptr<const mediametrics::Item> & item)466 void AudioPowerUsage::checkCreatePatch(const std::shared_ptr<const mediametrics::Item>& item)
467 {
468 std::string outputDevices;
469 if (!item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices)) return;
470
471 const std::string& key = item->getKey();
472 std::string flags;
473 if (mAudioAnalytics->mAnalyticsState->timeMachine().get(
474 key, AMEDIAMETRICS_PROP_FLAGS, &flags) != OK) return;
475
476 if (flags.find("AUDIO_OUTPUT_FLAG_PRIMARY") == std::string::npos) return;
477
478 const int32_t device = deviceFromStringPairs(outputDevices);
479
480 std::lock_guard l(mLock);
481 if (mPrimaryDevice == device) return;
482
483 if (mMode == "AUDIO_MODE_IN_CALL") {
484 // Save statistics
485 const int64_t endDeviceNs = item->getTimestamp();
486 const int64_t durationNs = endDeviceNs - mDeviceTimeNs;
487 const int64_t volumeDurationNs = endDeviceNs - mVolumeTimeNs;
488 if (durationNs > 0) {
489 mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
490 mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
491 updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
492 volumeDurationNs, mVoiceVolume,
493 mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
494 mMinVoiceVolumeDurationNs, mMinVoiceVolume);
495 saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
496 mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
497 mMinVoiceVolumeDurationNs, mMinVoiceVolume);
498 }
499 // reset statistics
500 mDeviceVolume = 0;
501 mDeviceTimeNs = endDeviceNs;
502 mVolumeTimeNs = endDeviceNs;
503 mMaxVoiceVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
504 mMinVoiceVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
505 mMaxVoiceVolumeDurationNs = 0;
506 mMinVoiceVolumeDurationNs = 0;
507 }
508 ALOGV("%s: new primary device:%#x old primary device:%#x", __func__, device, mPrimaryDevice);
509 mPrimaryDevice = device;
510 }
511
AudioPowerUsage(AudioAnalytics * audioAnalytics,const std::shared_ptr<StatsdLog> & statsdLog)512 AudioPowerUsage::AudioPowerUsage(
513 AudioAnalytics *audioAnalytics, const std::shared_ptr<StatsdLog>& statsdLog)
514 : mAudioAnalytics(audioAnalytics)
515 , mStatsdLog(statsdLog)
516 , mDisabled(property_get_bool(PROP_AUDIO_METRICS_DISABLED, AUDIO_METRICS_DISABLED_DEFAULT))
517 , mIntervalHours(property_get_int32(PROP_AUDIO_METRICS_INTERVAL_HR, INTERVAL_HR_DEFAULT))
518 {
519 ALOGD("%s", __func__);
520 ALOGI_IF(mDisabled, "AudioPowerUsage is disabled.");
521 collect(); // send items
522 }
523
~AudioPowerUsage()524 AudioPowerUsage::~AudioPowerUsage()
525 {
526 ALOGD("%s", __func__);
527 }
528
clear()529 void AudioPowerUsage::clear()
530 {
531 std::lock_guard _l(mLock);
532 mItems.clear();
533 }
534
collect()535 void AudioPowerUsage::collect()
536 {
537 std::lock_guard _l(mLock);
538 for (const auto &item : mItems) {
539 sendItem(item);
540 }
541 mItems.clear();
542 mAudioAnalytics->mTimedAction.postIn(
543 mIntervalHours <= 0 ? std::chrono::seconds(5) : std::chrono::hours(mIntervalHours),
544 [this](){ collect(); });
545 }
546
dump(int limit) const547 std::pair<std::string, int32_t> AudioPowerUsage::dump(int limit) const {
548 if (limit <= 2) {
549 return {{}, 0};
550 }
551 std::lock_guard _l(mLock);
552 if (mDisabled) {
553 return {"AudioPowerUsage disabled\n", 1};
554 }
555 if (mItems.empty()) {
556 return {"AudioPowerUsage empty\n", 1};
557 }
558
559 int slot = 1;
560 std::stringstream ss;
561 ss << "AudioPowerUsage interval " << mIntervalHours << " hours:\n";
562 for (const auto &item : mItems) {
563 if (slot >= limit - 1) {
564 ss << "-- AudioPowerUsage may be truncated!\n";
565 ++slot;
566 break;
567 }
568 ss << " " << slot << " " << item->toString() << "\n";
569 slot++;
570 }
571 return { ss.str(), slot };
572 }
573
574 } // namespace android::mediametrics
575