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