import.cpp (4341B)
1 #include "import.h" 2 3 #include "config.h" 4 5 #include "baseLib/filesystem.h" 6 7 #include "networkLib/logging.h" 8 9 #include "synthLib/deviceException.h" 10 #include "synthLib/os.h" 11 12 #ifdef _WIN32 13 #define NOMINMAX 14 #include <Windows.h> 15 #define RTLD_LAZY 0 16 void* dlopen (const char* _filename, int) 17 { 18 return LoadLibraryA(_filename); 19 } 20 FARPROC dlsym (void* _handle, const char* _name) 21 { 22 return GetProcAddress (static_cast<HMODULE>(_handle), _name); 23 } 24 int dlclose(void* _handle) 25 { 26 return FreeLibrary(static_cast<HMODULE>(_handle)); 27 } 28 #else 29 #include <dlfcn.h> 30 #endif 31 32 namespace bridgeServer 33 { 34 Import::Import(const Config& _config) : m_config(_config) 35 { 36 findPlugins(); 37 } 38 39 Import::~Import() 40 { 41 for (const auto& it : m_loadedPlugins) 42 dlclose(it.second.handle); 43 m_loadedPlugins.clear(); 44 } 45 46 synthLib::Device* Import::createDevice(const synthLib::DeviceCreateParams& _params, const bridgeLib::PluginDesc& _desc) 47 { 48 std::scoped_lock lock(m_mutex); 49 50 auto it = m_loadedPlugins.find(_desc); 51 52 if(it == m_loadedPlugins.end()) 53 findPlugins(); // try to load additional plugins if not found 54 55 it = m_loadedPlugins.find(_desc); 56 if(it == m_loadedPlugins.end()) 57 { 58 LOGNET(networkLib::LogLevel::Warning, "Failed to create device for plugin '" << _desc.pluginName << "', version " << _desc.pluginVersion << ", id " << _desc.plugin4CC << ", no matching plugin available"); 59 return nullptr; // still not found 60 } 61 62 try 63 { 64 return it->second.funcCreate(_params); 65 } 66 catch(synthLib::DeviceException& e) 67 { 68 LOGNET(networkLib::LogLevel::Error, "Failed to create device for plugin '" << _desc.pluginName << "', version " << _desc.pluginVersion << ", id " << _desc.plugin4CC << 69 ", device creation caused exception: code " << static_cast<uint32_t>(e.errorCode()) << ", message: " << e.what()); 70 return nullptr; 71 } 72 } 73 74 bool Import::destroyDevice(const bridgeLib::PluginDesc& _desc, synthLib::Device* _device) 75 { 76 if(!_device) 77 return true; 78 79 std::scoped_lock lock(m_mutex); 80 81 const auto it = m_loadedPlugins.find(_desc); 82 if(it == m_loadedPlugins.end()) 83 { 84 assert(false && "plugin unloaded before device destroyed"); 85 return false; 86 } 87 it->second.funcDestroy(_device); 88 return true; 89 } 90 91 void Import::findPlugins() 92 { 93 findPlugins(m_config.pluginsPath); 94 findPlugins(synthLib::getModulePath() + "plugins/"); 95 } 96 97 void Import::findPlugins(const std::string& _rootPath) 98 { 99 findPlugins(_rootPath, ".dll"); 100 findPlugins(_rootPath, ".so"); 101 findPlugins(_rootPath, ".dylib"); 102 103 findPlugins(_rootPath, ".vst3"); 104 findPlugins(_rootPath, ".clap"); 105 findPlugins(_rootPath, ".lv2"); 106 } 107 108 void Import::findPlugins(const std::string& _rootPath, const std::string& _extension) 109 { 110 const auto path = synthLib::getModulePath() + "plugins/"; 111 std::vector<std::string> files; 112 baseLib::filesystem::findFiles(files, path, _extension, 0, std::numeric_limits<uint32_t>::max()); 113 114 for (const auto& file : files) 115 loadPlugin(file); 116 } 117 118 void Import::loadPlugin(const std::string& _file) 119 { 120 // load each plugin lib only once 121 if(m_loadedFiles.find(_file) != m_loadedFiles.end()) 122 return; 123 124 Plugin plugin; 125 126 plugin.handle = dlopen(_file.c_str(), RTLD_LAZY); 127 if(!plugin.handle) 128 return; 129 130 plugin.funcCreate = reinterpret_cast<FuncBridgeDeviceCreate>(dlsym(plugin.handle, "bridgeDeviceCreate")); // NOLINT(clang-diagnostic-cast-function-type-strict) 131 plugin.funcDestroy = reinterpret_cast<FuncBridgeDeviceDestroy>(dlsym(plugin.handle, "bridgeDeviceDestroy")); // NOLINT(clang-diagnostic-cast-function-type-strict) 132 plugin.funcGetDesc = reinterpret_cast<FuncBridgeDeviceGetDesc>(dlsym(plugin.handle, "bridgeDeviceGetDesc")); // NOLINT(clang-diagnostic-cast-function-type-strict) 133 134 if(!plugin.funcCreate || !plugin.funcDestroy || !plugin.funcGetDesc) 135 { 136 dlclose(plugin.handle); 137 return; 138 } 139 140 bridgeLib::PluginDesc desc; 141 plugin.funcGetDesc(desc); 142 143 if(desc.plugin4CC.empty() || desc.pluginName.empty() || desc.pluginVersion == 0) 144 { 145 dlclose(plugin.handle); 146 return; 147 } 148 149 if(m_loadedPlugins.find(desc) != m_loadedPlugins.end()) 150 { 151 dlclose(plugin.handle); 152 return; 153 } 154 155 LOGNET(networkLib::LogLevel::Info, "Found plugin '" << desc.pluginName << "', version " << desc.pluginVersion << ", id " << desc.plugin4CC); 156 157 m_loadedPlugins.insert({desc, plugin}); 158 m_loadedFiles.insert(_file); 159 } 160 }