mirror of
				https://github.com/oplus-giulia-dev/android_hardware_oplus
				synced 2025-11-04 13:55:35 +08:00 
			
		
		
		
	aidl: vibrator: qti: load effects from blobs
Change-Id: I55350bea3b7c4f31a62b60a6792ba2a343c72970
This commit is contained in:
		
				
					committed by
					
						
						Bruno Martins
					
				
			
			
				
	
			
			
			
						parent
						
							b0fb5146b2
						
					
				
				
					commit
					12190ecbc4
				
			@@ -3,9 +3,12 @@ cc_library_shared {
 | 
			
		||||
    vendor: true,
 | 
			
		||||
    srcs: [
 | 
			
		||||
        "effect.cpp",
 | 
			
		||||
        "VibrationEffectLoader.cpp"
 | 
			
		||||
    ],
 | 
			
		||||
    shared_libs: [
 | 
			
		||||
        "libbase",
 | 
			
		||||
        "libcutils",
 | 
			
		||||
        "libjsoncpp",
 | 
			
		||||
        "libutils",
 | 
			
		||||
    ],
 | 
			
		||||
    include_dirs: select(soong_config_variable("OPLUS_LINEAGE_VIBRATOR_HAL", "INCLUDE_DIR"), {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										151
									
								
								aidl/vibrator/qti/effect/VibrationEffectLoader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								aidl/vibrator/qti/effect/VibrationEffectLoader.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2025 The LineageOS Project
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define LOG_TAG "VibrationEffectLoader"
 | 
			
		||||
 | 
			
		||||
#include "VibrationEffectLoader.h"
 | 
			
		||||
 | 
			
		||||
#include <android-base/logging.h>
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Example of valid vibrator_effect.json:
 | 
			
		||||
 *
 | 
			
		||||
 * {
 | 
			
		||||
 *   "9999": {
 | 
			
		||||
 *     "def_style": [
 | 
			
		||||
 *       {
 | 
			
		||||
 *         "effect_file": "/odm/etc/vibrator/9999/def/effect_0.bin",
 | 
			
		||||
 *         "effect_id": 0,
 | 
			
		||||
 *         "play_rate_hz": 24000
 | 
			
		||||
 *       },
 | 
			
		||||
 *       ...
 | 
			
		||||
 *     ],
 | 
			
		||||
 *     "soft_style": [
 | 
			
		||||
 *       {
 | 
			
		||||
 *         "effect_file": "/odm/etc/vibrator/9999/soft/effect_0.bin",
 | 
			
		||||
 *         "effect_id": 0,
 | 
			
		||||
 *         "play_rate_hz": 24000
 | 
			
		||||
 *       },
 | 
			
		||||
 *       ...
 | 
			
		||||
 *     ]
 | 
			
		||||
 *   },
 | 
			
		||||
 *   ...
 | 
			
		||||
 * }
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
const auto kConfigPath = "/odm/etc/vibrator/vibrator_effect.json";
 | 
			
		||||
 | 
			
		||||
const auto kKeyDefStyle = "def_style";
 | 
			
		||||
const auto kKeyEffectFile = "effect_file";
 | 
			
		||||
const auto kKeyEffectId = "effect_id";
 | 
			
		||||
const auto kKeyPlayRateHz = "play_rate_hz";
 | 
			
		||||
 | 
			
		||||
const int8_t* LoadEffectDataFromFile(const std::string& path, uint32_t& length) {
 | 
			
		||||
    std::ifstream file(path, std::ios::binary);
 | 
			
		||||
    if (!file.is_open()) {
 | 
			
		||||
        LOG(ERROR) << "Failed to open data file: " << path;
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    file.seekg(0, std::ios::end);
 | 
			
		||||
    length = file.tellg();
 | 
			
		||||
    file.seekg(0, std::ios::beg);
 | 
			
		||||
 | 
			
		||||
    int8_t* data = new int8_t[length];
 | 
			
		||||
    if (!file.read(reinterpret_cast<char*>(data), length)) {
 | 
			
		||||
        LOG(ERROR) << "Failed to read data file: " << path;
 | 
			
		||||
        delete[] data;
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOG(DEBUG) << "Successfully read data from " << path << ", length=" << length;
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
};  // anonymous namespace
 | 
			
		||||
 | 
			
		||||
VibrationEffectLoader::VibrationEffectLoader() {
 | 
			
		||||
    std::ifstream config_stream(kConfigPath);
 | 
			
		||||
    if (!config_stream) {
 | 
			
		||||
        LOG(INFO) << "Couldn't open " << kConfigPath
 | 
			
		||||
                  << " for parsing, falling back to built-in effects.";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    auto node = parseEffectJson(config_stream);
 | 
			
		||||
    if (node.isNull()) {
 | 
			
		||||
        LOG(ERROR) << "Failed to parse " << kConfigPath << ", falling back to built-in effects.";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    loadEffects(std::move(node));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VibrationEffectLoader::~VibrationEffectLoader() {
 | 
			
		||||
    std::for_each(effect_map_.begin(), effect_map_.end(), [](auto&& v) { delete[] v.second.data; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
effect_stream* VibrationEffectLoader::getEffectStream(uint32_t effect_id) {
 | 
			
		||||
    auto entry = effect_map_.find(effect_id);
 | 
			
		||||
    if (entry != effect_map_.end()) {
 | 
			
		||||
        return &entry->second;
 | 
			
		||||
    }
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Json::Value VibrationEffectLoader::parseEffectJson(std::ifstream& config_stream) {
 | 
			
		||||
    Json::Value root;
 | 
			
		||||
    Json::CharReaderBuilder builder;
 | 
			
		||||
    std::string errs;
 | 
			
		||||
 | 
			
		||||
    if (!Json::parseFromStream(builder, config_stream, &root, &errs)) {
 | 
			
		||||
        LOG(ERROR) << "Failed to parse config JSON stream, error: " << errs;
 | 
			
		||||
        return Json::Value::null;
 | 
			
		||||
    }
 | 
			
		||||
    if (!root.isObject()) {
 | 
			
		||||
        LOG(ERROR) << "Root must be an object";
 | 
			
		||||
        return Json::Value::null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (auto&& node : root) {
 | 
			
		||||
        if (node.isObject()) {
 | 
			
		||||
            // TODO: also load soft_style when dynamic switching is supported
 | 
			
		||||
            node = node[kKeyDefStyle];
 | 
			
		||||
            if (node.isArray() && !node.empty()) {
 | 
			
		||||
                return node;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    LOG(ERROR) << "No effect node found in config";
 | 
			
		||||
    return Json::Value::null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VibrationEffectLoader::loadEffects(Json::Value&& effect_nodes) {
 | 
			
		||||
    for (auto&& node : effect_nodes) {
 | 
			
		||||
        auto attr = node[kKeyEffectId];
 | 
			
		||||
        if (!attr.isUInt()) {
 | 
			
		||||
            LOG(ERROR) << "Invalid effect_id";
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        uint32_t effect_id = attr.asUInt();
 | 
			
		||||
 | 
			
		||||
        attr = node[kKeyPlayRateHz];
 | 
			
		||||
        if (!attr.isUInt()) {
 | 
			
		||||
            LOG(ERROR) << "Invalid play_rate_hz";
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        uint32_t play_rate_hz = attr.asUInt();
 | 
			
		||||
 | 
			
		||||
        uint32_t length;
 | 
			
		||||
        auto data = LoadEffectDataFromFile(node[kKeyEffectFile].asString(), length);
 | 
			
		||||
        if (!data) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        effect_map_.emplace(effect_id, effect_stream{effect_id, length, play_rate_hz, data});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								aidl/vibrator/qti/effect/VibrationEffectLoader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								aidl/vibrator/qti/effect/VibrationEffectLoader.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2025 The LineageOS Project
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "effect.h"
 | 
			
		||||
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
class VibrationEffectLoader {
 | 
			
		||||
  public:
 | 
			
		||||
    VibrationEffectLoader();
 | 
			
		||||
    ~VibrationEffectLoader();
 | 
			
		||||
    effect_stream* getEffectStream(uint32_t effect_id);
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    Json::Value parseEffectJson(std::ifstream& config_stream);
 | 
			
		||||
    void loadEffects(Json::Value&& effect_nodes);
 | 
			
		||||
 | 
			
		||||
    std::unordered_map<uint32_t, effect_stream> effect_map_;
 | 
			
		||||
};
 | 
			
		||||
@@ -33,14 +33,17 @@
 | 
			
		||||
 | 
			
		||||
#include <VibrationEffectConfig.h>
 | 
			
		||||
 | 
			
		||||
const struct effect_stream *get_effect_stream(uint32_t effect_id)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
#include "VibrationEffectLoader.h"
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < ARRAY_SIZE(effects); i++) {
 | 
			
		||||
        if (effect_id == effects[i].effect_id)
 | 
			
		||||
            return &effects[i];
 | 
			
		||||
    }
 | 
			
		||||
namespace {
 | 
			
		||||
VibrationEffectLoader loader;
 | 
			
		||||
};  // anonymous namespace
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
const struct effect_stream* get_effect_stream(uint32_t effect_id) {
 | 
			
		||||
    auto ret = loader.getEffectStream(effect_id);
 | 
			
		||||
    if (ret) return ret;
 | 
			
		||||
 | 
			
		||||
    auto it = std::find_if(std::begin(effects), std::end(effects),
 | 
			
		||||
                           [&](auto&& v) { return v.effect_id == effect_id; });
 | 
			
		||||
    return it != std::end(effects) ? &*it : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user