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

Commit b942702a authored by Andy Hung's avatar Andy Hung
Browse files

MediaMetricsService: Parse Spatializer metrics items

Register an action for incoming Spatializer items.

Test: adb shell dumpsys media.metrics - check spatializer log
Bug: 233773341
Change-Id: I97c73fc1001f9ca669255820e48fb32c11489742
parent 1807ccea
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -57,6 +57,10 @@
// The Audio Spatializer key appends the spatializerId (currently 0)
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER AMEDIAMETRICS_KEY_PREFIX_AUDIO "spatializer."

// The Audio Spatializer device key appends the device type.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER_DEVICE \
        AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "device."

// The AudioStream key appends the "streamId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM  AMEDIAMETRICS_KEY_PREFIX_AUDIO "stream."

@@ -132,6 +136,7 @@

#define AMEDIAMETRICS_PROP_DIRECTION      "direction"      // string AAudio input or output
#define AMEDIAMETRICS_PROP_DURATIONNS     "durationNs"     // int64 duration time span
#define AMEDIAMETRICS_PROP_ENABLED        "enabled"        // string true/false.
#define AMEDIAMETRICS_PROP_ENCODING       "encoding"       // string value of format

#define AMEDIAMETRICS_PROP_EVENT          "event#"         // string value (often func name)
@@ -141,6 +146,8 @@
#define AMEDIAMETRICS_PROP_FLAGS          "flags"

#define AMEDIAMETRICS_PROP_FRAMECOUNT     "frameCount"     // int32
#define AMEDIAMETRICS_PROP_HASHEADTRACKER  "hasHeadTracker" // string true/false
#define AMEDIAMETRICS_PROP_HEADTRACKERENABLED "headTrackerEnabled" // string true/false
#define AMEDIAMETRICS_PROP_HEADTRACKINGMODES "headTrackingModes" // string |, like modes.
#define AMEDIAMETRICS_PROP_INPUTDEVICES   "inputDevices"   // string value
#define AMEDIAMETRICS_PROP_INTERNALTRACKID "internalTrackId" // int32
+113 −0
Original line number Diff line number Diff line
@@ -459,6 +459,15 @@ AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
            [this](const std::shared_ptr<const android::mediametrics::Item> &item){
                mAudioPowerUsage.checkCreatePatch(item);
            }));

    // Handle Spatializer - these keys are prefixed by "audio.spatializer."
    mActions.addAction(
        AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
        std::monostate{}, /* match any event */
        std::make_shared<AnalyticsActions::Function>(
            [this](const std::shared_ptr<const android::mediametrics::Item> &item){
                mSpatializer.onEvent(item);
            }));
}

AudioAnalytics::~AudioAnalytics()
@@ -1525,5 +1534,109 @@ std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
    return { s, n };
}

void AudioAnalytics::Spatializer::onEvent(
        const std::shared_ptr<const android::mediametrics::Item> &item)
{
    const auto key = item->getKey();

    if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;

    const std::string suffix =
            key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);

    std::string eventStr; // optional - find the actual event string.
    (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);

    const size_t delim = suffix.find('.'); // note could use split.
    if (delim == suffix.npos) {
        // on create with suffix == "0" for the first spatializer effect.

        std::string headTrackingModes;
        (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);

        std::string levels;
        (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);

        std::string modes;
        (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);

        int32_t channelMask = 0;
        (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);

        LOG(LOG_LEVEL) << "key:" << key
                << " headTrackingModes:" << headTrackingModes
                << " levels:" << levels
                << " modes:" << modes
                << " channelMask:" << channelMask
                ;

        const std::vector<int32_t> headTrackingModesVector =
                types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
        const std::vector<int32_t> levelsVector =
                types::vectorFromMap(levels, types::getSpatializerLevelMap());
        const std::vector<int32_t> modesVector =
                types::vectorFromMap(modes, types::getSpatializerModeMap());

        // TODO: send to statsd

        std::lock_guard lg(mLock);
        mSimpleLog.log("%s suffix: %s item: %s",
                __func__, suffix.c_str(), item->toString().c_str());
    } else {
        std::string subtype = suffix.substr(0, delim);
        if (subtype != "device") return; // not a device.

        std::string deviceType = suffix.substr(std::size("device.") - 1);

        std::string enabled;
        (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
        std::string hasHeadTracker;
        (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
        std::string headTrackerEnabled;
        (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);

        std::lock_guard lg(mLock);

        // Validate from our cached state
        DeviceState& deviceState = mDeviceStateMap[deviceType];

        if (!enabled.empty()) {
            if (enabled != deviceState.enabled) {
                deviceState.enabled = enabled;
                const bool enabledStatsd = enabled == "true";
                // TODO: send to statsd
                (void)mAudioAnalytics;
                (void)enabledStatsd;
            }
        }
        if (!hasHeadTracker.empty()) {
            if (hasHeadTracker != deviceState.hasHeadTracker) {
                deviceState.hasHeadTracker = hasHeadTracker;
                const bool supportedStatsd = hasHeadTracker == "true";
                // TODO: send to statsd
                (void)supportedStatsd;
            }
        }
        if (!headTrackerEnabled.empty()) {
            if (headTrackerEnabled != deviceState.headTrackerEnabled) {
                deviceState.headTrackerEnabled = headTrackerEnabled;
                const bool enabledStatsd = headTrackerEnabled == "true";
                // TODO: send to statsd
                (void)enabledStatsd;
            }
        }
        mSimpleLog.log("%s deviceType: %s item: %s",
                __func__, deviceType.c_str(), item->toString().c_str());
    }
}

std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
        int32_t lines, const char *prefix) const
{
    std::lock_guard lg(mLock);
    std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
    size_t n = std::count(s.begin(), s.end(), '\n');
    return { s, n };
}

} // namespace android::mediametrics
+128 −0
Original line number Diff line number Diff line
@@ -135,6 +135,50 @@ const std::unordered_map<std::string, int64_t>& getAudioDeviceOutMap() {
    return map;
}

