• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <statslog.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_A2DP",       OUTPUT_BLUETOOTH_A2DP },
103         { "AUDIO_DEVICE_OUT_USB_HEADSET",          OUTPUT_USB_HEADSET },
104         { "AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET", OUTPUT_BLUETOOTH_SCO },
105 
106         { "AUDIO_DEVICE_IN_BUILTIN_MIC",           INPUT_BUILTIN_MIC },
107         { "AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET", INPUT_BLUETOOTH_SCO },
108         { "AUDIO_DEVICE_IN_WIRED_HEADSET",         INPUT_WIRED_HEADSET_MIC },
109         { "AUDIO_DEVICE_IN_USB_DEVICE",            INPUT_USB_HEADSET_MIC },
110         { "AUDIO_DEVICE_IN_BACK_MIC",              INPUT_BUILTIN_BACK_MIC },
111     };
112 
113     auto it = deviceTable.find(device_string);
114     if (it == deviceTable.end()) {
115         device = 0;
116         return false;
117     }
118 
119     device = it->second;
120     return true;
121 }
122 
deviceFromStringPairs(const std::string & device_strings)123 int32_t AudioPowerUsage::deviceFromStringPairs(const std::string& device_strings) {
124     int32_t deviceMask = 0;
125     const auto devaddrvec = stringutils::getDeviceAddressPairs(device_strings);
126     for (const auto &[device, addr] : devaddrvec) {
127         int32_t combo_device = 0;
128         deviceFromString(device, combo_device);
129         deviceMask |= combo_device;
130     }
131     return deviceMask;
132 }
133 
sendItem(const std::shared_ptr<const mediametrics::Item> & item) const134 void AudioPowerUsage::sendItem(const std::shared_ptr<const mediametrics::Item>& item) const
135 {
136     int32_t type;
137     if (!item->getInt32(AUDIO_POWER_USAGE_PROP_TYPE, &type)) return;
138 
139     int32_t audio_device;
140     if (!item->getInt32(AUDIO_POWER_USAGE_PROP_DEVICE, &audio_device)) return;
141 
142     int64_t duration_ns;
143     if (!item->getInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, &duration_ns)) return;
144 
145     double volume;
146     if (!item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &volume)) return;
147 
148     int64_t min_volume_duration_ns;
149     if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, &min_volume_duration_ns)) {
150         return;
151     }
152 
153     double min_volume;
154     if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &min_volume)) return;
155 
156     int64_t max_volume_duration_ns;
157     if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, &max_volume_duration_ns)) {
158         return;
159     }
160 
161     double max_volume;
162     if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &max_volume)) return;
163 
164     const int32_t duration_secs = (int32_t)(duration_ns / NANOS_PER_SECOND);
165     const int32_t min_volume_duration_secs = (int32_t)(min_volume_duration_ns / NANOS_PER_SECOND);
166     const int32_t max_volume_duration_secs = (int32_t)(max_volume_duration_ns / NANOS_PER_SECOND);
167     const int result = android::util::stats_write(android::util::AUDIO_POWER_USAGE_DATA_REPORTED,
168                                          audio_device,
169                                          duration_secs,
170                                          (float)volume,
171                                          type,
172                                          min_volume_duration_secs,
173                                          (float)min_volume,
174                                          max_volume_duration_secs,
175                                          (float)max_volume);
176 
177     std::stringstream log;
178     log << "result:" << result << " {"
179             << " mediametrics_audio_power_usage_data_reported:"
180             << android::util::AUDIO_POWER_USAGE_DATA_REPORTED
181             << " audio_device:" << audio_device
182             << " duration_secs:" << duration_secs
183             << " average_volume:" << (float)volume
184             << " type:" << type
185             << " min_volume_duration_secs:" << min_volume_duration_secs
186             << " min_volume:" << (float)min_volume
187             << " max_volume_duration_secs:" << max_volume_duration_secs
188             << " max_volume:" << (float)max_volume
189             << " }";
190     mStatsdLog->log(android::util::AUDIO_POWER_USAGE_DATA_REPORTED, log.str());
191 }
192 
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)193 void AudioPowerUsage::updateMinMaxVolumeAndDuration(
194             const int64_t cur_max_volume_duration_ns, const double cur_max_volume,
195             const int64_t cur_min_volume_duration_ns, const double cur_min_volume,
196             int64_t& f_max_volume_duration_ns, double& f_max_volume,
197             int64_t& f_min_volume_duration_ns, double& f_min_volume)
198 {
199     if (f_min_volume > cur_min_volume) {
200         f_min_volume = cur_min_volume;
201         f_min_volume_duration_ns = cur_min_volume_duration_ns;
202     } else if (f_min_volume == cur_min_volume) {
203         f_min_volume_duration_ns += cur_min_volume_duration_ns;
204     }
205     if (f_max_volume < cur_max_volume) {
206         f_max_volume = cur_max_volume;
207         f_max_volume_duration_ns = cur_max_volume_duration_ns;
208     } else if (f_max_volume == cur_max_volume) {
209         f_max_volume_duration_ns += cur_max_volume_duration_ns;
210     }
211 }
212 
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)213 bool AudioPowerUsage::saveAsItem_l(
214         int32_t device, int64_t duration_ns, int32_t type, double average_vol,
215         int64_t max_volume_duration_ns, double max_volume,
216         int64_t min_volume_duration_ns, double min_volume)
217 {
218     ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
219                                    (long long)duration_ns, average_vol);
220     if (duration_ns == 0) {
221         return true; // skip duration 0 usage
222     }
223     if (device == 0) {
224         return true; //ignore unknown device
225     }
226 
227     for (const auto& item : mItems) {
228         int32_t item_type = 0, item_device = 0;
229         double item_volume = 0.;
230         int64_t item_duration_ns = 0;
231         item->getInt32(AUDIO_POWER_USAGE_PROP_DEVICE, &item_device);
232         item->getInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, &item_duration_ns);
233         item->getInt32(AUDIO_POWER_USAGE_PROP_TYPE, &item_type);
234         item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &item_volume);
235 
236         // aggregate by device and type
237         if (item_device == device && item_type == type) {
238             int64_t final_duration_ns = item_duration_ns + duration_ns;
239             double final_volume = (device & INPUT_DEVICE_BIT) ? 1.0:
240                             ((item_volume * (double)item_duration_ns +
241                             average_vol * (double)duration_ns) / (double)final_duration_ns);
242 
243             item->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, final_duration_ns);
244             item->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, final_volume);
245             item->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
246 
247             // Update the max/min volume and duration
248             int64_t final_min_volume_duration_ns;
249             int64_t final_max_volume_duration_ns;
250             double final_min_volume;
251             double final_max_volume;
252 
253             item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
254                            &final_min_volume_duration_ns);
255             item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &final_min_volume);
256             item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
257                            &final_max_volume_duration_ns);
258             item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &final_max_volume);
259             updateMinMaxVolumeAndDuration(max_volume_duration_ns, max_volume,
260                                           min_volume_duration_ns, min_volume,
261                                           final_max_volume_duration_ns, final_max_volume,
262                                           final_min_volume_duration_ns, final_min_volume);
263             item->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
264                            final_min_volume_duration_ns);
265             item->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, final_min_volume);
266             item->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
267                            final_max_volume_duration_ns);
268             item->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, final_max_volume);
269 
270             ALOGV("%s: update (%#x, %d, %lld, %f) --> (%lld, %f) min(%lld, %f) max(%lld, %f)",
271                   __func__,
272                   device, type,
273                   (long long)item_duration_ns, item_volume,
274                   (long long)final_duration_ns, final_volume,
275                   (long long)final_min_volume_duration_ns, final_min_volume,
276                   (long long)final_max_volume_duration_ns, final_max_volume);
277 
278             return true;
279         }
280     }
281 
282     auto sitem = std::make_shared<mediametrics::Item>(AUDIO_POWER_USAGE_KEY_AUDIO_USAGE);
283     sitem->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
284     sitem->setInt32(AUDIO_POWER_USAGE_PROP_DEVICE, device);
285     sitem->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, duration_ns);
286     sitem->setInt32(AUDIO_POWER_USAGE_PROP_TYPE, type);
287     sitem->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, average_vol);
288     sitem->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, min_volume_duration_ns);
289     sitem->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, min_volume);
290     sitem->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, max_volume_duration_ns);
291     sitem->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, max_volume);
292     mItems.emplace_back(sitem);
293     return true;
294 }
295 
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)296 bool AudioPowerUsage::saveAsItems_l(
297         int32_t device, int64_t duration_ns, int32_t type, double average_vol,
298         int64_t max_volume_duration, double max_volume,
299         int64_t min_volume_duration, double min_volume)
300 {
301     ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
302                                    (long long)duration_ns, average_vol );
303     if (duration_ns == 0) {
304         return true; // skip duration 0 usage
305     }
306     if (device == 0) {
307         return true; //ignore unknown device
308     }
309 
310     bool ret = false;
311     const int32_t input_bit = device & INPUT_DEVICE_BIT;
312     int32_t device_bits = device ^ input_bit;
313 
314     while (device_bits != 0) {
315         int32_t tmp_device = device_bits & -device_bits; // get lowest bit
316         device_bits ^= tmp_device;  // clear lowest bit
317         tmp_device |= input_bit;    // restore input bit
318         ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol,
319                            max_volume_duration, max_volume,
320                            min_volume_duration, min_volume);
321 
322         ALOGV("%s: device %#x recorded, remaining device_bits = %#x", __func__,
323             tmp_device, device_bits);
324     }
325     return ret;
326 }
327 
checkTrackRecord(const std::shared_ptr<const mediametrics::Item> & item,bool isTrack)328 void AudioPowerUsage::checkTrackRecord(
329         const std::shared_ptr<const mediametrics::Item>& item, bool isTrack)
330 {
331     const std::string key = item->getKey();
332 
333     int64_t deviceTimeNs = 0;
334     if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs)) {
335         return;
336     }
337     double deviceVolume = 1.;
338     int64_t maxVolumeDurationNs = 0;
339     double maxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
340     int64_t minVolumeDurationNs = 0;
341     double minVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
342     if (isTrack) {
343         if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume)) {
344             return;
345         }
346         if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, &maxVolumeDurationNs)) {
347             return;
348         }
349         if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, &maxVolume)) {
350             return;
351         }
352         if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, &minVolumeDurationNs)) {
353             return;
354         }
355         if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, &minVolume)) {
356             return;
357         }
358     }
359 
360     int32_t type = 0;
361     std::string type_string;
362     if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
363                key, AMEDIAMETRICS_PROP_STREAMTYPE, &type_string) == OK) ||
364         (!isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
365                key, AMEDIAMETRICS_PROP_SOURCE, &type_string) == OK)) {
366         typeFromString(type_string, type);
367 
368         if (isTrack && type == UNKNOWN_TYPE &&
369                    mAudioAnalytics->mAnalyticsState->timeMachine().get(
370                    key, AMEDIAMETRICS_PROP_USAGE, &type_string) == OK) {
371             typeFromString(type_string, type);
372         }
373         if (isTrack && type == UNKNOWN_TYPE &&
374                    mAudioAnalytics->mAnalyticsState->timeMachine().get(
375                    key, AMEDIAMETRICS_PROP_CONTENTTYPE, &type_string) == OK) {
376             typeFromString(type_string, type);
377         }
378         ALOGV("type = %s => %d", type_string.c_str(), type);
379     }
380 
381     int32_t device = 0;
382     std::string device_strings;
383     if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
384          key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &device_strings) == OK) ||
385         (!isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
386          key, AMEDIAMETRICS_PROP_INPUTDEVICES, &device_strings) == OK)) {
387 
388         device = deviceFromStringPairs(device_strings);
389         ALOGV("device = %s => %d", device_strings.c_str(), device);
390     }
391     std::lock_guard l(mLock);
392     saveAsItems_l(device, deviceTimeNs, type, deviceVolume,
393                   maxVolumeDurationNs, maxVolume, minVolumeDurationNs, minVolume);
394 }
395 
checkMode(const std::shared_ptr<const mediametrics::Item> & item)396 void AudioPowerUsage::checkMode(const std::shared_ptr<const mediametrics::Item>& item)
397 {
398     std::string mode;
399     if (!item->getString(AMEDIAMETRICS_PROP_AUDIOMODE, &mode)) return;
400 
401     std::lock_guard l(mLock);
402     if (mode == mMode) return;  // no change in mode.
403 
404     if (mMode == "AUDIO_MODE_IN_CALL") { // leaving call mode
405         const int64_t endCallNs = item->getTimestamp();
406         const int64_t durationNs = endCallNs - mDeviceTimeNs;
407         const int64_t volumeDurationNs = endCallNs - mVolumeTimeNs;
408         if (durationNs > 0) {
409             mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
410                     mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
411             updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
412                           volumeDurationNs, mVoiceVolume,
413                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
414                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
415             saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
416                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
417                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
418         }
419     } else if (mode == "AUDIO_MODE_IN_CALL") { // entering call mode
420         mStartCallNs = item->getTimestamp(); // advisory only
421 
422         mDeviceVolume = 0;
423         mVolumeTimeNs = mStartCallNs;
424         mDeviceTimeNs = mStartCallNs;
425     }
426     ALOGV("%s: new mode:%s  old mode:%s", __func__, mode.c_str(), mMode.c_str());
427     mMode = mode;
428 }
429 
checkVoiceVolume(const std::shared_ptr<const mediametrics::Item> & item)430 void AudioPowerUsage::checkVoiceVolume(const std::shared_ptr<const mediametrics::Item>& item)
431 {
432     double voiceVolume = 0.;
433     if (!item->getDouble(AMEDIAMETRICS_PROP_VOICEVOLUME, &voiceVolume)) return;
434 
435     std::lock_guard l(mLock);
436     if (voiceVolume == mVoiceVolume) return;  // no change in volume
437 
438     // we only track average device volume when we are in-call
439     if (mMode == "AUDIO_MODE_IN_CALL") {
440         const int64_t timeNs = item->getTimestamp();
441         const int64_t durationNs = timeNs - mDeviceTimeNs;
442         const int64_t volumeDurationNs = timeNs - mVolumeTimeNs;
443         if (durationNs > 0) {
444             mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
445                     mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
446             mVolumeTimeNs = timeNs;
447             updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
448                           volumeDurationNs, mVoiceVolume,
449                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
450                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
451         }
452     }
453     ALOGV("%s: new voice volume:%lf  old voice volume:%lf", __func__, voiceVolume, mVoiceVolume);
454     mVoiceVolume = voiceVolume;
455 }
456 
checkCreatePatch(const std::shared_ptr<const mediametrics::Item> & item)457 void AudioPowerUsage::checkCreatePatch(const std::shared_ptr<const mediametrics::Item>& item)
458 {
459     std::string outputDevices;
460     if (!item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices)) return;
461 
462     const std::string& key = item->getKey();
463     std::string flags;
464     if (mAudioAnalytics->mAnalyticsState->timeMachine().get(
465          key, AMEDIAMETRICS_PROP_FLAGS, &flags) != OK) return;
466 
467     if (flags.find("AUDIO_OUTPUT_FLAG_PRIMARY") == std::string::npos) return;
468 
469     const int32_t device = deviceFromStringPairs(outputDevices);
470 
471     std::lock_guard l(mLock);
472     if (mPrimaryDevice == device) return;
473 
474     if (mMode == "AUDIO_MODE_IN_CALL") {
475         // Save statistics
476         const int64_t endDeviceNs = item->getTimestamp();
477         const int64_t durationNs = endDeviceNs - mDeviceTimeNs;
478         const int64_t volumeDurationNs = endDeviceNs - mVolumeTimeNs;
479         if (durationNs > 0) {
480             mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
481                     mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
482             updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
483                           volumeDurationNs, mVoiceVolume,
484                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
485                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
486             saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
487                           mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
488                           mMinVoiceVolumeDurationNs, mMinVoiceVolume);
489         }
490         // reset statistics
491         mDeviceVolume = 0;
492         mDeviceTimeNs = endDeviceNs;
493         mVolumeTimeNs = endDeviceNs;
494         mMaxVoiceVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
495         mMinVoiceVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
496         mMaxVoiceVolumeDurationNs = 0;
497         mMinVoiceVolumeDurationNs = 0;
498     }
499     ALOGV("%s: new primary device:%#x  old primary device:%#x", __func__, device, mPrimaryDevice);
500     mPrimaryDevice = device;
501 }
502 
AudioPowerUsage(AudioAnalytics * audioAnalytics,const std::shared_ptr<StatsdLog> & statsdLog)503 AudioPowerUsage::AudioPowerUsage(
504         AudioAnalytics *audioAnalytics, const std::shared_ptr<StatsdLog>& statsdLog)
505     : mAudioAnalytics(audioAnalytics)
506     , mStatsdLog(statsdLog)
507     , mDisabled(property_get_bool(PROP_AUDIO_METRICS_DISABLED, AUDIO_METRICS_DISABLED_DEFAULT))
508     , mIntervalHours(property_get_int32(PROP_AUDIO_METRICS_INTERVAL_HR, INTERVAL_HR_DEFAULT))
509 {
510     ALOGD("%s", __func__);
511     ALOGI_IF(mDisabled, "AudioPowerUsage is disabled.");
512     collect(); // send items
513 }
514 
~AudioPowerUsage()515 AudioPowerUsage::~AudioPowerUsage()
516 {
517     ALOGD("%s", __func__);
518 }
519 
clear()520 void AudioPowerUsage::clear()
521 {
522     std::lock_guard _l(mLock);
523     mItems.clear();
524 }
525 
collect()526 void AudioPowerUsage::collect()
527 {
528     std::lock_guard _l(mLock);
529     for (const auto &item : mItems) {
530         sendItem(item);
531     }
532     mItems.clear();
533     mAudioAnalytics->mTimedAction.postIn(
534         mIntervalHours <= 0 ? std::chrono::seconds(5) : std::chrono::hours(mIntervalHours),
535         [this](){ collect(); });
536 }
537 
dump(int limit) const538 std::pair<std::string, int32_t> AudioPowerUsage::dump(int limit) const {
539     if (limit <= 2) {
540         return {{}, 0};
541     }
542     std::lock_guard _l(mLock);
543     if (mDisabled) {
544         return {"AudioPowerUsage disabled\n", 1};
545     }
546     if (mItems.empty()) {
547         return {"AudioPowerUsage empty\n", 1};
548     }
549 
550     int slot = 1;
551     std::stringstream ss;
552     ss << "AudioPowerUsage:\n";
553     for (const auto &item : mItems) {
554         if (slot >= limit - 1) {
555             ss << "-- AudioPowerUsage may be truncated!\n";
556             ++slot;
557             break;
558         }
559         ss << " " << slot << " " << item->toString() << "\n";
560         slot++;
561     }
562     return { ss.str(), slot };
563 }
564 
565 } // namespace android::mediametrics
566