TrackMetrics: Add device-based statistics for audio
Compute summary statistics based on the current device
rather than the entire AudioTrack or AudioRecord duration.
Test: adb shell dumpsys media.metrics
Bug: 149850236
Change-Id: Ia3a5707c43c4530f5a6ac90f52901bd2e0bd0bab
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 8aec80d..9cabd8b 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -614,6 +614,8 @@
// and thus which resulted in an underrun.
virtual uint32_t getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
+ virtual uint32_t getUnderrunCount() const { return mCblk->u.mStreaming.mUnderrunCount; }
+
// Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
AudioPlaybackRate getPlaybackRate();
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 00da69a..ec0e133 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -37,6 +37,11 @@
// They must be appended with another value to make a key.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."
+// The AudioMmap key appends the "trackId" to the prefix.
+// This is the AudioFlinger equivalent of the AAudio Stream.
+// TODO: unify with AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP AMEDIAMETRICS_KEY_PREFIX_AUDIO "mmap."
+
// The AudioRecord key appends the "trackId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."
@@ -95,6 +100,14 @@
#define AMEDIAMETRICS_PROP_CHANNELCOUNT "channelCount" // int32
#define AMEDIAMETRICS_PROP_CHANNELMASK "channelMask" // int32
#define AMEDIAMETRICS_PROP_CONTENTTYPE "contentType" // string attributes (AudioTrack)
+#define AMEDIAMETRICS_PROP_CUMULATIVETIMENS "cumulativeTimeNs" // int64_t playback/record time
+ // since start
+// DEVICE values are averaged since starting on device
+#define AMEDIAMETRICS_PROP_DEVICELATENCYMS "deviceLatencyMs" // double - avg latency time
+#define AMEDIAMETRICS_PROP_DEVICESTARTUPMS "deviceStartupMs" // double - avg startup time
+#define AMEDIAMETRICS_PROP_DEVICETIMENS "deviceTimeNs" // int64_t playback/record time
+#define AMEDIAMETRICS_PROP_DEVICEVOLUME "deviceVolume" // double - average device volume
+
#define AMEDIAMETRICS_PROP_DIRECTION "direction" // string AAudio input or output
#define AMEDIAMETRICS_PROP_DURATIONNS "durationNs" // int64 duration time span
#define AMEDIAMETRICS_PROP_ENCODING "encoding" // string value of format
@@ -105,7 +118,9 @@
#define AMEDIAMETRICS_PROP_FRAMECOUNT "frameCount" // int32
#define AMEDIAMETRICS_PROP_INPUTDEVICES "inputDevices" // string value
+#define AMEDIAMETRICS_PROP_INTERVALCOUNT "intervalCount" // int32
#define AMEDIAMETRICS_PROP_LATENCYMS "latencyMs" // double value
+#define AMEDIAMETRICS_PROP_NAME "name" // string value
#define AMEDIAMETRICS_PROP_ORIGINALFLAGS "originalFlags" // int32
#define AMEDIAMETRICS_PROP_OUTPUTDEVICES "outputDevices" // string value
#define AMEDIAMETRICS_PROP_PERFORMANCEMODE "performanceMode" // string value, "none", lowLatency"
@@ -129,6 +144,7 @@
#define AMEDIAMETRICS_PROP_TRACKID "trackId" // int32 port id of track/record
#define AMEDIAMETRICS_PROP_TYPE "type" // string (thread type)
#define AMEDIAMETRICS_PROP_UNDERRUN "underrun" // int32
+#define AMEDIAMETRICS_PROP_UNDERRUNFRAMES "underrunFrames" // int64_t from Thread
#define AMEDIAMETRICS_PROP_USAGE "usage" // string attributes (ATrack)
#define AMEDIAMETRICS_PROP_VOLUME_LEFT "volume.left" // double (AudioTrack)
#define AMEDIAMETRICS_PROP_VOLUME_RIGHT "volume.right" // double (AudioTrack)
@@ -140,12 +156,14 @@
// Values are strings accepted for a given property.
// An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE "close"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE "create"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH "createAudioPatch"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR "ctor"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT "disconnect"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR "dtor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP "endAudioIntervalGroup"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH "flush" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE "invalidate" // server track, record
#define AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN "open"
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 6afbd4f..0ed63a4 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -88,6 +88,7 @@
#include "SpdifStreamOut.h"
#include "AudioHwDevice.h"
#include "NBAIO_Tee.h"
+#include "TrackMetrics.h"
#include <powermanager/IPowerManager.h>
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1ff03c4..d8eebf3 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -171,6 +171,16 @@
void setTeePatches(TeePatches teePatches);
+ void tallyUnderrunFrames(size_t frames) override {
+ if (isOut()) { // we expect this from output tracks only
+ mAudioTrackServerProxy->tallyUnderrunFrames(frames);
+ // Fetch absolute numbers from AudioTrackShared as it counts
+ // contiguous underruns as a one -- we want a consistent number.
+ // TODO: isolate this counting into a class.
+ mTrackMetrics.logUnderruns(mAudioTrackServerProxy->getUnderrunCount(),
+ mAudioTrackServerProxy->getUnderrunFrames());
+ }
+ }
protected:
// for numerous
friend class PlaybackThread;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 5d9c35a..69bf831 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -220,6 +220,9 @@
{
std::stringstream ss;
for (size_t i = 0; i < patch->num_sinks; ++i) {
+ if (i > 0) {
+ ss << "|";
+ }
ss << "(" << toString(patch->sinks[i].ext.device.type)
<< ", " << patch->sinks[i].ext.device.address << ")";
}
@@ -230,6 +233,9 @@
{
std::stringstream ss;
for (size_t i = 0; i < patch->num_sources; ++i) {
+ if (i > 0) {
+ ss << "|";
+ }
ss << "(" << toString(patch->sources[i].ext.device.type)
<< ", " << patch->sources[i].ext.device.address << ")";
}
@@ -1686,6 +1692,7 @@
#ifdef TEE_SINK
track->dumpTee(-1 /* fd */, "_REMOVE");
#endif
+ track->logEndInterval(); // log to MediaMetrics
return index;
}
@@ -2553,6 +2560,7 @@
chain->incActiveTrackCnt();
}
+ track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics
status = NO_ERROR;
}
@@ -4256,10 +4264,16 @@
status = mOutput->stream->setParameters(param.toString());
*handle = AUDIO_PATCH_HANDLE_NONE;
}
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
- .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, patchSinksToString(patch).c_str())
+ const std::string patchSinksAsString = patchSinksToString(patch);
+ mediametrics::LogItem item(mMetricsId);
+ item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
+ .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, patchSinksAsString.c_str())
.record();
+ // also dispatch to active AudioTracks for MediaMetrics
+ for (const auto &track : mActiveTracks) {
+ track->logEndInterval();
+ track->logBeginInterval(patchSinksAsString);
+ }
if (configChanged) {
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
@@ -4812,19 +4826,9 @@
// because that is when the underrun occurs.
// We do not distinguish between FastTracks and NormalTracks here.
if (*mMixerStatus == MIXER_TRACKS_READY && mUnderrunFrames.size() > 0) {
- mediametrics::LogItem item(mMetricsId);
-
- item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN);
for (const auto &underrun : mUnderrunFrames) {
- underrun.first->mAudioTrackServerProxy->tallyUnderrunFrames(
- underrun.second);
-
- item.set(std::string("[" AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
- + std::to_string(underrun.first->portId())
- + "]" AMEDIAMETRICS_PROP_UNDERRUN,
- (int32_t)underrun.second);
+ underrun.first->tallyUnderrunFrames(underrun.second);
}
- item.record();
}
}
@@ -4837,7 +4841,7 @@
private:
const mixer_state * const mMixerStatus;
- const std::string& mMetricsId;
+ const std::string& __unused mMetricsId;
std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
} deferredOperations(&mixerStatus, mMetricsId);
// implicit nested scope for variable capture
@@ -7881,6 +7885,9 @@
sendIoConfigEvent_l(
AUDIO_CLIENT_STARTED, recordTrack->creatorPid(), recordTrack->portId());
}
+
+ recordTrack->logBeginInterval(patchSourcesToString(&mPatch)); // log to MediaMetrics
+
// Catch up with current buffer indices if thread is already running.
// This is what makes a new client discard all buffered data. If the track's mRsmpInFront
// was initialized to some value closer to the thread's mRsmpInFront, then the track could
@@ -8545,12 +8552,17 @@
mPatch = *patch;
}
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
- .set(AMEDIAMETRICS_PROP_INPUTDEVICES, patchSourcesToString(patch).c_str())
+ const std::string pathSourcesAsString = patchSourcesToString(patch);
+ mediametrics::LogItem item(mMetricsId);
+ item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
+ .set(AMEDIAMETRICS_PROP_INPUTDEVICES, pathSourcesAsString.c_str())
.set(AMEDIAMETRICS_PROP_SOURCE, toString(mAudioSource).c_str())
.record();
-
+ // also dispatch to active AudioRecords
+ for (const auto &track : mActiveTracks) {
+ track->logEndInterval();
+ track->logBeginInterval(pathSourcesAsString);
+ }
return status;
}
@@ -8861,6 +8873,7 @@
chain->incActiveTrackCnt();
}
+ track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics
*handle = portId;
broadcast_l();
@@ -8946,6 +8959,26 @@
result = mHalStream->getBufferSize(&mBufferSize);
LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
mFrameCount = mBufferSize / mFrameSize;
+
+ mediametrics::LogItem item(mMetricsId);
+ item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
+ .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+ .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
+ .set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)mChannelCount)
+ .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
+ /*
+ .set(AMEDIAMETRICS_PROP_FLAGS, toString(flags).c_str())
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELMASK,
+ (int32_t)mHapticChannelMask)
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELCOUNT,
+ (int32_t)mHapticChannelCount)
+ */
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_ENCODING,
+ formatToString(mHALFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_FRAMECOUNT,
+ (int32_t)mFrameCount) // sic - added HAL
+ .record();
}
bool AudioFlinger::MmapThread::threadLoop()
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index e39b944..15c66fb 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -97,10 +97,7 @@
virtual void invalidate() {
if (mIsInvalid) return;
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT,
- AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
- .record();
+ mTrackMetrics.logInvalidate();
mIsInvalid = true;
}
bool isInvalid() const { return mIsInvalid; }
@@ -242,6 +239,20 @@
}
}
+ // Called by the PlaybackThread to indicate that the track is becoming active
+ // and a new interval should start with a given device list.
+ void logBeginInterval(const std::string& devices) {
+ mTrackMetrics.logBeginInterval(devices);
+ }
+
+ // Called by the PlaybackThread to indicate the track is no longer active.
+ void logEndInterval() {
+ mTrackMetrics.logEndInterval();
+ }
+
+ // Called to tally underrun frames in playback.
+ virtual void tallyUnderrunFrames(size_t /* frames */) {}
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -367,7 +378,7 @@
int64_t mLogStartTimeNs = 0;
int64_t mLogStartFrames = 0;
- const std::string mMetricsId;
+ TrackMetrics mTrackMetrics;
bool mServerLatencySupported = false;
std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
new file mode 100644
index 0000000..399c788
--- /dev/null
+++ b/services/audioflinger/TrackMetrics.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_TRACKMETRICS_H
+#define ANDROID_AUDIO_TRACKMETRICS_H
+
+#include <mutex>
+
+namespace android {
+
+/**
+ * TrackMetrics handles the AudioFlinger track metrics.
+ *
+ * We aggregate metrics for a particular device for proper analysis.
+ * This includes power, performance, and usage metrics.
+ *
+ * This class is thread-safe with a lock for safety. There is no risk of deadlock
+ * as this class only executes external one-way calls in Mediametrics and does not
+ * call any other AudioFlinger class.
+ *
+ * Terminology:
+ * An AudioInterval is a contiguous playback segment.
+ * An AudioIntervalGroup is a group of continuous playback segments on the same device.
+ *
+ * We currently deliver metrics based on an AudioIntervalGroup.
+ */
+class TrackMetrics final {
+public:
+ TrackMetrics(std::string metricsId, bool isOut)
+ : mMetricsId(std::move(metricsId))
+ , mIsOut(isOut)
+ {} // we don't log a constructor item, we wait for more info in logConstructor().
+
+ ~TrackMetrics() {
+ logEndInterval();
+ std::lock_guard l(mLock);
+ deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+ // we don't log a destructor item here.
+ }
+
+ // Called under the following circumstances
+ // 1) when we are added to the Thread
+ // 2) when we have a createPatch in the Thread.
+ void logBeginInterval(const std::string& devices) {
+ std::lock_guard l(mLock);
+ if (mDevices != devices) {
+ deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+ mDevices = devices;
+ resetIntervalGroupMetrics();
+ deliverDeviceMetrics(
+ AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, devices.c_str());
+ }
+ ++mIntervalCount;
+ mIntervalStartTimeNs = systemTime();
+ }
+
+ void logConstructor(pid_t creatorPid, uid_t creatorUid) const {
+ // Once this item is logged by the server, the client can add properties.
+ // no lock required, all local or const variables.
+ mediametrics::LogItem(mMetricsId)
+ .setPid(creatorPid)
+ .setUid(creatorUid)
+ .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)creatorUid)
+ .set(AMEDIAMETRICS_PROP_EVENT,
+ AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .record();
+ }
+
+ // Called when we are removed from the Thread.
+ void logEndInterval() {
+ std::lock_guard l(mLock);
+ if (mIntervalStartTimeNs != 0) {
+ const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
+ mIntervalStartTimeNs = 0;
+ mCumulativeTimeNs += elapsedTimeNs;
+ mDeviceTimeNs += elapsedTimeNs;
+ }
+ }
+
+ void logInvalidate() const {
+ // no lock required, all local or const variables.
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
+ .record();
+ }
+
+ void logLatencyAndStartup(double latencyMs, double startupMs) {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
+ .set(AMEDIAMETRICS_PROP_STARTUPMS, startupMs)
+ .record();
+ std::lock_guard l(mLock);
+ mDeviceLatencyMs.add(latencyMs);
+ mDeviceStartupMs.add(startupMs);
+ }
+
+ // may be called multiple times during an interval
+ void logVolume(float volume) {
+ const int64_t timeNs = systemTime();
+ std::lock_guard l(mLock);
+ if (mStartVolumeTimeNs == 0) {
+ mDeviceVolume = mVolume = volume;
+ mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
+ return;
+ }
+ mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
+ mVolume * (timeNs - mLastVolumeChangeTimeNs)) / (timeNs - mStartVolumeTimeNs);
+ mVolume = volume;
+ mLastVolumeChangeTimeNs = timeNs;
+ }
+
+ // Use absolute numbers returned by AudioTrackShared.
+ void logUnderruns(size_t count, size_t frames) {
+ std::lock_guard l(mLock);
+ mUnderrunCount = count;
+ mUnderrunFrames = frames;
+ // Consider delivering a message here (also be aware of excessive spam).
+ }
+
+private:
+ // no lock required - all arguments and constants.
+ void deliverDeviceMetrics(const char *eventName, const char *devices) const {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+ .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
+ : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
+ .record();
+ }
+
+ void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
+ if (mIntervalCount > 0) {
+ mediametrics::LogItem item(mMetricsId);
+ item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
+ .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
+ .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+ .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
+ if (mIsOut) {
+ item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume);
+ }
+ if (mDeviceLatencyMs.getN() > 0) {
+ item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
+ .set(AMEDIAMETRICS_PROP_DEVICESTARTUPMS, mDeviceStartupMs.getMean());
+ }
+ if (mUnderrunCount > 0) {
+ item.set(AMEDIAMETRICS_PROP_UNDERRUN,
+ (int32_t)(mUnderrunCount - mUnderrunCountSinceIntervalGroup))
+ .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES,
+ (int64_t)(mUnderrunFrames - mUnderrunFramesSinceIntervalGroup));
+ }
+ item.record();
+ }
+ }
+
+ void resetIntervalGroupMetrics() REQUIRES(mLock) {
+ // mDevices is not reset by resetIntervalGroupMetrics.
+
+ mIntervalCount = 0;
+ mIntervalStartTimeNs = 0;
+ // mCumulativeTimeNs is not reset by resetIntervalGroupMetrics.
+ mDeviceTimeNs = 0;
+
+ mVolume = 0.f;
+ mDeviceVolume = 0.f;
+ mStartVolumeTimeNs = 0;
+ mLastVolumeChangeTimeNs = 0;
+
+ mDeviceLatencyMs.reset();
+ mDeviceStartupMs.reset();
+
+ mUnderrunCountSinceIntervalGroup = mUnderrunCount;
+ mUnderrunFramesSinceIntervalGroup = mUnderrunFrames;
+ // do not reset mUnderrunCount - it keeps continuously running for tracks.
+ }
+
+ const std::string mMetricsId;
+ const bool mIsOut; // if true, than a playback track, otherwise used for record.
+
+ mutable std::mutex mLock;
+
+ // Devices in the interval group.
+ std::string mDevices GUARDED_BY(mLock);
+
+ // Number of intervals and playing time
+ int32_t mIntervalCount GUARDED_BY(mLock) = 0;
+ int64_t mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mCumulativeTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0;
+
+ // Average volume
+ double mVolume GUARDED_BY(mLock) = 0.f;
+ double mDeviceVolume GUARDED_BY(mLock) = 0.f;
+ int64_t mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
+
+ // latency and startup for each interval.
+ audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
+ audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
+
+ // underrun count and frames
+ int64_t mUnderrunCount GUARDED_BY(mLock) = 0;
+ int64_t mUnderrunFrames GUARDED_BY(mLock) = 0;
+ int64_t mUnderrunCountSinceIntervalGroup GUARDED_BY(mLock) = 0;
+ int64_t mUnderrunFramesSinceIntervalGroup GUARDED_BY(mLock) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_TRACKMETRICS_H
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 4898d37..58c61c9 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -106,7 +106,7 @@
mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
mPortId(portId),
mIsInvalid(false),
- mMetricsId(std::move(metricsId)),
+ mTrackMetrics(std::move(metricsId), isOut),
mCreatorPid(creatorPid)
{
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -602,13 +602,7 @@
}
// Once this item is logged by the server, the client can add properties.
- mediametrics::LogItem(mMetricsId)
- .setPid(creatorPid)
- .setUid(uid)
- .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
- .set(AMEDIAMETRICS_PROP_EVENT,
- AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
- .record();
+ mTrackMetrics.logConstructor(creatorPid, uid);
}
AudioFlinger::PlaybackThread::Track::~Track()
@@ -1249,6 +1243,7 @@
if (mFinalVolume != volume) { // Compare to an epsilon if too many meaningless updates
mFinalVolume = volume;
setMetadataHasChanged();
+ mTrackMetrics.logVolume(volume);
}
}
@@ -1534,10 +1529,7 @@
(long long)mLogStartTimeNs,
(long long)local.mPosition[ExtendedTimestamp::LOCATION_SERVER],
(long long)mLogStartFrames);
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
- .set(AMEDIAMETRICS_PROP_STARTUPMS, startUpMs)
- .record();
+ mTrackMetrics.logLatencyAndStartup(latencyMs, startUpMs);
}
}
}
@@ -2163,12 +2155,7 @@
#endif
// Once this item is logged by the server, the client can add properties.
- mediametrics::LogItem(mMetricsId)
- .setPid(creatorPid)
- .setUid(uid)
- .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
- .set(AMEDIAMETRICS_PROP_EVENT, "server." AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
- .record();
+ mTrackMetrics.logConstructor(creatorPid, uid);
}
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
@@ -2725,9 +2712,12 @@
nullptr /* buffer */, (size_t)0 /* bufferSize */,
sessionId, creatorPid, uid, isOut,
ALLOC_NONE,
- TYPE_DEFAULT, portId),
+ TYPE_DEFAULT, portId,
+ std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
mPid(pid), mSilenced(false), mSilencedNotified(false)
{
+ // Once this item is logged by the server, the client can add properties.
+ mTrackMetrics.logConstructor(creatorPid, uid);
}
AudioFlinger::MmapThread::MmapTrack::~MmapTrack()