// A map for the Java AudioDeviceInfo types to internal (native) output devices.
const std::unordered_map<std::string, int32_t>& getAudioDeviceOutCompactMap() {
    // DO NOT MODIFY VALUES (OK to add new ones).
    static std::unordered_map<std::string, int32_t> map{
        // should "unknown" go to AUDIO_DEVICE_NONE?
        {"earpiece", AUDIO_DEVICE_OUT_EARPIECE},
        {"speaker", AUDIO_DEVICE_OUT_SPEAKER},
        {"headset", AUDIO_DEVICE_OUT_WIRED_HEADSET},
        {"headphone", AUDIO_DEVICE_OUT_WIRED_HEADPHONE},
        {"bt_sco", AUDIO_DEVICE_OUT_BLUETOOTH_SCO},
        {"bt_sco_hs", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
        {"bt_sco_carkit", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
        {"bt_a2dp", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP},
        {"bt_a2dp_hp", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
        {"bt_a2dp_spk", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
        {"aux_digital", AUDIO_DEVICE_OUT_AUX_DIGITAL},
        {"hdmi", AUDIO_DEVICE_OUT_HDMI},
        {"analog_dock", AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET},
        {"digital_dock", AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET},
        {"usb_accessory", AUDIO_DEVICE_OUT_USB_ACCESSORY},
        {"usb_device", AUDIO_DEVICE_OUT_USB_DEVICE},
        {"remote_submix", AUDIO_DEVICE_OUT_REMOTE_SUBMIX},
        {"telephony_tx", AUDIO_DEVICE_OUT_TELEPHONY_TX},
        {"line", AUDIO_DEVICE_OUT_LINE},
        {"hdmi_arc", AUDIO_DEVICE_OUT_HDMI_ARC},
        {"hdmi_earc", AUDIO_DEVICE_OUT_HDMI_EARC},
        {"spdif", AUDIO_DEVICE_OUT_SPDIF},
        {"fm_transmitter", AUDIO_DEVICE_OUT_FM},
        {"aux_line", AUDIO_DEVICE_OUT_AUX_LINE},
        {"speaker_safe", AUDIO_DEVICE_OUT_SPEAKER_SAFE},
        {"ip", AUDIO_DEVICE_OUT_IP},
        {"bus", AUDIO_DEVICE_OUT_BUS},
        {"proxy", AUDIO_DEVICE_OUT_PROXY},
        {"usb_headset", AUDIO_DEVICE_OUT_USB_HEADSET},
        {"hearing_aid_out", AUDIO_DEVICE_OUT_HEARING_AID},
        {"echo_canceller", AUDIO_DEVICE_OUT_ECHO_CANCELLER},
        // default does not exist
        {"ble_headset", AUDIO_DEVICE_OUT_BLE_HEADSET},
        {"ble_speaker", AUDIO_DEVICE_OUT_BLE_SPEAKER},
        {"ble_broadcast", AUDIO_DEVICE_OUT_BLE_BROADCAST},
    };
    return map;
}

const std::unordered_map<std::string, int32_t>& getAudioThreadTypeMap() {
    // DO NOT MODIFY VALUES (OK to add new ones).
    // This may be found in frameworks/av/services/audioflinger/Threads.h
@@ -197,6 +241,41 @@ const std::unordered_map<std::string, int32_t>& getAAudioSharingMode() {
    return map;
}

const std::unordered_map<std::string, int32_t>& getHeadTrackingModeMap() {
    // DO NOT MODIFY VALUES(OK to add new ones).
    // frameworks/base/media/java/android/media/Spatializer.java
    // frameworks/av/media/libaudioclient/aidl/android/media/SpatializerHeadTrackingMode.aidl
    static std::unordered_map<std::string, int32_t> map {
        {"OTHER", 0},
        {"DISABLED", -1},
        {"RELATIVE_WORLD", 1},
        {"RELATIVE_SCREEN", 2},
    };
    return map;
}

const std::unordered_map<std::string, int32_t>& getSpatializerLevelMap() {
    // DO NOT MODIFY VALUES(OK to add new ones).
    // frameworks/base/media/java/android/media/Spatializer.java
    // frameworks/av/media/libaudioclient/aidl/android/media/SpatializerHeadTrackingMode.aidl
    static std::unordered_map<std::string, int32_t> map {
        {"NONE", 0},
        {"SPATIALIZER_MULTICHANNEL", 1},
        {"SPATIALIZER_MCHAN_BED_PLUS_OBJECTS", 2},
    };
    return map;
}

const std::unordered_map<std::string, int32_t>& getSpatializerModeMap() {
    // DO NOT MODIFY VALUES(OK to add new ones).
    // frameworks/av/media/libaudioclient/aidl/android/media/SpatializationMode.aidl
    static std::unordered_map<std::string, int32_t> map {
        {"SPATIALIZER_BINAURAL", 0},
        {"SPATIALIZER_TRANSAURAL", 1},
    };
    return map;
}

const std::unordered_map<std::string, int32_t>& getStatusMap() {
    // DO NOT MODIFY VALUES(OK to add new ones).
    static std::unordered_map<std::string, int32_t> map {
@@ -286,6 +365,22 @@ typename M::mapped_type flagsFromMap(const std::string &str, const M& map)
    return value;
}

std::vector<int32_t> vectorFromMap(
        const std::string &str, const std::unordered_map<std::string, int32_t>& map)
{
    std::vector<int32_t> v;

    if (str.empty()) return v;

    const auto result = stringutils::split(str, "|");
    for (const auto &s : result) {
        auto it = map.find(s);
        if (it == map.end()) continue;
        v.push_back(it->second);
    }
    return v;
}

template <>
int32_t lookup<CONTENT_TYPE>(const std::string &contentType)
{
@@ -462,6 +557,39 @@ std::string lookup<CALLER_NAME>(const std::string &callerName)
    return callerName;
}

template <>
int32_t lookup<HEAD_TRACKING_MODE>(const std::string& headTrackingMode)
{
    auto& map = getHeadTrackingModeMap();
    auto it = map.find(headTrackingMode);
    if (it == map.end()) {
        return 0;
    }
    return it->second;
}

template <>
int32_t lookup<SPATIALIZER_LEVEL>(const std::string& spatializerLevel)
{
    auto& map = getSpatializerLevelMap();
    auto it = map.find(spatializerLevel);
    if (it == map.end()) {
        return 0;
    }
    return it->second;
}

template <>
int32_t lookup<SPATIALIZER_MODE>(const std::string& spatializerMode)
{
    auto& map = getSpatializerModeMap();
    auto it = map.find(spatializerMode);
    if (it == map.end()) {
        return 0;
    }
    return it->second;
}

template <>
int32_t lookup<STATUS>(const std::string &status)
{
+9 −0
Original line number Diff line number Diff line
@@ -338,6 +338,15 @@ status_t MediaMetricsService::dump(int fd, const Vector<String16>& args)
                result << "-- some lines may be truncated --\n";
            }

            const int32_t spatializerLinesToDump = all ? INT32_MAX : 15;
            result << "\nSpatializer Message Log:";
            const auto [ spatializerDumpString, spatializerLines ] =
                    mAudioAnalytics.dumpSpatializer(spatializerLinesToDump);
            result << "\n" << spatializerDumpString;
            if (spatializerLines == spatializerLinesToDump) {
                result << "-- some lines may be truncated --\n";
            }

            result << "\nLogSessionId:\n"
                   << mediametrics::ValidateId::get()->dump();

+38 −0
Original line number Diff line number Diff line
@@ -92,6 +92,15 @@ public:
        return mHealth.dump(lines);
    }

    /**
     * Returns a pair consisting of the dump string and the number of lines in the string.
     *
     * Spatializer dump.
     */
    std::pair<std::string, int32_t> dumpSpatializer(int32_t lines = INT32_MAX) const {
        return mSpatializer.dump(lines);
    }

    void clear() {
        // underlying state is locked.
        mPreviousAnalyticsState->clear();
@@ -317,6 +326,35 @@ private:
        SimpleLog mSimpleLog GUARDED_BY(mLock) {64};
    } mHealth{*this};

    // Spatializer is a nested class that tracks related messages.
    class Spatializer {
    public:
        explicit Spatializer(AudioAnalytics &audioAnalytics)
            : mAudioAnalytics(audioAnalytics) {}

        // an item that starts with "audio.spatializer"
        void onEvent(const std::shared_ptr<const android::mediametrics::Item> &item);

        std::pair<std::string, int32_t> dump(
                int32_t lines = INT32_MAX, const char *prefix = nullptr) const;

    private:

        // Current device state as strings:
        // "" means unknown, "true" or "false".
        struct DeviceState {
            std::string enabled;
            std::string hasHeadTracker;
            std::string headTrackerEnabled;
        };

        AudioAnalytics& mAudioAnalytics;

        mutable std::mutex mLock;
        std::map<std::string, DeviceState> mDeviceStateMap GUARDED_BY(mLock);
        SimpleLog mSimpleLog GUARDED_BY(mLock) {64};
    } mSpatializer{*this};

    AudioPowerUsage mAudioPowerUsage;
};

Loading