MediaMetrics: Add AudioAnalytics actions
Underrun handling
Latency handling
Test: adb shell dumpsys media.metrics
Bug: 138583596
Change-Id: I4c0a5ba0f4f4ce9209146dab99433e33646d959b
diff --git a/services/mediametrics/AnalyticsState.h b/services/mediametrics/AnalyticsState.h
index 4711bb6..290ed21 100644
--- a/services/mediametrics/AnalyticsState.h
+++ b/services/mediametrics/AnalyticsState.h
@@ -56,6 +56,24 @@
}
/**
+ * Returns the TimeMachine.
+ *
+ * The TimeMachine object is internally locked, so access is safe and defined,
+ * but multiple threaded access may change results after calling.
+ */
+ TimeMachine& timeMachine() { return mTimeMachine; }
+ const TimeMachine& timeMachine() const { return mTimeMachine; }
+
+ /**
+ * Returns the TransactionLog.
+ *
+ * The TransactionLog object is internally locked, so access is safe and defined,
+ * but multiple threaded access may change results after calling.
+ */
+ TransactionLog& transactionLog() { return mTransactionLog; }
+ const TransactionLog& transactionLog() const { return mTransactionLog; }
+
+ /**
* Returns a pair consisting of the dump string, and the number of lines in the string.
*
* The number of lines in the returned pair is used as an optimization
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index f7ee051..126e501 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -32,16 +32,60 @@
// This triggers on an item of "audio.flinger"
// with a property "event" set to "AudioFlinger" (the constructor).
mActions.addAction(
- "audio.flinger.event",
- std::string("AudioFlinger"),
+ AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
std::make_shared<AnalyticsActions::Function>(
- [this](const std::shared_ptr<const android::mediametrics::Item> &){
- ALOGW("Audioflinger() constructor event detected");
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+ ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
*mAnalyticsState.get()));
// Note: get returns shared_ptr temp, whose lifetime is extended
// to end of full expression.
mAnalyticsState->clear(); // TODO: filter the analytics state.
+ // Perhaps report this.
+ }));
+
+ // Check underruns
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN),
+ 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
+ }
}));
}
@@ -53,7 +97,7 @@
status_t AudioAnalytics::submit(
const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
{
- if (!startsWith(item->getKey(), "audio.")) return BAD_VALUE;
+ if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
status_t status = mAnalyticsState->submit(item, isTrusted);
if (status != NO_ERROR) return status; // may not be permitted.
@@ -94,4 +138,16 @@
}
}
+// HELPER METHODS
+
+std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
+{
+ int32_t threadId_int32{};
+ if (mAnalyticsState->timeMachine().get(
+ track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
+ return {};
+ }
+ return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
+}
+
} // namespace android
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/AudioAnalytics.h
index be885ec..4a42e22 100644
--- a/services/mediametrics/AudioAnalytics.h
+++ b/services/mediametrics/AudioAnalytics.h
@@ -72,6 +72,14 @@
*/
void checkActions(const std::shared_ptr<const mediametrics::Item>& item);
+ // HELPER METHODS
+ /**
+ * Return the audio thread associated with an audio track name.
+ * e.g. "audio.track.32" -> "audio.thread.10" if the associated
+ * threadId for the audio track is 10.
+ */
+ std::string getThreadFromTrack(const std::string& track) const;
+
// Actions is individually locked
AnalyticsActions mActions;