annotate src/vamp-hostsdk/PluginLoader.cpp @ 525:8c18bdaad04f c++11-mutex

Avoid simple static allocation of mutex, as it could lead to mutex being destroyed before last adapter that needs to use it (since adapters are usually also static)
author Chris Cannam
date Mon, 09 Sep 2019 10:24:13 +0100
parents 762b79b49c31
children
rev   line source
cannam@233 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@233 2
cannam@233 3 /*
cannam@233 4 Vamp
cannam@233 5
cannam@233 6 An API for audio analysis and feature extraction plugins.
cannam@233 7
cannam@233 8 Centre for Digital Music, Queen Mary, University of London.
Chris@423 9 Copyright 2006-2016 Chris Cannam and QMUL.
cannam@233 10
cannam@233 11 Permission is hereby granted, free of charge, to any person
cannam@233 12 obtaining a copy of this software and associated documentation
cannam@233 13 files (the "Software"), to deal in the Software without
cannam@233 14 restriction, including without limitation the rights to use, copy,
cannam@233 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@233 16 of the Software, and to permit persons to whom the Software is
cannam@233 17 furnished to do so, subject to the following conditions:
cannam@233 18
cannam@233 19 The above copyright notice and this permission notice shall be
cannam@233 20 included in all copies or substantial portions of the Software.
cannam@233 21
cannam@233 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@233 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@233 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@233 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@233 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@233 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@233 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@233 29
cannam@233 30 Except as contained in this notice, the names of the Centre for
cannam@233 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@233 32 shall not be used in advertising or otherwise to promote the sale,
cannam@233 33 use or other dealings in this Software without prior written
cannam@233 34 authorization.
cannam@233 35 */
cannam@233 36
cannam@233 37 #include <vamp-hostsdk/PluginLoader.h>
cannam@233 38 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
cannam@233 39 #include <vamp-hostsdk/PluginChannelAdapter.h>
cannam@233 40 #include <vamp-hostsdk/PluginBufferingAdapter.h>
Chris@390 41 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@390 42
Chris@390 43 #include <vamp/vamp.h>
Chris@390 44
Chris@390 45 #include "Files.h"
cannam@233 46
cannam@233 47 #include <fstream>
cannam@233 48
cannam@233 49 using namespace std;
cannam@233 50
cannam@263 51 _VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.cpp)
cannam@263 52
cannam@233 53 namespace Vamp {
cannam@233 54
cannam@233 55 namespace HostExt {
cannam@233 56
cannam@233 57 class PluginLoader::Impl
cannam@233 58 {
cannam@233 59 public:
cannam@233 60 Impl();
cannam@233 61 virtual ~Impl();
cannam@233 62
cannam@233 63 PluginKeyList listPlugins();
Chris@473 64 PluginKeyList listPluginsIn(vector<string>);
Chris@473 65 PluginKeyList listPluginsNotIn(vector<string>);
Chris@456 66
cannam@233 67 Plugin *loadPlugin(PluginKey key,
cannam@233 68 float inputSampleRate,
cannam@233 69 int adapterFlags);
Chris@423 70
cannam@233 71 PluginKey composePluginKey(string libraryName, string identifier);
cannam@233 72
cannam@233 73 PluginCategoryHierarchy getPluginCategory(PluginKey key);
cannam@233 74
cannam@233 75 string getLibraryPathForPlugin(PluginKey key);
cannam@233 76
cannam@233 77 static void setInstanceToClean(PluginLoader *instance);
cannam@233 78
cannam@233 79 protected:
cannam@233 80 class PluginDeletionNotifyAdapter : public PluginWrapper {
cannam@233 81 public:
cannam@233 82 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
cannam@233 83 virtual ~PluginDeletionNotifyAdapter();
cannam@233 84 protected:
cannam@233 85 Impl *m_loader;
cannam@233 86 };
cannam@233 87
cannam@233 88 class InstanceCleaner {
cannam@233 89 public:
cannam@233 90 InstanceCleaner() : m_instance(0) { }
cannam@233 91 ~InstanceCleaner() { delete m_instance; }
cannam@233 92 void setInstance(PluginLoader *instance) { m_instance = instance; }
cannam@233 93 protected:
cannam@233 94 PluginLoader *m_instance;
cannam@233 95 };
cannam@233 96
cannam@233 97 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
cannam@233 98
cannam@233 99 map<PluginKey, string> m_pluginLibraryNameMap;
cannam@233 100 bool m_allPluginsEnumerated;
Chris@473 101
Chris@473 102 struct Enumeration {
Chris@473 103 enum { All, SinglePlugin, InLibraries, NotInLibraries } type;
Chris@473 104 PluginKey key;
Chris@473 105 vector<string> libraryNames;
Chris@473 106 Enumeration() : type(All) { }
Chris@473 107 };
Chris@473 108 vector<string> listLibraryFilesFor(Enumeration);
Chris@473 109
Chris@473 110 /// Populate m_pluginLibraryNameMap and return a list of the keys
Chris@473 111 /// that were added to it
Chris@473 112 vector<PluginKey> enumeratePlugins(Enumeration);
cannam@233 113
cannam@233 114 map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
cannam@233 115 void generateTaxonomy();
cannam@233 116
cannam@233 117 map<Plugin *, void *> m_pluginLibraryHandleMap;
cannam@233 118
cannam@233 119 bool decomposePluginKey(PluginKey key,
cannam@233 120 string &libraryName, string &identifier);
cannam@233 121
cannam@233 122 static InstanceCleaner m_cleaner;
cannam@233 123 };
cannam@233 124
cannam@233 125 PluginLoader *
cannam@233 126 PluginLoader::m_instance = 0;
cannam@233 127
cannam@233 128 PluginLoader::Impl::InstanceCleaner
cannam@233 129 PluginLoader::Impl::m_cleaner;
cannam@233 130
cannam@233 131 PluginLoader::PluginLoader()
cannam@233 132 {
cannam@233 133 m_impl = new Impl();
cannam@233 134 }
cannam@233 135
cannam@233 136 PluginLoader::~PluginLoader()
cannam@233 137 {
cannam@233 138 delete m_impl;
cannam@233 139 }
cannam@233 140
cannam@233 141 PluginLoader *
cannam@233 142 PluginLoader::getInstance()
cannam@233 143 {
cannam@233 144 if (!m_instance) {
cannam@233 145 // The cleaner doesn't own the instance, because we leave the
cannam@233 146 // instance pointer in the base class for binary backwards
cannam@233 147 // compatibility reasons and to avoid waste
cannam@233 148 m_instance = new PluginLoader();
cannam@233 149 Impl::setInstanceToClean(m_instance);
cannam@233 150 }
cannam@233 151 return m_instance;
cannam@233 152 }
cannam@233 153
Chris@426 154 PluginLoader::PluginKeyList
cannam@233 155 PluginLoader::listPlugins()
cannam@233 156 {
cannam@233 157 return m_impl->listPlugins();
cannam@233 158 }
cannam@233 159
Chris@473 160 PluginLoader::PluginKeyList
Chris@473 161 PluginLoader::listPluginsIn(vector<string> libs)
Chris@473 162 {
Chris@473 163 return m_impl->listPluginsIn(libs);
Chris@473 164 }
Chris@473 165
Chris@473 166 PluginLoader::PluginKeyList
Chris@473 167 PluginLoader::listPluginsNotIn(vector<string> libs)
Chris@473 168 {
Chris@473 169 return m_impl->listPluginsNotIn(libs);
Chris@473 170 }
Chris@473 171
cannam@233 172 Plugin *
cannam@233 173 PluginLoader::loadPlugin(PluginKey key,
cannam@233 174 float inputSampleRate,
cannam@233 175 int adapterFlags)
cannam@233 176 {
cannam@233 177 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
cannam@233 178 }
cannam@233 179
cannam@233 180 PluginLoader::PluginKey
cannam@233 181 PluginLoader::composePluginKey(string libraryName, string identifier)
cannam@233 182 {
cannam@233 183 return m_impl->composePluginKey(libraryName, identifier);
cannam@233 184 }
cannam@233 185
cannam@233 186 PluginLoader::PluginCategoryHierarchy
cannam@233 187 PluginLoader::getPluginCategory(PluginKey key)
cannam@233 188 {
cannam@233 189 return m_impl->getPluginCategory(key);
cannam@233 190 }
cannam@233 191
cannam@233 192 string
cannam@233 193 PluginLoader::getLibraryPathForPlugin(PluginKey key)
cannam@233 194 {
cannam@233 195 return m_impl->getLibraryPathForPlugin(key);
cannam@233 196 }
cannam@233 197
cannam@233 198 PluginLoader::Impl::Impl() :
cannam@233 199 m_allPluginsEnumerated(false)
cannam@233 200 {
cannam@233 201 }
cannam@233 202
cannam@233 203 PluginLoader::Impl::~Impl()
cannam@233 204 {
cannam@233 205 }
cannam@233 206
cannam@233 207 void
cannam@233 208 PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
cannam@233 209 {
cannam@233 210 m_cleaner.setInstance(instance);
cannam@233 211 }
cannam@233 212
Chris@426 213 PluginLoader::PluginKeyList
cannam@233 214 PluginLoader::Impl::listPlugins()
cannam@233 215 {
Chris@477 216 if (!m_allPluginsEnumerated) enumeratePlugins(Enumeration());
cannam@233 217
cannam@233 218 vector<PluginKey> plugins;
Chris@477 219 for (map<PluginKey, string>::const_iterator i =
Chris@477 220 m_pluginLibraryNameMap.begin();
Chris@477 221 i != m_pluginLibraryNameMap.end(); ++i) {
Chris@477 222 plugins.push_back(i->first);
cannam@233 223 }
cannam@233 224
cannam@233 225 return plugins;
cannam@233 226 }
cannam@233 227
Chris@473 228 PluginLoader::PluginKeyList
Chris@473 229 PluginLoader::Impl::listPluginsIn(vector<string> libs)
Chris@473 230 {
Chris@473 231 Enumeration enumeration;
Chris@473 232 enumeration.type = Enumeration::InLibraries;
Chris@473 233 enumeration.libraryNames = libs;
Chris@473 234 return enumeratePlugins(enumeration);
Chris@473 235 }
Chris@473 236
Chris@473 237 PluginLoader::PluginKeyList
Chris@473 238 PluginLoader::Impl::listPluginsNotIn(vector<string> libs)
Chris@473 239 {
Chris@473 240 Enumeration enumeration;
Chris@473 241 enumeration.type = Enumeration::NotInLibraries;
Chris@473 242 enumeration.libraryNames = libs;
Chris@473 243 return enumeratePlugins(enumeration);
Chris@473 244 }
Chris@473 245
Chris@473 246 vector<string>
Chris@473 247 PluginLoader::Impl::listLibraryFilesFor(Enumeration enumeration)
Chris@473 248 {
Chris@473 249 Files::Filter filter;
Chris@473 250
Chris@473 251 switch (enumeration.type) {
Chris@473 252
Chris@473 253 case Enumeration::All:
Chris@473 254 filter.type = Files::Filter::All;
Chris@473 255 break;
Chris@473 256
Chris@473 257 case Enumeration::SinglePlugin:
Chris@473 258 {
Chris@473 259 string libraryName, identifier;
Chris@473 260 if (!decomposePluginKey(enumeration.key, libraryName, identifier)) {
Chris@473 261 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: "
Chris@473 262 << "Invalid plugin key \"" << enumeration.key
Chris@473 263 << "\" in enumerate" << std::endl;
Chris@477 264 return vector<string>();
Chris@473 265 }
Chris@473 266 filter.type = Files::Filter::Matching;
Chris@477 267 filter.libraryNames.clear();
Chris@477 268 filter.libraryNames.push_back(libraryName);
Chris@473 269 break;
Chris@473 270 }
Chris@473 271
Chris@473 272 case Enumeration::InLibraries:
Chris@473 273 filter.type = Files::Filter::Matching;
Chris@473 274 filter.libraryNames = enumeration.libraryNames;
Chris@473 275 break;
Chris@473 276
Chris@473 277 case Enumeration::NotInLibraries:
Chris@473 278 filter.type = Files::Filter::NotMatching;
Chris@473 279 filter.libraryNames = enumeration.libraryNames;
Chris@473 280 break;
Chris@473 281 }
Chris@473 282
Chris@473 283 return Files::listLibraryFilesMatching(filter);
Chris@473 284 }
Chris@473 285
Chris@473 286 vector<PluginLoader::PluginKey>
Chris@473 287 PluginLoader::Impl::enumeratePlugins(Enumeration enumeration)
cannam@233 288 {
cannam@233 289 string libraryName, identifier;
Chris@473 290 if (enumeration.type == Enumeration::SinglePlugin) {
Chris@473 291 decomposePluginKey(enumeration.key, libraryName, identifier);
Chris@473 292 }
Chris@390 293
Chris@473 294 vector<string> fullPaths = listLibraryFilesFor(enumeration);
cannam@233 295
Chris@473 296 // For these we should warn if a plugin can be loaded from a library
Chris@473 297 bool specific = (enumeration.type == Enumeration::SinglePlugin ||
Chris@473 298 enumeration.type == Enumeration::InLibraries);
Chris@473 299
Chris@473 300 vector<PluginKey> added;
Chris@473 301
Chris@390 302 for (size_t i = 0; i < fullPaths.size(); ++i) {
cannam@233 303
Chris@390 304 string fullPath = fullPaths[i];
Chris@390 305 void *handle = Files::loadLibrary(fullPath);
Chris@390 306 if (!handle) continue;
cannam@233 307
Chris@390 308 VampGetPluginDescriptorFunction fn =
Chris@390 309 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
Chris@390 310 (handle, "vampGetPluginDescriptor");
cannam@233 311
Chris@390 312 if (!fn) {
Chris@473 313 if (specific) {
Chris@473 314 cerr << "Vamp::HostExt::PluginLoader: "
Chris@473 315 << "No vampGetPluginDescriptor function found in library \""
cannam@295 316 << fullPath << "\"" << endl;
cannam@295 317 }
Chris@390 318 Files::unloadLibrary(handle);
Chris@390 319 continue;
Chris@390 320 }
cannam@233 321
Chris@390 322 int index = 0;
Chris@390 323 const VampPluginDescriptor *descriptor = 0;
Chris@390 324 bool found = false;
Chris@390 325
Chris@390 326 while ((descriptor = fn(VAMP_API_VERSION, index))) {
Chris@390 327 ++index;
Chris@390 328 if (identifier != "") {
Chris@473 329 if (descriptor->identifier != identifier) {
Chris@473 330 continue;
Chris@473 331 }
Chris@390 332 }
Chris@390 333 found = true;
Chris@390 334 PluginKey key = composePluginKey(fullPath, descriptor->identifier);
Chris@390 335 if (m_pluginLibraryNameMap.find(key) ==
Chris@390 336 m_pluginLibraryNameMap.end()) {
Chris@390 337 m_pluginLibraryNameMap[key] = fullPath;
Chris@390 338 }
Chris@473 339 added.push_back(key);
cannam@233 340 }
Chris@390 341
Chris@473 342 if (!found && specific) {
Chris@390 343 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
Chris@390 344 << identifier << "\" not found in library \""
Chris@390 345 << fullPath << "\"" << endl;
Chris@390 346 }
Chris@390 347
Chris@390 348 Files::unloadLibrary(handle);
cannam@233 349 }
cannam@233 350
Chris@473 351 if (enumeration.type == Enumeration::All) {
Chris@473 352 m_allPluginsEnumerated = true;
Chris@473 353 }
Chris@473 354
Chris@473 355 return added;
cannam@233 356 }
cannam@233 357
cannam@233 358 PluginLoader::PluginKey
cannam@233 359 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
cannam@233 360 {
Chris@390 361 string basename = Files::lcBasename(libraryName);
cannam@233 362 return basename + ":" + identifier;
cannam@233 363 }
cannam@233 364
cannam@233 365 bool
cannam@233 366 PluginLoader::Impl::decomposePluginKey(PluginKey key,
cannam@233 367 string &libraryName,
cannam@233 368 string &identifier)
cannam@233 369 {
cannam@233 370 string::size_type ki = key.find(':');
cannam@233 371 if (ki == string::npos) {
cannam@233 372 return false;
cannam@233 373 }
cannam@233 374
cannam@233 375 libraryName = key.substr(0, ki);
cannam@233 376 identifier = key.substr(ki + 1);
cannam@233 377 return true;
cannam@233 378 }
cannam@233 379
cannam@233 380 PluginLoader::PluginCategoryHierarchy
cannam@233 381 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
cannam@233 382 {
cannam@233 383 if (m_taxonomy.empty()) generateTaxonomy();
cannam@233 384 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
cannam@233 385 return PluginCategoryHierarchy();
cannam@233 386 }
cannam@233 387 return m_taxonomy[plugin];
cannam@233 388 }
cannam@233 389
cannam@233 390 string
cannam@233 391 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
cannam@233 392 {
cannam@233 393 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 394 if (m_allPluginsEnumerated) return "";
Chris@473 395 Enumeration enumeration;
Chris@473 396 enumeration.type = Enumeration::SinglePlugin;
Chris@473 397 enumeration.key = plugin;
Chris@473 398 enumeratePlugins(enumeration);
cannam@233 399 }
cannam@233 400 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 401 return "";
cannam@233 402 }
cannam@233 403 return m_pluginLibraryNameMap[plugin];
cannam@233 404 }
cannam@233 405
cannam@233 406 Plugin *
cannam@233 407 PluginLoader::Impl::loadPlugin(PluginKey key,
cannam@233 408 float inputSampleRate, int adapterFlags)
cannam@233 409 {
cannam@233 410 string libname, identifier;
cannam@233 411 if (!decomposePluginKey(key, libname, identifier)) {
cannam@233 412 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@233 413 << key << "\" in loadPlugin" << std::endl;
cannam@233 414 return 0;
cannam@233 415 }
cannam@233 416
cannam@233 417 string fullPath = getLibraryPathForPlugin(key);
cannam@293 418 if (fullPath == "") {
cannam@295 419 std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
cannam@293 420 return 0;
cannam@293 421 }
cannam@233 422
Chris@390 423 void *handle = Files::loadLibrary(fullPath);
cannam@233 424 if (!handle) return 0;
cannam@233 425
cannam@233 426 VampGetPluginDescriptorFunction fn =
Chris@390 427 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
cannam@233 428 (handle, "vampGetPluginDescriptor");
cannam@233 429
cannam@233 430 if (!fn) {
cannam@293 431 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
cannam@293 432 << fullPath << "\"" << endl;
Chris@390 433 Files::unloadLibrary(handle);
cannam@233 434 return 0;
cannam@233 435 }
cannam@233 436
cannam@233 437 int index = 0;
cannam@233 438 const VampPluginDescriptor *descriptor = 0;
cannam@233 439
cannam@233 440 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@233 441
cannam@233 442 if (string(descriptor->identifier) == identifier) {
cannam@233 443
cannam@233 444 Vamp::PluginHostAdapter *plugin =
cannam@233 445 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
cannam@233 446
cannam@233 447 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
cannam@233 448
cannam@233 449 m_pluginLibraryHandleMap[adapter] = handle;
cannam@233 450
cannam@233 451 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
cannam@233 452 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
cannam@233 453 adapter = new PluginInputDomainAdapter(adapter);
cannam@233 454 }
cannam@233 455 }
cannam@233 456
cannam@233 457 if (adapterFlags & ADAPT_BUFFER_SIZE) {
cannam@233 458 adapter = new PluginBufferingAdapter(adapter);
cannam@233 459 }
cannam@233 460
cannam@233 461 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
cannam@233 462 adapter = new PluginChannelAdapter(adapter);
cannam@233 463 }
cannam@233 464
cannam@233 465 return adapter;
cannam@233 466 }
cannam@233 467
cannam@233 468 ++index;
cannam@233 469 }
cannam@233 470
cannam@233 471 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
cannam@233 472 << identifier << "\" not found in library \""
cannam@233 473 << fullPath << "\"" << endl;
cannam@233 474
cannam@233 475 return 0;
cannam@233 476 }
cannam@233 477
cannam@233 478 void
cannam@233 479 PluginLoader::Impl::generateTaxonomy()
cannam@233 480 {
cannam@233 481 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
cannam@233 482
cannam@233 483 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@233 484 string libfragment = "/lib/";
cannam@233 485 vector<string> catpath;
cannam@233 486
cannam@233 487 string suffix = "cat";
cannam@233 488
cannam@233 489 for (vector<string>::iterator i = path.begin();
cannam@233 490 i != path.end(); ++i) {
cannam@233 491
cannam@233 492 // It doesn't matter that we're using literal forward-slash in
cannam@233 493 // this bit, as it's only relevant if the path contains
cannam@233 494 // "/lib/", which is only meaningful and only plausible on
cannam@233 495 // systems with forward-slash delimiters
cannam@233 496
cannam@233 497 string dir = *i;
cannam@233 498 string::size_type li = dir.find(libfragment);
cannam@233 499
cannam@233 500 if (li != string::npos) {
cannam@233 501 catpath.push_back
cannam@233 502 (dir.substr(0, li)
cannam@233 503 + "/share/"
cannam@233 504 + dir.substr(li + libfragment.length()));
cannam@233 505 }
cannam@233 506
cannam@233 507 catpath.push_back(dir);
cannam@233 508 }
cannam@233 509
cannam@233 510 char buffer[1024];
cannam@233 511
cannam@233 512 for (vector<string>::iterator i = catpath.begin();
cannam@233 513 i != catpath.end(); ++i) {
cannam@233 514
Chris@390 515 vector<string> files = Files::listFiles(*i, suffix);
cannam@233 516
cannam@233 517 for (vector<string>::iterator fi = files.begin();
cannam@233 518 fi != files.end(); ++fi) {
cannam@233 519
Chris@390 520 string filepath = Files::splicePath(*i, *fi);
cannam@233 521 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
cannam@233 522
cannam@233 523 if (is.fail()) {
cannam@233 524 // cerr << "failed to open: " << filepath << endl;
cannam@233 525 continue;
cannam@233 526 }
cannam@233 527
cannam@233 528 // cerr << "opened: " << filepath << endl;
cannam@233 529
cannam@233 530 while (!!is.getline(buffer, 1024)) {
cannam@233 531
cannam@233 532 string line(buffer);
cannam@233 533
cannam@233 534 // cerr << "line = " << line << endl;
cannam@233 535
cannam@233 536 string::size_type di = line.find("::");
cannam@233 537 if (di == string::npos) continue;
cannam@233 538
cannam@233 539 string id = line.substr(0, di);
cannam@233 540 string encodedCat = line.substr(di + 2);
cannam@233 541
cannam@233 542 if (id.substr(0, 5) != "vamp:") continue;
cannam@233 543 id = id.substr(5);
cannam@233 544
cannam@233 545 while (encodedCat.length() >= 1 &&
cannam@233 546 encodedCat[encodedCat.length()-1] == '\r') {
cannam@233 547 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
cannam@233 548 }
cannam@233 549
cannam@233 550 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
cannam@233 551
cannam@233 552 PluginCategoryHierarchy category;
cannam@233 553 string::size_type ai;
cannam@233 554 while ((ai = encodedCat.find(" > ")) != string::npos) {
cannam@233 555 category.push_back(encodedCat.substr(0, ai));
cannam@233 556 encodedCat = encodedCat.substr(ai + 3);
cannam@233 557 }
cannam@233 558 if (encodedCat != "") category.push_back(encodedCat);
cannam@233 559
cannam@233 560 m_taxonomy[id] = category;
cannam@233 561 }
cannam@233 562 }
cannam@233 563 }
cannam@233 564 }
cannam@233 565
cannam@233 566 void
cannam@233 567 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
cannam@233 568 {
cannam@233 569 void *handle = m_pluginLibraryHandleMap[adapter];
Chris@524 570 if (!handle) return;
Chris@524 571
cannam@233 572 m_pluginLibraryHandleMap.erase(adapter);
Chris@524 573
Chris@524 574 for (auto h: m_pluginLibraryHandleMap) {
Chris@524 575 if (h.second == handle) {
Chris@524 576 // still in use
Chris@524 577 return;
Chris@524 578 }
Chris@524 579 }
Chris@524 580
Chris@524 581 Files::unloadLibrary(handle);
cannam@233 582 }
cannam@233 583
cannam@233 584 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
cannam@233 585 Impl *loader) :
cannam@233 586 PluginWrapper(plugin),
cannam@233 587 m_loader(loader)
cannam@233 588 {
cannam@233 589 }
cannam@233 590
cannam@233 591 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
cannam@233 592 {
cannam@233 593 // We need to delete the plugin before calling pluginDeleted, as
cannam@233 594 // the delete call may require calling through to the descriptor
cannam@233 595 // (for e.g. cleanup) but pluginDeleted may unload the required
cannam@233 596 // library for the call. To prevent a double deletion when our
cannam@233 597 // parent's destructor runs (after this one), be sure to set
cannam@233 598 // m_plugin to 0 after deletion.
cannam@233 599 delete m_plugin;
cannam@233 600 m_plugin = 0;
cannam@233 601
cannam@233 602 if (m_loader) m_loader->pluginDeleted(this);
cannam@233 603 }
cannam@233 604
cannam@233 605 }
cannam@233 606
cannam@233 607 }
cannam@263 608
cannam@263 609 _VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)
cannam@263 610