blob: 30d69ab61dc56ff64c5d5c998fafb9c43ccede5e [file] [log] [blame]
Andy Hungc2b11cb2020-04-22 09:04:01 -07001/*
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#ifndef ANDROID_AUDIO_TRACKMETRICS_H
18#define ANDROID_AUDIO_TRACKMETRICS_H
19
20#include <mutex>
21
22namespace android {
23
24/**
25 * TrackMetrics handles the AudioFlinger track metrics.
26 *
27 * We aggregate metrics for a particular device for proper analysis.
28 * This includes power, performance, and usage metrics.
29 *
30 * This class is thread-safe with a lock for safety. There is no risk of deadlock
31 * as this class only executes external one-way calls in Mediametrics and does not
32 * call any other AudioFlinger class.
33 *
34 * Terminology:
35 * An AudioInterval is a contiguous playback segment.
36 * An AudioIntervalGroup is a group of continuous playback segments on the same device.
37 *
38 * We currently deliver metrics based on an AudioIntervalGroup.
39 */
40class TrackMetrics final {
41public:
42 TrackMetrics(std::string metricsId, bool isOut)
43 : mMetricsId(std::move(metricsId))
44 , mIsOut(isOut)
45 {} // we don't log a constructor item, we wait for more info in logConstructor().
46
47 ~TrackMetrics() {
48 logEndInterval();
49 std::lock_guard l(mLock);
50 deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
51 // we don't log a destructor item here.
52 }
53
54 // Called under the following circumstances
55 // 1) when we are added to the Thread
56 // 2) when we have a createPatch in the Thread.
57 void logBeginInterval(const std::string& devices) {
58 std::lock_guard l(mLock);
59 if (mDevices != devices) {
60 deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
61 mDevices = devices;
62 resetIntervalGroupMetrics();
63 deliverDeviceMetrics(
64 AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, devices.c_str());
65 }
66 ++mIntervalCount;
67 mIntervalStartTimeNs = systemTime();
68 }
69
Andy Hung5837c7f2021-02-25 10:48:24 -080070 void logConstructor(pid_t creatorPid, uid_t creatorUid, int32_t internalTrackId,
Andy Hunga629bd12020-06-05 16:03:53 -070071 const std::string& traits = {},
Andy Hungea840382020-05-05 21:50:17 -070072 audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT) const {
Andy Hungc2b11cb2020-04-22 09:04:01 -070073 // Once this item is logged by the server, the client can add properties.
74 // no lock required, all local or const variables.
Andy Hungea840382020-05-05 21:50:17 -070075 mediametrics::LogItem item(mMetricsId);
76 item.setPid(creatorPid)
Andy Hungc2b11cb2020-04-22 09:04:01 -070077 .setUid(creatorUid)
78 .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)creatorUid)
79 .set(AMEDIAMETRICS_PROP_EVENT,
Andy Hunga629bd12020-06-05 16:03:53 -070080 AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
Andy Hung5837c7f2021-02-25 10:48:24 -080081 .set(AMEDIAMETRICS_PROP_INTERNALTRACKID, internalTrackId)
Andy Hunga629bd12020-06-05 16:03:53 -070082 .set(AMEDIAMETRICS_PROP_TRAITS, traits);
Andy Hungea840382020-05-05 21:50:17 -070083 // log streamType from the service, since client doesn't know chosen streamType.
84 if (streamType != AUDIO_STREAM_DEFAULT) {
85 item.set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(streamType).c_str());
86 }
87 item.record();
Andy Hungc2b11cb2020-04-22 09:04:01 -070088 }
89
90 // Called when we are removed from the Thread.
91 void logEndInterval() {
92 std::lock_guard l(mLock);
93 if (mIntervalStartTimeNs != 0) {
94 const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
95 mIntervalStartTimeNs = 0;
96 mCumulativeTimeNs += elapsedTimeNs;
97 mDeviceTimeNs += elapsedTimeNs;
98 }
99 }
100
101 void logInvalidate() const {
102 // no lock required, all local or const variables.
103 mediametrics::LogItem(mMetricsId)
104 .set(AMEDIAMETRICS_PROP_EVENT,
105 AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
106 .record();
107 }
108
109 void logLatencyAndStartup(double latencyMs, double startupMs) {
110 mediametrics::LogItem(mMetricsId)
111 .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
112 .set(AMEDIAMETRICS_PROP_STARTUPMS, startupMs)
113 .record();
114 std::lock_guard l(mLock);
115 mDeviceLatencyMs.add(latencyMs);
116 mDeviceStartupMs.add(startupMs);
117 }
118
Robert Lee36ac0412022-01-13 03:05:41 +0000119 void updateMinMaxVolume(int64_t durationNs, double deviceVolume) {
120 if (deviceVolume > mMaxVolume) {
121 mMaxVolume = deviceVolume;
122 mMaxVolumeDurationNs = durationNs;
123 } else if (deviceVolume == mMaxVolume) {
124 mMaxVolumeDurationNs += durationNs;
125 }
126 if (deviceVolume < mMinVolume) {
127 mMinVolume = deviceVolume;
128 mMinVolumeDurationNs = durationNs;
129 } else if (deviceVolume == mMinVolume) {
130 mMinVolumeDurationNs += durationNs;
131 }
132 }
133
Andy Hungc2b11cb2020-04-22 09:04:01 -0700134 // may be called multiple times during an interval
135 void logVolume(float volume) {
136 const int64_t timeNs = systemTime();
137 std::lock_guard l(mLock);
138 if (mStartVolumeTimeNs == 0) {
139 mDeviceVolume = mVolume = volume;
140 mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
Robert Lee36ac0412022-01-13 03:05:41 +0000141 updateMinMaxVolume(0, mVolume);
Andy Hungc2b11cb2020-04-22 09:04:01 -0700142 return;
143 }
Robert Lee36ac0412022-01-13 03:05:41 +0000144 const int64_t durationNs = timeNs - mLastVolumeChangeTimeNs;
145 updateMinMaxVolume(durationNs, mVolume);
Andy Hungc2b11cb2020-04-22 09:04:01 -0700146 mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
Robert Lee36ac0412022-01-13 03:05:41 +0000147 mVolume * durationNs) / (timeNs - mStartVolumeTimeNs);
Andy Hungc2b11cb2020-04-22 09:04:01 -0700148 mVolume = volume;
149 mLastVolumeChangeTimeNs = timeNs;
150 }
151
152 // Use absolute numbers returned by AudioTrackShared.
153 void logUnderruns(size_t count, size_t frames) {
154 std::lock_guard l(mLock);
155 mUnderrunCount = count;
156 mUnderrunFrames = frames;
157 // Consider delivering a message here (also be aware of excessive spam).
158 }
159
160private:
161 // no lock required - all arguments and constants.
162 void deliverDeviceMetrics(const char *eventName, const char *devices) const {
163 mediametrics::LogItem(mMetricsId)
164 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
165 .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
166 : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
167 .record();
168 }
169
170 void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
171 if (mIntervalCount > 0) {
172 mediametrics::LogItem item(mMetricsId);
173 item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
174 .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
175 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
176 .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
177 if (mIsOut) {
Robert Lee36ac0412022-01-13 03:05:41 +0000178 item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume)
179 .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, mMaxVolumeDurationNs)
180 .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, mMaxVolume)
181 .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, mMinVolumeDurationNs)
182 .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, mMinVolume);
Andy Hungc2b11cb2020-04-22 09:04:01 -0700183 }
184 if (mDeviceLatencyMs.getN() > 0) {
185 item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
186 .set(AMEDIAMETRICS_PROP_DEVICESTARTUPMS, mDeviceStartupMs.getMean());
187 }
188 if (mUnderrunCount > 0) {
189 item.set(AMEDIAMETRICS_PROP_UNDERRUN,
190 (int32_t)(mUnderrunCount - mUnderrunCountSinceIntervalGroup))
191 .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES,
192 (int64_t)(mUnderrunFrames - mUnderrunFramesSinceIntervalGroup));
193 }
194 item.record();
195 }
196 }
197
198 void resetIntervalGroupMetrics() REQUIRES(mLock) {
199 // mDevices is not reset by resetIntervalGroupMetrics.
200
201 mIntervalCount = 0;
202 mIntervalStartTimeNs = 0;
203 // mCumulativeTimeNs is not reset by resetIntervalGroupMetrics.
204 mDeviceTimeNs = 0;
205
206 mVolume = 0.f;
207 mDeviceVolume = 0.f;
208 mStartVolumeTimeNs = 0;
209 mLastVolumeChangeTimeNs = 0;
Robert Lee36ac0412022-01-13 03:05:41 +0000210 mMinVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
211 mMaxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
212 mMinVolumeDurationNs = 0;
213 mMaxVolumeDurationNs = 0;
Andy Hungc2b11cb2020-04-22 09:04:01 -0700214
215 mDeviceLatencyMs.reset();
216 mDeviceStartupMs.reset();
217
218 mUnderrunCountSinceIntervalGroup = mUnderrunCount;
219 mUnderrunFramesSinceIntervalGroup = mUnderrunFrames;
220 // do not reset mUnderrunCount - it keeps continuously running for tracks.
221 }
222
223 const std::string mMetricsId;
224 const bool mIsOut; // if true, than a playback track, otherwise used for record.
225
226 mutable std::mutex mLock;
227
228 // Devices in the interval group.
229 std::string mDevices GUARDED_BY(mLock);
230
231 // Number of intervals and playing time
232 int32_t mIntervalCount GUARDED_BY(mLock) = 0;
233 int64_t mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
234 int64_t mCumulativeTimeNs GUARDED_BY(mLock) = 0;
235 int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0;
236
237 // Average volume
238 double mVolume GUARDED_BY(mLock) = 0.f;
239 double mDeviceVolume GUARDED_BY(mLock) = 0.f;
240 int64_t mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
241 int64_t mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
242
Robert Lee36ac0412022-01-13 03:05:41 +0000243 // Min/Max volume
244 double mMinVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
245 double mMaxVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
246 int64_t mMinVolumeDurationNs GUARDED_BY(mLock) = 0;
247 int64_t mMaxVolumeDurationNs GUARDED_BY(mLock) = 0;
248
Andy Hungc2b11cb2020-04-22 09:04:01 -0700249 // latency and startup for each interval.
250 audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
251 audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
252
253 // underrun count and frames
254 int64_t mUnderrunCount GUARDED_BY(mLock) = 0;
255 int64_t mUnderrunFrames GUARDED_BY(mLock) = 0;
256 int64_t mUnderrunCountSinceIntervalGroup GUARDED_BY(mLock) = 0;
257 int64_t mUnderrunFramesSinceIntervalGroup GUARDED_BY(mLock) = 0;
258};
259
260} // namespace android
261
262#endif // ANDROID_AUDIO_TRACKMETRICS_H