Merge "MediaMetrics: Prepare statistics for protos" into rvc-dev
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0bbceef..d4c421a 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -405,7 +405,7 @@
? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
: mCallerName.c_str())
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
.record(); });
@@ -481,7 +481,7 @@
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
.record(); });
@@ -742,6 +742,8 @@
void *iMemPointer;
audio_track_cblk_t* cblk;
status_t status;
+ std::string flagsAsString;
+ std::string originalFlagsAsString;
if (audioFlinger == 0) {
ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId);
@@ -920,13 +922,15 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
+ InputFlagConverter::toString(mFlags, flagsAsString);
+ InputFlagConverter::toString(mOrigFlags, originalFlagsAsString);
mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD) + std::to_string(mPortId);
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
// the following are immutable (at least until restore)
- .set(AMEDIAMETRICS_PROP_FLAGS, (int32_t)mFlags)
- .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, (int32_t)mOrigFlags)
+ .set(AMEDIAMETRICS_PROP_FLAGS, flagsAsString.c_str())
+ .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, originalFlagsAsString.c_str())
.set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
.set(AMEDIAMETRICS_PROP_TRACKID, mPortId)
.set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str())
@@ -1387,7 +1391,7 @@
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
.set(AMEDIAMETRICS_PROP_WHERE, from)
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index ca80dc4..011b0fa 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -650,7 +650,7 @@
? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
: mCallerName.c_str())
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
.record(); });
@@ -783,7 +783,7 @@
mediametrics::Defer defer([&]() {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
.record();
logBufferSizeUnderruns();
@@ -845,7 +845,7 @@
mediametrics::Defer defer([&]() {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
.record(); });
@@ -886,7 +886,7 @@
mediametrics::Defer defer([&]() {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
.record(); });
@@ -1715,15 +1715,19 @@
// The creation of the audio track by AudioFlinger (in the code above)
// is the first log of the AudioTrack and must be present before
// any AudioTrack client logs will be accepted.
+
+ std::string flagsAsString;
+ OutputFlagConverter::toString(mFlags, flagsAsString);
+ std::string originalFlagsAsString;
+ OutputFlagConverter::toString(mOrigFlags, originalFlagsAsString);
mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + std::to_string(mPortId);
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE)
// the following are immutable
- .set(AMEDIAMETRICS_PROP_FLAGS, (int32_t)mFlags)
- .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, (int32_t)mOrigFlags)
+ .set(AMEDIAMETRICS_PROP_FLAGS, flagsAsString.c_str())
+ .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, originalFlagsAsString.c_str())
.set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
.set(AMEDIAMETRICS_PROP_TRACKID, mPortId) // dup from key
- .set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(mStreamType).c_str())
.set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(mAttributes.content_type).c_str())
.set(AMEDIAMETRICS_PROP_USAGE, toString(mAttributes.usage).c_str())
.set(AMEDIAMETRICS_PROP_THREADID, (int32_t)output.outputId)
@@ -2440,7 +2444,7 @@
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
.set(AMEDIAMETRICS_PROP_WHERE, from)
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 586a1a3..b916a78 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -37,6 +37,9 @@
// They must be appended with another value to make a key.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."
+// Device related key prefix.
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE AMEDIAMETRICS_KEY_PREFIX_AUDIO "device."
+
// 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
@@ -113,6 +116,7 @@
#define AMEDIAMETRICS_PROP_DURATIONNS "durationNs" // int64 duration time span
#define AMEDIAMETRICS_PROP_ENCODING "encoding" // string value of format
#define AMEDIAMETRICS_PROP_EVENT "event#" // string value (often func name)
+#define AMEDIAMETRICS_PROP_EXECUTIONTIMENS "executionTimeNs" // time to execute the event
// TODO: fix inconsistency in flags: AudioRecord / AudioTrack int32, AudioThread string
#define AMEDIAMETRICS_PROP_FLAGS "flags"
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 55f2952..3dfeb83 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2812,7 +2812,7 @@
if (t == nullptr) {
return false;
}
- return t->type() == ThreadBase::OFFLOAD || t->type() == ThreadBase::MMAP;
+ return t->isOffloadOrMmap();
}
uint32_t AudioFlinger::EffectChain::EffectCallback::sampleRate() const {
diff --git a/services/audioflinger/ThreadMetrics.h b/services/audioflinger/ThreadMetrics.h
index 7989de1..6526655 100644
--- a/services/audioflinger/ThreadMetrics.h
+++ b/services/audioflinger/ThreadMetrics.h
@@ -58,9 +58,11 @@
// 2) We come out of standby
void logBeginInterval() {
std::lock_guard l(mLock);
- if (mDevices != mCreatePatchDevices) {
+ // The devices we look for change depend on whether the Thread is input or output.
+ const std::string& patchDevices = mIsOut ? mCreatePatchOutDevices : mCreatePatchInDevices;
+ if (mDevices != patchDevices) {
deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
- mDevices = mCreatePatchDevices; // set after endAudioIntervalGroup
+ mDevices = patchDevices; // set after endAudioIntervalGroup
resetIntervalGroupMetrics();
deliverDeviceMetrics(
AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, mDevices.c_str());
@@ -80,12 +82,14 @@
.record();
}
- void logCreatePatch(const std::string& devices) {
+ void logCreatePatch(const std::string& inDevices, const std::string& outDevices) {
std::lock_guard l(mLock);
- mCreatePatchDevices = devices;
+ mCreatePatchInDevices = inDevices;
+ mCreatePatchOutDevices = outDevices;
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
- .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, devices)
+ .set(AMEDIAMETRICS_PROP_INPUTDEVICES, inDevices)
+ .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, outDevices)
.record();
}
@@ -115,11 +119,13 @@
mDeviceLatencyMs.add(latencyMs);
}
- // TODO: further implement this.
- void logUnderrunFrames(size_t count, size_t frames) {
+ void logUnderrunFrames(size_t frames) {
std::lock_guard l(mLock);
- mUnderrunCount = count;
- mUnderrunFrames = frames;
+ if (mLastUnderrun == false && frames > 0) {
+ ++mUnderrunCount; // count non-continguous underrun sequences.
+ }
+ mLastUnderrun = (frames > 0);
+ mUnderrunFrames += frames;
}
const std::string& getMetricsId() const {
@@ -164,6 +170,7 @@
mDeviceLatencyMs.reset();
+ mLastUnderrun = false;
mUnderrunCount = 0;
mUnderrunFrames = 0;
}
@@ -174,8 +181,9 @@
mutable std::mutex mLock;
// Devices in the interval group.
- std::string mDevices GUARDED_BY(mLock);
- std::string mCreatePatchDevices GUARDED_BY(mLock);
+ std::string mDevices GUARDED_BY(mLock); // last input or output devices based on mIsOut.
+ std::string mCreatePatchInDevices GUARDED_BY(mLock);
+ std::string mCreatePatchOutDevices GUARDED_BY(mLock);
// Number of intervals and playing time
int32_t mIntervalCount GUARDED_BY(mLock) = 0;
@@ -187,8 +195,9 @@
audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
// underrun count and frames
- int64_t mUnderrunCount GUARDED_BY(mLock) = 0;
- int64_t mUnderrunFrames GUARDED_BY(mLock) = 0;
+ bool mLastUnderrun GUARDED_BY(mLock) = false; // checks consecutive underruns
+ int64_t mUnderrunCount GUARDED_BY(mLock) = 0; // number of consecutive underruns
+ int64_t mUnderrunFrames GUARDED_BY(mLock) = 0; // total estimated frames underrun
};
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b806040..4a4899f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -484,8 +484,10 @@
return "RECORD";
case OFFLOAD:
return "OFFLOAD";
- case MMAP:
- return "MMAP";
+ case MMAP_PLAYBACK:
+ return "MMAP_PLAYBACK";
+ case MMAP_CAPTURE:
+ return "MMAP_CAPTURE";
default:
return "unknown";
}
@@ -967,8 +969,10 @@
return String16("AudioIn");
case OFFLOAD:
return String16("AudioOffload");
- case MMAP:
- return String16("Mmap");
+ case MMAP_PLAYBACK:
+ return String16("MmapPlayback");
+ case MMAP_CAPTURE:
+ return String16("MmapCapture");
default:
ALOG_ASSERT(false);
return String16("AudioUnknown");
@@ -1477,7 +1481,7 @@
}
void AudioFlinger::ThreadBase::onEffectEnable(const sp<EffectModule>& effect) {
- if (mType == OFFLOAD || mType == MMAP) {
+ if (isOffloadOrMmap()) {
Mutex::Autolock _l(mLock);
broadcast_l();
}
@@ -1493,7 +1497,7 @@
}
void AudioFlinger::ThreadBase::onEffectDisable() {
- if (mType == OFFLOAD || mType == MMAP) {
+ if (isOffloadOrMmap()) {
Mutex::Autolock _l(mLock);
broadcast_l();
}
@@ -4266,7 +4270,7 @@
const std::string patchSinksAsString = patchSinksToString(patch);
mThreadMetrics.logEndInterval();
- mThreadMetrics.logCreatePatch(patchSinksAsString);
+ mThreadMetrics.logCreatePatch(/* inDevices */ {}, patchSinksAsString);
mThreadMetrics.logBeginInterval();
// also dispatch to active AudioTracks for MediaMetrics
for (const auto &track : mActiveTracks) {
@@ -4815,19 +4819,24 @@
// DeferredOperations handles statistics after setting mixerStatus.
class DeferredOperations {
public:
- explicit DeferredOperations(mixer_state *mixerStatus)
- : mMixerStatus(mixerStatus) {}
+ DeferredOperations(mixer_state *mixerStatus, ThreadMetrics *threadMetrics)
+ : mMixerStatus(mixerStatus)
+ , mThreadMetrics(threadMetrics) {}
// when leaving scope, tally frames properly.
~DeferredOperations() {
// Tally underrun frames only if we are actually mixing (MIXER_TRACKS_READY)
// because that is when the underrun occurs.
// We do not distinguish between FastTracks and NormalTracks here.
+ size_t maxUnderrunFrames = 0;
if (*mMixerStatus == MIXER_TRACKS_READY && mUnderrunFrames.size() > 0) {
for (const auto &underrun : mUnderrunFrames) {
underrun.first->tallyUnderrunFrames(underrun.second);
+ maxUnderrunFrames = max(underrun.second, maxUnderrunFrames);
}
}
+ // send the max underrun frames for this mixer period
+ mThreadMetrics->logUnderrunFrames(maxUnderrunFrames);
}
// tallyUnderrunFrames() is called to update the track counters
@@ -4839,8 +4848,9 @@
private:
const mixer_state * const mMixerStatus;
+ ThreadMetrics * const mThreadMetrics;
std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
- } deferredOperations(&mixerStatus);
+ } deferredOperations(&mixerStatus, &mThreadMetrics);
// implicit nested scope for variable capture
bool noFastHapticTrack = true;
@@ -8434,6 +8444,17 @@
// AudioRecord mSampleRate and mChannelCount are constant due to AudioRecord API constraints.
// But if thread's mSampleRate or mChannelCount changes, how will that affect active tracks?
+
+ audio_input_flags_t flags = mInput->flags;
+ mediametrics::LogItem item(mThreadMetrics.getMetricsId());
+ item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
+ .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_FLAGS, toString(flags).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)
+ .record();
}
uint32_t AudioFlinger::RecordThread::getInputFramesLost()
@@ -8564,7 +8585,7 @@
const std::string pathSourcesAsString = patchSourcesToString(patch);
mThreadMetrics.logEndInterval();
- mThreadMetrics.logCreatePatch(pathSourcesAsString);
+ mThreadMetrics.logCreatePatch(pathSourcesAsString, /* outDevices */ {});
mThreadMetrics.logBeginInterval();
// also dispatch to active AudioRecords
for (const auto &track : mActiveTracks) {
@@ -8678,7 +8699,7 @@
AudioFlinger::MmapThread::MmapThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady, bool isOut)
- : ThreadBase(audioFlinger, id, MMAP, systemReady, isOut),
+ : ThreadBase(audioFlinger, id, (isOut ? MMAP_PLAYBACK : MMAP_CAPTURE), systemReady, isOut),
mSessionId(AUDIO_SESSION_NONE),
mPortId(AUDIO_PORT_HANDLE_NONE),
mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 5b8c081..c1ac2e4 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -30,7 +30,8 @@
DUPLICATING, // Thread class is DuplicatingThread
RECORD, // Thread class is RecordThread
OFFLOAD, // Thread class is OffloadThread
- MMAP // control thread for MMAP stream
+ MMAP_PLAYBACK, // Thread class for MMAP playback stream
+ MMAP_CAPTURE, // Thread class for MMAP capture stream
// If you add any values here, also update ThreadBase::threadTypeToString()
};
@@ -332,6 +333,17 @@
bool isOutput() const { return mIsOut; }
+ bool isOffloadOrMmap() const {
+ switch (mType) {
+ case OFFLOAD:
+ case MMAP_PLAYBACK:
+ case MMAP_CAPTURE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
virtual sp<StreamHalInterface> stream() const = 0;
sp<EffectHandle> createEffect_l(
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
index 399c788..12bd341 100644
--- a/services/audioflinger/TrackMetrics.h
+++ b/services/audioflinger/TrackMetrics.h
@@ -67,16 +67,21 @@
mIntervalStartTimeNs = systemTime();
}
- void logConstructor(pid_t creatorPid, uid_t creatorUid) const {
+ void logConstructor(pid_t creatorPid, uid_t creatorUid,
+ audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT) 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)
+ mediametrics::LogItem item(mMetricsId);
+ item.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();
+ AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR);
+ // log streamType from the service, since client doesn't know chosen streamType.
+ if (streamType != AUDIO_STREAM_DEFAULT) {
+ item.set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(streamType).c_str());
+ }
+ item.record();
}
// Called when we are removed from the Thread.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 58c61c9..73a40d3 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -602,7 +602,7 @@
}
// Once this item is logged by the server, the client can add properties.
- mTrackMetrics.logConstructor(creatorPid, uid);
+ mTrackMetrics.logConstructor(creatorPid, uid, streamType);
}
AudioFlinger::PlaybackThread::Track::~Track()
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index e50fbe8..6138d32 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -49,47 +49,13 @@
// Perhaps report this.
}));
- // Check underruns
+ // Handle device use record statistics
mActions.addAction(
- AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
- std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN),
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
std::make_shared<AnalyticsActions::Function>(
[this](const std::shared_ptr<const android::mediametrics::Item> &item){
- std::string threadId = item->getKey().substr(
- sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) - 1);
- std::string outputDevices;
- mAnalyticsState->timeMachine().get(
- item->getKey(), AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
- ALOGD("(key=%s) Thread underrun event detected on io handle:%s device:%s",
- item->getKey().c_str(), threadId.c_str(), outputDevices.c_str());
- if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
- // report this for Bluetooth
- }
- }));
-
- // Check latencies, playback and startup
- mActions.addAction(
- AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_LATENCYMS,
- std::monostate{}, // accept any value
- std::make_shared<AnalyticsActions::Function>(
- [this](const std::shared_ptr<const android::mediametrics::Item> &item){
- double latencyMs{};
- double startupMs{};
- if (!item->get(AMEDIAMETRICS_PROP_LATENCYMS, &latencyMs)
- || !item->get(AMEDIAMETRICS_PROP_STARTUPMS, &startupMs)) return;
-
- std::string trackId = item->getKey().substr(
- sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) - 1);
- std::string thread = getThreadFromTrack(item->getKey());
- std::string outputDevices;
- mAnalyticsState->timeMachine().get(
- thread, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
- ALOGD("(key=%s) Track latencyMs:%lf startupMs:%lf detected on port:%s device:%s",
- item->getKey().c_str(), latencyMs, startupMs,
- trackId.c_str(), outputDevices.c_str());
- if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
- // report this for Bluetooth
- }
+ mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
}));
// Handle device use thread statistics
@@ -98,7 +64,7 @@
std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
std::make_shared<AnalyticsActions::Function>(
[this](const std::shared_ptr<const android::mediametrics::Item> &item){
- mDeviceUse.endAudioIntervalGroup(item, false /* isTrack */);
+ mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
}));
// Handle device use track statistics
@@ -107,10 +73,11 @@
std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
std::make_shared<AnalyticsActions::Function>(
[this](const std::shared_ptr<const android::mediametrics::Item> &item){
- mDeviceUse.endAudioIntervalGroup(item, true /* isTrack */);
+ mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
}));
- // Handle device routing statistics
+
+ // Handle device connection statistics
// We track connections (not disconnections) for the time to connect.
// TODO: consider BT requests in their A2dp service
@@ -119,7 +86,7 @@
// AudioDeviceBroker.postA2dpActiveDeviceChange
mActions.addAction(
"audio.device.a2dp.state",
- std::string("connected"),
+ "connected",
std::make_shared<AnalyticsActions::Function>(
[this](const std::shared_ptr<const android::mediametrics::Item> &item){
mDeviceConnection.a2dpConnected(item);
@@ -133,6 +100,17 @@
mDeviceConnection.createPatch(item);
}));
+ // Called from BT service
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
+ "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
+ "." AMEDIAMETRICS_PROP_STATE,
+ "connected",
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
+ }));
+
// Handle power usage
mActions.addAction(
AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
@@ -248,11 +226,12 @@
// DeviceUse helper class.
void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
- const std::shared_ptr<const android::mediametrics::Item> &item, bool isTrack) const {
+ const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
const std::string& key = item->getKey();
const std::string id = key.substr(
- (isTrack ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
- : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD))
+ (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
+ : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
+ : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
- 1);
// deliver statistics
int64_t deviceTimeNs = 0;
@@ -264,6 +243,9 @@
int32_t frameCount = 0;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
+ std::string inputDevices;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevices);
int32_t intervalCount = 0;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
@@ -273,29 +255,128 @@
int32_t sampleRate = 0;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
- int32_t underrun = 0;
+ std::string flags;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
- key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
+ key, AMEDIAMETRICS_PROP_FLAGS, &flags);
+ // We may have several devices.
+ // Strings allow us to mix input and output devices together.
+ // TODO: review if we want to separate them.
+ std::stringstream ss;
+ for (const auto& devicePairs : { outputDevices, inputDevices }) {
+ const auto devaddrvec = MediaMetricsService::getDeviceAddressPairs(devicePairs);
+ for (const auto& [device, addr] : devaddrvec) {
+ if (ss.tellp() > 0) ss << "|"; // delimit devices with '|'.
+ ss << device;
+ }
+ }
+ std::string devices = ss.str();
// Get connected device name if from bluetooth.
bool isBluetooth = false;
- std::string name;
+ std::string deviceNames; // we only have one device name at this time.
if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
isBluetooth = true;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
- "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &name);
+ "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
+ // We don't check if deviceName is sanitized.
+ // TODO: remove reserved chars such as '|' and replace with a char like '_'.
}
- // We may have several devices. We only list the first device.
- // TODO: consider whether we should list all the devices separated by |
- std::string firstDevice = "unknown";
- auto devaddrvec = MediaMetricsService::getDeviceAddressPairs(outputDevices);
- if (devaddrvec.size() != 0) {
- firstDevice = devaddrvec[0].first;
- // DO NOT show the address.
- }
+ switch (itemType) {
+ case RECORD: {
+ std::string callerName;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
- if (isTrack) {
+ std::string packageName;
+ int64_t versionCode = 0;
+ int32_t uid = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
+ if (uid != -1) {
+ std::tie(packageName, versionCode) =
+ MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
+ }
+
+ int32_t selectedDeviceId = 0;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
+ std::string source;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_SOURCE, &source);
+
+ ALOGD("(key=%s) id:%s endAudioIntervalGroup devices:%s deviceNames:%s "
+ "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
+ "sampleRate:%d "
+ "packageName:%s "
+ "selectedDeviceId:%d "
+ "callerName:%s source:%s",
+ key.c_str(), id.c_str(), devices.c_str(), deviceNames.c_str(),
+ (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
+ sampleRate,
+ packageName.c_str(), selectedDeviceId,
+ callerName.c_str(), source.c_str());
+
+#ifdef STATSD
+ if (mAudioAnalytics.mDeliverStatistics) {
+ (void)android::util::stats_write(
+ android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED
+ /* timestamp, */
+ /* mediaApexVersion, */
+ , devices.c_str()
+ , deviceNames.c_str()
+ , deviceTimeNs
+ , encoding.c_str()
+ , frameCount
+ , intervalCount
+ , sampleRate
+ , flags.c_str()
+
+ , packageName.c_str()
+ , selectedDeviceId
+ , callerName.c_str()
+ , source.c_str()
+ );
+ }
+#endif
+ } break;
+ case THREAD: {
+ std::string type;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_TYPE, &type);
+ int32_t underrun = 0; // zero for record types
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
+ ALOGD("(key=%s) id:%s endAudioIntervalGroup devices:%s deviceNames:%s "
+ "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
+ "sampleRate:%d underrun:%d "
+ "flags:%s type:%s",
+ key.c_str(), id.c_str(), devices.c_str(), deviceNames.c_str(),
+ (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
+ sampleRate, underrun,
+ flags.c_str(), type.c_str());
+#ifdef STATSD
+ if (mAudioAnalytics.mDeliverStatistics) {
+ (void)android::util::stats_write(
+ android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED
+ /* timestamp, */
+ /* mediaApexVersion, */
+ , devices.c_str()
+ , deviceNames.c_str()
+ , deviceTimeNs
+ , encoding.c_str()
+ , frameCount
+ , intervalCount
+ , sampleRate
+ , flags.c_str()
+
+ , underrun
+ , type.c_str()
+ );
+ }
+#endif
+ } break;
+ case TRACK: {
std::string callerName;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
@@ -329,38 +410,44 @@
int32_t selectedDeviceId = 0;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
-
+ std::string streamType;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
+ int32_t underrun = 0;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
std::string usage;
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_USAGE, &usage);
- ALOGD("(key=%s) id:%s endAudioIntervalGroup device:%s name:%s "
+ ALOGD("(key=%s) id:%s endAudioIntervalGroup devices:%s deviceNames:%s "
"deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
"sampleRate:%d underrun:%d "
"callerName:%s contentType:%s "
- "deviceLatencyMs:%lf deviceStartupMs:%lf deviceVolume:%lf"
+ "deviceLatencyMs:%lf deviceStartupMs:%lf deviceVolume:%lf "
"packageName:%s playbackPitch:%lf playbackSpeed:%lf "
- "selectedDevceId:%d usage:%s",
- key.c_str(), id.c_str(), firstDevice.c_str(), name.c_str(),
+ "selectedDeviceId:%d streamType:%s usage:%s",
+ key.c_str(), id.c_str(), devices.c_str(), deviceNames.c_str(),
(long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
sampleRate, underrun,
callerName.c_str(), contentType.c_str(),
deviceLatencyMs, deviceStartupMs, deviceVolume,
packageName.c_str(), playbackPitch, playbackSpeed,
- selectedDeviceId, usage.c_str());
+ selectedDeviceId, streamType.c_str(), usage.c_str());
#ifdef STATSD
if (mAudioAnalytics.mDeliverStatistics) {
(void)android::util::stats_write(
android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED
/* timestamp, */
/* mediaApexVersion, */
- , firstDevice.c_str()
- , name.c_str()
+ , devices.c_str()
+ , deviceNames.c_str()
, deviceTimeNs
, encoding.c_str()
, frameCount
, intervalCount
, sampleRate
+ , flags.c_str()
, underrun
, packageName.c_str()
@@ -368,43 +455,14 @@
, (float)deviceStartupMs
, (float)deviceVolume
, selectedDeviceId
+ , streamType.c_str()
, usage.c_str()
, contentType.c_str()
, callerName.c_str()
);
}
#endif
- } else {
-
- std::string flags;
- mAudioAnalytics.mAnalyticsState->timeMachine().get(
- key, AMEDIAMETRICS_PROP_FLAGS, &flags);
-
- ALOGD("(key=%s) id:%s endAudioIntervalGroup device:%s name:%s "
- "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
- "sampleRate:%d underrun:%d "
- "flags:%s",
- key.c_str(), id.c_str(), firstDevice.c_str(), name.c_str(),
- (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
- sampleRate, underrun,
- flags.c_str());
-#ifdef STATSD
- if (mAudioAnalytics.mDeliverStatistics) {
- (void)android::util::stats_write(
- android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED
- /* timestamp, */
- /* mediaApexVersion, */
- , firstDevice.c_str()
- , name.c_str()
- , deviceTimeNs
- , encoding.c_str()
- , frameCount
- , intervalCount
- , sampleRate
- , underrun
- );
- }
-#endif
+ } break;
}
// Report this as needed.
@@ -417,49 +475,123 @@
void AudioAnalytics::DeviceConnection::a2dpConnected(
const std::shared_ptr<const android::mediametrics::Item> &item) {
const std::string& key = item->getKey();
-
- const int64_t connectedAtNs = item->getTimestamp();
+ const int64_t atNs = item->getTimestamp();
{
std::lock_guard l(mLock);
- mA2dpTimeConnectedNs = connectedAtNs;
- ++mA2dpConnectedAttempts;
+ mA2dpConnectionServiceNs = atNs;
+ ++mA2dpConnectionServices;
+
+ if (mA2dpConnectionRequestNs == 0) {
+ mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
+ }
+ // This sets the time we were connected. Now we look for the delta in the future.
}
std::string name;
item->get(AMEDIAMETRICS_PROP_NAME, &name);
- ALOGD("(key=%s) a2dp connected device:%s "
- "connectedAtNs:%lld",
- key.c_str(), name.c_str(),
- (long long)connectedAtNs);
- // Note - we need to be able to cancel a timed event
- mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
- // This sets the time we were connected. Now we look for the delta in the future.
+ ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
+ key.c_str(), name.c_str(), (long long)atNs);
+
}
void AudioAnalytics::DeviceConnection::createPatch(
const std::shared_ptr<const android::mediametrics::Item> &item) {
std::lock_guard l(mLock);
- if (mA2dpTimeConnectedNs == 0) return; // ignore
+ if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
const std::string& key = item->getKey();
std::string outputDevices;
item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
- if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
+ if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
// TODO compare address
- const int64_t timeDiff = item->getTimestamp() - mA2dpTimeConnectedNs;
+ int64_t timeDiff = item->getTimestamp();
+ if (mA2dpConnectionRequestNs == 0) {
+ ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
+ timeDiff -= mA2dpConnectionServiceNs;
+ } else {
+ timeDiff -= mA2dpConnectionRequestNs;
+ }
ALOGD("(key=%s) A2DP device connection time: %lld", key.c_str(), (long long)timeDiff);
- mA2dpTimeConnectedNs = 0; // reset counter.
- ++mA2dpConnectedSuccesses;
+ mA2dpConnectionRequestNs = 0;
+ mA2dpConnectionServiceNs = 0;
+ ++mA2dpConnectionSuccesses;
+
+#ifdef STATSD
+ if (mAudioAnalytics.mDeliverStatistics) {
+ (void)android::util::stats_write(
+ android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
+ /* timestamp, */
+ /* mediaApexVersion, */
+ , "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"
+ , android::util::MEDIAMETRICS_AUDIO_DEVICE_CONNECTION_REPORTED__RESULT__SUCCESS
+ , /* connection_time_ms */ timeDiff * 1e-6 /* NS to MS */
+ , /* connection_count */ 1
+ );
+ }
+#endif
}
}
+// Called through AudioManager when the BT service wants to enable
+void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ const std::shared_ptr<const android::mediametrics::Item> &item) {
+ const int64_t atNs = item->getTimestamp();
+ const std::string& key = item->getKey();
+ std::string state;
+ item->get(AMEDIAMETRICS_PROP_STATE, &state);
+ if (state != "connected") return;
+ {
+ std::lock_guard l(mLock);
+ mA2dpConnectionRequestNs = atNs;
+ ++mA2dpConnectionRequests;
+ }
+ ALOGD("(key=%s) a2dp connection request atNs:%lld",
+ key.c_str(), (long long)atNs);
+ // TODO: attempt to cancel a timed event, rather than let it expire.
+ mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
+}
+
void AudioAnalytics::DeviceConnection::expire() {
std::lock_guard l(mLock);
- if (mA2dpTimeConnectedNs == 0) return; // ignore
+ if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
+ if (mA2dpConnectionServiceNs == 0) {
+ ALOGD("A2DP device connection service cancels");
+ ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
- // An expiration may occur because there is no audio playing.
+#ifdef STATSD
+ if (mAudioAnalytics.mDeliverStatistics) {
+ (void)android::util::stats_write(
+ android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
+ /* timestamp, */
+ /* mediaApexVersion, */
+ , "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"
+ , android::util::MEDIAMETRICS_AUDIO_DEVICE_CONNECTION_REPORTED__RESULT__JAVA_SERVICE_CANCEL
+ , /* connection_time_ms */ 0.f
+ , /* connection_count */ 1
+ );
+ }
+#endif
+ return;
+ }
+
+ // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
+ // Should we check elsewhere?
// TODO: disambiguate this case.
- ALOGD("A2DP device connection expired");
- ++mA2dpConnectedFailures; // this is not a true failure.
- mA2dpTimeConnectedNs = 0;
+ ALOGD("A2DP device connection expired, state unknown");
+ mA2dpConnectionRequestNs = 0;
+ mA2dpConnectionServiceNs = 0;
+ ++mA2dpConnectionUnknowns; // connection result unknown
+#ifdef STATSD
+ if (mAudioAnalytics.mDeliverStatistics) {
+ (void)android::util::stats_write(
+ android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
+ /* timestamp, */
+ /* mediaApexVersion, */
+ , "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"
+ , android::util::MEDIAMETRICS_AUDIO_DEVICE_CONNECTION_REPORTED__RESULT__UNKNOWN
+ , /* connection_time_ms */ 0.f
+ , /* connection_count */ 1
+ );
+ }
+#endif
}
} // namespace android
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/AudioAnalytics.h
index f9c776d..9089d6f 100644
--- a/services/mediametrics/AudioAnalytics.h
+++ b/services/mediametrics/AudioAnalytics.h
@@ -83,6 +83,17 @@
private:
+ /*
+ * AudioAnalytics class does not contain a monitor mutex.
+ * Instead, all of its variables are individually locked for access.
+ * Since data and items are generally added only (gc removes it), this is a reasonable
+ * compromise for availability/concurrency versus consistency.
+ *
+ * It is possible for concurrent threads to be reading and writing inside of AudioAnalytics.
+ * Reads based on a prior time (e.g. one second) in the past from the TimeMachine can be
+ * used to achieve better consistency if needed.
+ */
+
/**
* Checks for any pending actions for a particular item.
*
@@ -117,12 +128,19 @@
// TODO: Consider statistics aggregation.
class DeviceUse {
public:
+ enum ItemType {
+ RECORD = 0,
+ THREAD = 1,
+ TRACK = 2,
+ };
+
explicit DeviceUse(AudioAnalytics &audioAnalytics) : mAudioAnalytics{audioAnalytics} {}
// Called every time an endAudioIntervalGroup message is received.
void endAudioIntervalGroup(
const std::shared_ptr<const android::mediametrics::Item> &item,
- bool isTrack) const;
+ ItemType itemType) const;
+
private:
AudioAnalytics &mAudioAnalytics;
} mDeviceUse{*this};
@@ -144,6 +162,10 @@
void createPatch(
const std::shared_ptr<const android::mediametrics::Item> &item);
+ // Called through AudioManager when the BT service wants to notify connection
+ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+ const std::shared_ptr<const android::mediametrics::Item> &item);
+
// When the timer expires.
void expire();
@@ -151,10 +173,16 @@
AudioAnalytics &mAudioAnalytics;
mutable std::mutex mLock;
- int64_t mA2dpTimeConnectedNs GUARDED_BY(mLock) = 0;
- int32_t mA2dpConnectedAttempts GUARDED_BY(mLock) = 0;
- int32_t mA2dpConnectedSuccesses GUARDED_BY(mLock) = 0;
- int32_t mA2dpConnectedFailures GUARDED_BY(mLock) = 0;
+ int64_t mA2dpConnectionRequestNs GUARDED_BY(mLock) = 0; // Time for BT service request.
+ int64_t mA2dpConnectionServiceNs GUARDED_BY(mLock) = 0; // Time audio service agrees.
+
+ int32_t mA2dpConnectionRequests GUARDED_BY(mLock) = 0;
+ int32_t mA2dpConnectionServices GUARDED_BY(mLock) = 0;
+
+ // See the statsd atoms.proto
+ int32_t mA2dpConnectionSuccesses GUARDED_BY(mLock) = 0;
+ int32_t mA2dpConnectionJavaServiceCancels GUARDED_BY(mLock) = 0;
+ int32_t mA2dpConnectionUnknowns GUARDED_BY(mLock) = 0;
} mDeviceConnection{*this};
AudioPowerUsage mAudioPowerUsage{this};
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index dba9fb9..531bfa1 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -225,7 +225,7 @@
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
.record(); });
@@ -268,7 +268,7 @@
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
.record(); });
@@ -310,7 +310,7 @@
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
.record(); });
@@ -364,7 +364,7 @@
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
- .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
.set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
.record(); });