Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 255f610f authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "MediaMetrics: Add AudioAnalytics actions"

parents 00dd6d7e ea186fae
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -35,6 +35,49 @@

namespace android {

/*
 * MediaMetrics Keys and Properties for Audio.
 *
 * C/C++ friendly constants that ensure
 * 1) Compilation error on misspelling
 * 2) Consistent behavior and documentation.
 *
 * TODO: Move to separate header file.
 */

// Taxonomy of audio keys

// Key Prefixes are used for MediaMetrics Item Keys and ends with a ".".
// They must be appended with another value to make a key.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."

// The AudioRecord key appends the "trackId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."

// The AudioThread key appends the "threadId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread."

// The AudioTrack key appends the "trackId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK  AMEDIAMETRICS_KEY_PREFIX_AUDIO "track."

// Keys are strings used for MediaMetrics Item Keys
#define AMEDIAMETRICS_KEY_AUDIO_FLINGER       AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger"
#define AMEDIAMETRICS_KEY_AUDIO_POLICY        AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy"

// Props are properties allowed for Mediametrics Items.
#define AMEDIAMETRICS_PROP_EVENT          "event"          // string value (often func name)
#define AMEDIAMETRICS_PROP_LATENCYMS      "latencyMs"      // double value
#define AMEDIAMETRICS_PROP_OUTPUTDEVICES  "outputDevices"  // string value
#define AMEDIAMETRICS_PROP_STARTUPMS      "startupMs"      // double value
#define AMEDIAMETRICS_PROP_THREADID       "threadId"       // int32 value io handle

// 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_CTOR       "ctor"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR       "dtor"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN   "underrun" // from Thread

class IMediaMetricsService;
class Parcel;

+18 −0
Original line number Diff line number Diff line
@@ -55,6 +55,24 @@ public:
        return mTimeMachine.put(item, isTrusted) ?: mTransactionLog.put(item);
    }

    /**
     * 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.
     *
+61 −5
Original line number Diff line number Diff line
@@ -32,16 +32,60 @@ AudioAnalytics::AudioAnalytics()
    // 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 @@ AudioAnalytics::~AudioAnalytics()
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 @@ void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item
    }
}

// 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
+8 −0
Original line number Diff line number Diff line
@@ -72,6 +72,14 @@ private:
     */
    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;