blob: af16448c7735d239c6177c6f6f94833eecbf511c [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 Hungea840382020-05-05 21:50:17 -070070 void logConstructor(pid_t creatorPid, uid_t creatorUid,
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)
81 .set(AMEDIAMETRICS_PROP_TRAITS, traits);
Andy Hungea840382020-05-05 21:50:17 -070082 // log streamType from the service, since client doesn't know chosen streamType.
83 if (streamType != AUDIO_STREAM_DEFAULT) {
84 item.set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(streamType).c_str());
85 }
86 item.record();
Andy Hungc2b11cb2020-04-22 09:04:01 -070087 }
88
89 // Called when we are removed from the Thread.
90 void logEndInterval() {
91 std::lock_guard l(mLock);
92 if (mIntervalStartTimeNs != 0) {
93 const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
94 mIntervalStartTimeNs = 0;
95 mCumulativeTimeNs += elapsedTimeNs;
96 mDeviceTimeNs += elapsedTimeNs;
97 }
98 }
99
100 void logInvalidate() const {
101 // no lock required, all local or const variables.
102 mediametrics::LogItem(mMetricsId)
103 .set(AMEDIAMETRICS_PROP_EVENT,
104 AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
105 .record();
106 }
107
108 void logLatencyAndStartup(double latencyMs, double startupMs) {
109 mediametrics::LogItem(mMetricsId)
110 .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
111 .set(AMEDIAMETRICS_PROP_STARTUPMS, startupMs)
112 .record();
113 std::lock_guard l(mLock);
114 mDeviceLatencyMs.add(latencyMs);
115 mDeviceStartupMs.add(startupMs);
116 }
117
118 // may be called multiple times during an interval
119 void logVolume(float volume) {
120 const int64_t timeNs = systemTime();
121 std::lock_guard l(mLock);
122 if (mStartVolumeTimeNs == 0) {
123 mDeviceVolume = mVolume = volume;
124 mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
125 return;
126 }
127 mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
128 mVolume * (timeNs - mLastVolumeChangeTimeNs)) / (timeNs - mStartVolumeTimeNs);
129 mVolume = volume;
130 mLastVolumeChangeTimeNs = timeNs;
131 }
132
133 // Use absolute numbers returned by AudioTrackShared.
134 void logUnderruns(size_t count, size_t frames) {
135 std::lock_guard l(mLock);
136 mUnderrunCount = count;
137 mUnderrunFrames = frames;
138 // Consider delivering a message here (also be aware of excessive spam).
139 }
140
141private:
142 // no lock required - all arguments and constants.
143 void deliverDeviceMetrics(const char *eventName, const char *devices) const {
144 mediametrics::LogItem(mMetricsId)
145 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
146 .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
147 : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
148 .record();
149 }
150
151 void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
152 if (mIntervalCount > 0) {
153 mediametrics::LogItem item(mMetricsId);
154 item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
155 .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
156 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
157 .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
158 if (mIsOut) {
159 item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume);
160 }
161 if (mDeviceLatencyMs.getN() > 0) {
162 item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
163 .set(AMEDIAMETRICS_PROP_DEVICESTARTUPMS, mDeviceStartupMs.getMean());
164 }
165 if (mUnderrunCount > 0) {
166 item.set(AMEDIAMETRICS_PROP_UNDERRUN,
167 (int32_t)(mUnderrunCount - mUnderrunCountSinceIntervalGroup))
168 .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES,
169 (int64_t)(mUnderrunFrames - mUnderrunFramesSinceIntervalGroup));
170 }
171 item.record();
172 }
173 }
174
175 void resetIntervalGroupMetrics() REQUIRES(mLock) {
176 // mDevices is not reset by resetIntervalGroupMetrics.
177
178 mIntervalCount = 0;
179 mIntervalStartTimeNs = 0;
180 // mCumulativeTimeNs is not reset by resetIntervalGroupMetrics.
181 mDeviceTimeNs = 0;
182
183 mVolume = 0.f;
184 mDeviceVolume = 0.f;
185 mStartVolumeTimeNs = 0;
186 mLastVolumeChangeTimeNs = 0;
187
188 mDeviceLatencyMs.reset();
189 mDeviceStartupMs.reset();
190
191 mUnderrunCountSinceIntervalGroup = mUnderrunCount;
192 mUnderrunFramesSinceIntervalGroup = mUnderrunFrames;
193 // do not reset mUnderrunCount - it keeps continuously running for tracks.
194 }
195
196 const std::string mMetricsId;
197 const bool mIsOut; // if true, than a playback track, otherwise used for record.
198
199 mutable std::mutex mLock;
200
201 // Devices in the interval group.
202 std::string mDevices GUARDED_BY(mLock);
203
204 // Number of intervals and playing time
205 int32_t mIntervalCount GUARDED_BY(mLock) = 0;
206 int64_t mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
207 int64_t mCumulativeTimeNs GUARDED_BY(mLock) = 0;
208 int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0;
209
210 // Average volume
211 double mVolume GUARDED_BY(mLock) = 0.f;
212 double mDeviceVolume GUARDED_BY(mLock) = 0.f;
213 int64_t mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
214 int64_t mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
215
216 // latency and startup for each interval.
217 audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
218 audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
219
220 // underrun count and frames
221 int64_t mUnderrunCount GUARDED_BY(mLock) = 0;
222 int64_t mUnderrunFrames GUARDED_BY(mLock) = 0;
223 int64_t mUnderrunCountSinceIntervalGroup GUARDED_BY(mLock) = 0;
224 int64_t mUnderrunFramesSinceIntervalGroup GUARDED_BY(mLock) = 0;
225};
226
227} // namespace android
228
229#endif // ANDROID_AUDIO_TRACKMETRICS_H