annotate plugin/PluginPathSetter.cpp @ 1879:652c5360e682

Ensure transforms are populated before instantiateDefaultPluginFor runs - otherwise if we have prior knowledge of a transform id, we can find ourselves trying to instantiate it before the plugin factory has heard of it and e.g. knows which server to use
author Chris Cannam
date Thu, 25 Jun 2020 12:20:06 +0100
parents c014839f49c7
children
rev   line source
Chris@1472 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1472 2
Chris@1472 3 /*
Chris@1472 4 Sonic Visualiser
Chris@1472 5 An audio file viewer and annotation editor.
Chris@1472 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1472 7
Chris@1472 8 This program is free software; you can redistribute it and/or
Chris@1472 9 modify it under the terms of the GNU General Public License as
Chris@1472 10 published by the Free Software Foundation; either version 2 of the
Chris@1472 11 License, or (at your option) any later version. See the file
Chris@1472 12 COPYING included with this distribution for more information.
Chris@1472 13 */
Chris@1472 14
Chris@1472 15 #include "PluginPathSetter.h"
Chris@1472 16
Chris@1472 17 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@1472 18
Chris@1472 19 #include "RealTimePluginFactory.h"
Chris@1472 20 #include "LADSPAPluginFactory.h"
Chris@1472 21 #include "DSSIPluginFactory.h"
Chris@1472 22
Chris@1472 23 #include <QSettings>
Chris@1472 24 #include <QMutexLocker>
Chris@1472 25
Chris@1480 26 #include "system/System.h"
Chris@1481 27 #include "base/Preferences.h"
Chris@1481 28 #include "base/HelperExecPath.h"
Chris@1480 29
Chris@1472 30 QMutex
Chris@1472 31 PluginPathSetter::m_mutex;
Chris@1472 32
Chris@1472 33 PluginPathSetter::Paths
Chris@1472 34 PluginPathSetter::m_defaultPaths;
Chris@1472 35
Chris@1472 36 PluginPathSetter::Paths
Chris@1473 37 PluginPathSetter::m_environmentPaths;
Chris@1473 38
Chris@1473 39 std::map<QString, QString>
Chris@1473 40 PluginPathSetter::m_originalEnvValues;
Chris@1473 41
Chris@1481 42 PluginPathSetter::TypeKeys
Chris@1481 43 PluginPathSetter::m_supportedKeys;
Chris@1480 44
Chris@1481 45 using namespace std;
Chris@1481 46
Chris@1481 47 PluginPathSetter::TypeKeys
Chris@1481 48 PluginPathSetter::getSupportedKeys()
Chris@1481 49 {
Chris@1481 50 QMutexLocker locker(&m_mutex);
Chris@1481 51
Chris@1481 52 if (!m_supportedKeys.empty()) {
Chris@1481 53 return m_supportedKeys;
Chris@1481 54 }
Chris@1481 55
Chris@1481 56 TypeKeys keys;
Chris@1481 57 keys.push_back({ KnownPlugins::VampPlugin, KnownPlugins::FormatNative });
Chris@1481 58
Chris@1481 59 bool inProcess = Preferences::getInstance()->getRunPluginsInProcess();
Chris@1481 60 HelperExecPath hep(inProcess ?
Chris@1481 61 HelperExecPath::NativeArchitectureOnly :
Chris@1481 62 HelperExecPath::AllInstalled);
Chris@1481 63 auto execs = hep.getHelperExecutables("vamp-plugin-load-checker");
Chris@1481 64 if (execs.size() > 1) {
Chris@1481 65 keys.push_back({
Chris@1481 66 KnownPlugins::VampPlugin, KnownPlugins::FormatNonNative32Bit });
Chris@1481 67 }
Chris@1481 68
Chris@1481 69 keys.push_back({ KnownPlugins::LADSPAPlugin, KnownPlugins::FormatNative });
Chris@1481 70 keys.push_back({ KnownPlugins::DSSIPlugin, KnownPlugins::FormatNative });
Chris@1481 71
Chris@1481 72 m_supportedKeys = keys;
Chris@1481 73 return keys;
Chris@1481 74 }
Chris@1481 75
Chris@1481 76 // call with mutex held please
Chris@1473 77 PluginPathSetter::Paths
Chris@1481 78 PluginPathSetter::getEnvironmentPathsUncached(const TypeKeys &keys)
Chris@1472 79 {
Chris@1472 80 Paths paths;
Chris@1472 81
Chris@1481 82 for (auto k: keys) {
Chris@1472 83
Chris@1481 84 KnownPlugins kp(k.second);
Chris@1481 85
Chris@1481 86 auto path = kp.getPathFor(k.first);
Chris@1481 87 QStringList qPath;
Chris@1481 88 for (auto s: path) {
Chris@1481 89 qPath.push_back(QString::fromStdString(s));
Chris@1481 90 }
Chris@1481 91
Chris@1481 92 auto var = kp.getPathEnvironmentVariableFor(k.first);
Chris@1481 93 QString qVar = QString::fromStdString(var);
Chris@1481 94
Chris@1481 95 paths[k] = { qPath, qVar, true };
Chris@1472 96 }
Chris@1472 97
Chris@1473 98 return paths;
Chris@1473 99 }
Chris@1473 100
Chris@1473 101 PluginPathSetter::Paths
Chris@1473 102 PluginPathSetter::getDefaultPaths()
Chris@1473 103 {
Chris@1481 104 TypeKeys keys = getSupportedKeys();
Chris@1481 105
Chris@1473 106 QMutexLocker locker(&m_mutex);
Chris@1473 107
Chris@1481 108 Paths paths;
Chris@1481 109
Chris@1481 110 for (auto k: keys) {
Chris@1481 111
Chris@1481 112 KnownPlugins kp(k.second);
Chris@1481 113
Chris@1481 114 auto path = kp.getDefaultPathFor(k.first);
Chris@1481 115 QStringList qPath;
Chris@1481 116 for (auto s: path) {
Chris@1481 117 qPath.push_back(QString::fromStdString(s));
Chris@1481 118 }
Chris@1481 119
Chris@1481 120 auto var = kp.getPathEnvironmentVariableFor(k.first);
Chris@1481 121 QString qVar = QString::fromStdString(var);
Chris@1481 122
Chris@1481 123 paths[k] = { qPath, qVar, true };
Chris@1473 124 }
Chris@1473 125
Chris@1481 126 return paths;
Chris@1472 127 }
Chris@1472 128
Chris@1472 129 PluginPathSetter::Paths
Chris@1473 130 PluginPathSetter::getEnvironmentPaths()
Chris@1473 131 {
Chris@1481 132 TypeKeys keys = getSupportedKeys();
Chris@1481 133
Chris@1473 134 QMutexLocker locker(&m_mutex);
Chris@1473 135
Chris@1473 136 if (!m_environmentPaths.empty()) {
Chris@1473 137 return m_environmentPaths;
Chris@1473 138 }
Chris@1473 139
Chris@1481 140 m_environmentPaths = getEnvironmentPathsUncached(keys);
Chris@1473 141 return m_environmentPaths;
Chris@1473 142 }
Chris@1473 143
Chris@1481 144 QString
Chris@1481 145 PluginPathSetter::getSettingTagFor(TypeKey tk)
Chris@1481 146 {
Chris@1481 147 string tag = KnownPlugins(tk.second).getTagFor(tk.first);
Chris@1481 148 if (tk.second == KnownPlugins::FormatNonNative32Bit) {
Chris@1481 149 tag += "-32";
Chris@1481 150 }
Chris@1481 151 return QString::fromStdString(tag);
Chris@1481 152 }
Chris@1481 153
Chris@1473 154 PluginPathSetter::Paths
Chris@1472 155 PluginPathSetter::getPaths()
Chris@1472 156 {
Chris@1473 157 Paths paths = getEnvironmentPaths();
Chris@1472 158
Chris@1472 159 QSettings settings;
Chris@1472 160 settings.beginGroup("Plugins");
Chris@1472 161
Chris@1472 162 for (auto p: paths) {
Chris@1472 163
Chris@1481 164 TypeKey tk = p.first;
Chris@1481 165
Chris@1481 166 QString settingTag = getSettingTagFor(tk);
Chris@1472 167
Chris@1472 168 QStringList directories =
Chris@1481 169 settings.value(QString("directories-%1").arg(settingTag),
Chris@1472 170 p.second.directories)
Chris@1472 171 .toStringList();
Chris@1472 172 QString envVariable =
Chris@1481 173 settings.value(QString("env-variable-%1").arg(settingTag),
Chris@1472 174 p.second.envVariable)
Chris@1472 175 .toString();
Chris@1472 176 bool useEnvVariable =
Chris@1481 177 settings.value(QString("use-env-variable-%1").arg(settingTag),
Chris@1472 178 p.second.useEnvVariable)
Chris@1472 179 .toBool();
Chris@1480 180
Chris@1480 181 string envVarStr = envVariable.toStdString();
Chris@1480 182 string currentValue;
Chris@1480 183 (void)getEnvUtf8(envVarStr, currentValue);
Chris@1480 184
Chris@1480 185 if (currentValue != "" && useEnvVariable) {
Chris@1480 186 directories = QString::fromStdString(currentValue).split(
Chris@1472 187 #ifdef Q_OS_WIN
Chris@1472 188 ";"
Chris@1472 189 #else
Chris@1472 190 ":"
Chris@1472 191 #endif
Chris@1472 192 );
Chris@1472 193 }
Chris@1472 194
Chris@1481 195 paths[tk] = { directories, envVariable, useEnvVariable };
Chris@1472 196 }
Chris@1472 197
Chris@1472 198 settings.endGroup();
Chris@1472 199
Chris@1472 200 return paths;
Chris@1472 201 }
Chris@1472 202
Chris@1472 203 void
Chris@1472 204 PluginPathSetter::savePathSettings(Paths paths)
Chris@1472 205 {
Chris@1472 206 QSettings settings;
Chris@1472 207 settings.beginGroup("Plugins");
Chris@1472 208
Chris@1472 209 for (auto p: paths) {
Chris@1481 210 QString settingTag = getSettingTagFor(p.first);
Chris@1481 211 settings.setValue(QString("directories-%1").arg(settingTag),
Chris@1472 212 p.second.directories);
Chris@1481 213 settings.setValue(QString("env-variable-%1").arg(settingTag),
Chris@1472 214 p.second.envVariable);
Chris@1481 215 settings.setValue(QString("use-env-variable-%1").arg(settingTag),
Chris@1472 216 p.second.useEnvVariable);
Chris@1472 217 }
Chris@1472 218
Chris@1472 219 settings.endGroup();
Chris@1472 220 }
Chris@1472 221
Chris@1473 222 QString
Chris@1473 223 PluginPathSetter::getOriginalEnvironmentValue(QString envVariable)
Chris@1473 224 {
Chris@1473 225 if (m_originalEnvValues.find(envVariable) != m_originalEnvValues.end()) {
Chris@1473 226 return m_originalEnvValues.at(envVariable);
Chris@1473 227 } else {
Chris@1473 228 return QString();
Chris@1473 229 }
Chris@1473 230 }
Chris@1473 231
Chris@1472 232 void
Chris@1473 233 PluginPathSetter::initialiseEnvironmentVariables()
Chris@1472 234 {
Chris@1472 235 // Set the relevant environment variables from user configuration,
Chris@1472 236 // so that later lookups through the standard APIs will follow the
Chris@1472 237 // same paths as we have in the user config
Chris@1472 238
Chris@1472 239 // First ensure the default paths have been recorded for later, so
Chris@1472 240 // we don't erroneously re-read them from the environment
Chris@1472 241 // variables we've just set
Chris@1472 242 (void)getDefaultPaths();
Chris@1473 243 (void)getEnvironmentPaths();
Chris@1472 244
Chris@1472 245 Paths paths = getPaths();
Chris@1472 246
Chris@1472 247 for (auto p: paths) {
Chris@1472 248 QString envVariable = p.second.envVariable;
Chris@1480 249 string envVarStr = envVariable.toStdString();
Chris@1481 250 string currentValue;
Chris@1481 251 getEnvUtf8(envVarStr, currentValue);
Chris@1481 252 m_originalEnvValues[envVariable] = QString::fromStdString(currentValue);
Chris@1481 253 if (currentValue != "" && p.second.useEnvVariable) {
Chris@1472 254 // don't override
Chris@1482 255 SVDEBUG << "PluginPathSetter: for environment variable "
Chris@1482 256 << envVariable << ", useEnvVariable setting is false; "
Chris@1482 257 << "leaving current value alone: it is \""
Chris@1482 258 << currentValue << "\"" << endl;
Chris@1472 259 continue;
Chris@1472 260 }
Chris@1472 261 QString separator =
Chris@1472 262 #ifdef Q_OS_WIN
Chris@1472 263 ";"
Chris@1472 264 #else
Chris@1472 265 ":"
Chris@1472 266 #endif
Chris@1472 267 ;
Chris@1472 268 QString proposedValue = p.second.directories.join(separator);
Chris@1482 269 SVDEBUG << "PluginPathSetter: for environment variable "
Chris@1482 270 << envVariable << ", useEnvVariable setting is true or "
Chris@1482 271 << "variable is currently unset; "
Chris@1482 272 << "changing value from \"" << currentValue
Chris@1482 273 << "\" to setting preference of \"" << proposedValue
Chris@1482 274 << "\"" << endl;
Chris@1480 275 putEnvUtf8(envVarStr, proposedValue.toStdString());
Chris@1472 276 }
Chris@1472 277 }
Chris@1472 278