• 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 #ifndef ANDROID_AUDIO_TRACKMETRICS_H
18 #define ANDROID_AUDIO_TRACKMETRICS_H
19 
20 #include <mutex>
21 
22 namespace 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  */
40 class TrackMetrics final {
41 public:
TrackMetrics(std::string metricsId,bool isOut)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 
~TrackMetrics()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.
logBeginInterval(const std::string & devices)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 
70     void logConstructor(pid_t creatorPid, uid_t creatorUid, int32_t internalTrackId,
71             const std::string& traits = {},
72             audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT) const {
73         // Once this item is logged by the server, the client can add properties.
74         // no lock required, all local or const variables.
75         mediametrics::LogItem item(mMetricsId);
76         item.setPid(creatorPid)
77             .setUid(creatorUid)
78             .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)creatorUid)
79             .set(AMEDIAMETRICS_PROP_EVENT,
80                     AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
81             .set(AMEDIAMETRICS_PROP_INTERNALTRACKID, internalTrackId)
82             .set(AMEDIAMETRICS_PROP_TRAITS, traits);
83         // 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();
88     }
89 
90     // Called when we are removed from the Thread.
logEndInterval()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 
logInvalidate()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 
logLatencyAndStartup(double latencyMs,double startupMs)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 
119     // may be called multiple times during an interval
logVolume(float volume)120     void logVolume(float volume) {
121         const int64_t timeNs = systemTime();
122         std::lock_guard l(mLock);
123         if (mStartVolumeTimeNs == 0) {
124             mDeviceVolume = mVolume = volume;
125             mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
126             return;
127         }
128         mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
129             mVolume * (timeNs - mLastVolumeChangeTimeNs)) / (timeNs - mStartVolumeTimeNs);
130         mVolume = volume;
131         mLastVolumeChangeTimeNs = timeNs;
132     }
133 
134     // Use absolute numbers returned by AudioTrackShared.
logUnderruns(size_t count,size_t frames)135     void logUnderruns(size_t count, size_t frames) {
136         std::lock_guard l(mLock);
137         mUnderrunCount = count;
138         mUnderrunFrames = frames;
139         // Consider delivering a message here (also be aware of excessive spam).
140     }
141 
142 private:
143     // no lock required - all arguments and constants.
deliverDeviceMetrics(const char * eventName,const char * devices)144     void deliverDeviceMetrics(const char *eventName, const char *devices) const {
145         mediametrics::LogItem(mMetricsId)
146             .set(AMEDIAMETRICS_PROP_EVENT, eventName)
147             .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
148                    : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
149            .record();
150     }
151 
deliverCumulativeMetrics(const char * eventName)152     void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
153         if (mIntervalCount > 0) {
154             mediametrics::LogItem item(mMetricsId);
155             item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
156                 .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
157                 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
158                 .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
159             if (mIsOut) {
160                 item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume);
161             }
162             if (mDeviceLatencyMs.getN() > 0) {
163                 item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
164                     .set(AMEDIAMETRICS_PROP_DEVICESTARTUPMS, mDeviceStartupMs.getMean());
165             }
166             if (mUnderrunCount > 0) {
167                 item.set(AMEDIAMETRICS_PROP_UNDERRUN,
168                         (int32_t)(mUnderrunCount - mUnderrunCountSinceIntervalGroup))
169                     .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES,
170                         (int64_t)(mUnderrunFrames - mUnderrunFramesSinceIntervalGroup));
171             }
172             item.record();
173         }
174     }
175 
resetIntervalGroupMetrics()176     void resetIntervalGroupMetrics() REQUIRES(mLock) {
177         // mDevices is not reset by resetIntervalGroupMetrics.
178 
179         mIntervalCount = 0;
180         mIntervalStartTimeNs = 0;
181         // mCumulativeTimeNs is not reset by resetIntervalGroupMetrics.
182         mDeviceTimeNs = 0;
183 
184         mVolume = 0.f;
185         mDeviceVolume = 0.f;
186         mStartVolumeTimeNs = 0;
187         mLastVolumeChangeTimeNs = 0;
188 
189         mDeviceLatencyMs.reset();
190         mDeviceStartupMs.reset();
191 
192         mUnderrunCountSinceIntervalGroup = mUnderrunCount;
193         mUnderrunFramesSinceIntervalGroup = mUnderrunFrames;
194         // do not reset mUnderrunCount - it keeps continuously running for tracks.
195     }
196 
197     const std::string mMetricsId;
198     const bool        mIsOut;  // if true, than a playback track, otherwise used for record.
199 
200     mutable           std::mutex mLock;
201 
202     // Devices in the interval group.
203     std::string       mDevices GUARDED_BY(mLock);
204 
205     // Number of intervals and playing time
206     int32_t           mIntervalCount GUARDED_BY(mLock) = 0;
207     int64_t           mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
208     int64_t           mCumulativeTimeNs GUARDED_BY(mLock) = 0;
209     int64_t           mDeviceTimeNs GUARDED_BY(mLock) = 0;
210 
211     // Average volume
212     double            mVolume GUARDED_BY(mLock) = 0.f;
213     double            mDeviceVolume GUARDED_BY(mLock) = 0.f;
214     int64_t           mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
215     int64_t           mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
216 
217     // latency and startup for each interval.
218     audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
219     audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
220 
221     // underrun count and frames
222     int64_t           mUnderrunCount GUARDED_BY(mLock) = 0;
223     int64_t           mUnderrunFrames GUARDED_BY(mLock) = 0;
224     int64_t           mUnderrunCountSinceIntervalGroup GUARDED_BY(mLock) = 0;
225     int64_t           mUnderrunFramesSinceIntervalGroup GUARDED_BY(mLock) = 0;
226 };
227 
228 } // namespace android
229 
230 #endif // ANDROID_AUDIO_TRACKMETRICS_H
231