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