annotate src/vamp-hostsdk/PluginLoader.cpp @ 263:4454843ff384

* OK, we're going to have to place the host stuff in its own namespace too. Otherwise our new SV build on OSX fails to load old plugins because they pull in the host namespace PluginBase and thus report the wrong Vamp version... *sigh*
author cannam
date Thu, 20 Nov 2008 15:01:30 +0000
parents 521734d2b498
children 1ed95908a397
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.
cannam@233 9 Copyright 2006-2007 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/PluginHostAdapter.h>
cannam@233 38 #include <vamp-hostsdk/PluginLoader.h>
cannam@233 39 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
cannam@233 40 #include <vamp-hostsdk/PluginChannelAdapter.h>
cannam@233 41 #include <vamp-hostsdk/PluginBufferingAdapter.h>
cannam@233 42
cannam@233 43 #include <fstream>
cannam@233 44 #include <cctype> // tolower
cannam@233 45
cannam@233 46 #include <cstring>
cannam@233 47
cannam@233 48 #ifdef _WIN32
cannam@233 49
cannam@233 50 #include <windows.h>
cannam@233 51 #include <tchar.h>
cannam@233 52 #define PLUGIN_SUFFIX "dll"
cannam@233 53
cannam@233 54 #else /* ! _WIN32 */
cannam@233 55
cannam@233 56 #include <dirent.h>
cannam@233 57 #include <dlfcn.h>
cannam@233 58
cannam@233 59 #ifdef __APPLE__
cannam@233 60 #define PLUGIN_SUFFIX "dylib"
cannam@233 61 #else /* ! __APPLE__ */
cannam@233 62 #define PLUGIN_SUFFIX "so"
cannam@233 63 #endif /* ! __APPLE__ */
cannam@233 64
cannam@233 65 #endif /* ! _WIN32 */
cannam@233 66
cannam@233 67 using namespace std;
cannam@233 68
cannam@263 69 _VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.cpp)
cannam@263 70
cannam@233 71 namespace Vamp {
cannam@233 72
cannam@233 73 namespace HostExt {
cannam@233 74
cannam@233 75 class PluginLoader::Impl
cannam@233 76 {
cannam@233 77 public:
cannam@233 78 Impl();
cannam@233 79 virtual ~Impl();
cannam@233 80
cannam@233 81 PluginKeyList listPlugins();
cannam@233 82
cannam@233 83 Plugin *loadPlugin(PluginKey key,
cannam@233 84 float inputSampleRate,
cannam@233 85 int adapterFlags);
cannam@233 86
cannam@233 87 PluginKey composePluginKey(string libraryName, string identifier);
cannam@233 88
cannam@233 89 PluginCategoryHierarchy getPluginCategory(PluginKey key);
cannam@233 90
cannam@233 91 string getLibraryPathForPlugin(PluginKey key);
cannam@233 92
cannam@233 93 static void setInstanceToClean(PluginLoader *instance);
cannam@233 94
cannam@233 95 protected:
cannam@233 96 class PluginDeletionNotifyAdapter : public PluginWrapper {
cannam@233 97 public:
cannam@233 98 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
cannam@233 99 virtual ~PluginDeletionNotifyAdapter();
cannam@233 100 protected:
cannam@233 101 Impl *m_loader;
cannam@233 102 };
cannam@233 103
cannam@233 104 class InstanceCleaner {
cannam@233 105 public:
cannam@233 106 InstanceCleaner() : m_instance(0) { }
cannam@233 107 ~InstanceCleaner() { delete m_instance; }
cannam@233 108 void setInstance(PluginLoader *instance) { m_instance = instance; }
cannam@233 109 protected:
cannam@233 110 PluginLoader *m_instance;
cannam@233 111 };
cannam@233 112
cannam@233 113 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
cannam@233 114
cannam@233 115 map<PluginKey, string> m_pluginLibraryNameMap;
cannam@233 116 bool m_allPluginsEnumerated;
cannam@233 117 void enumeratePlugins(PluginKey forPlugin = "");
cannam@233 118
cannam@233 119 map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
cannam@233 120 void generateTaxonomy();
cannam@233 121
cannam@233 122 map<Plugin *, void *> m_pluginLibraryHandleMap;
cannam@233 123
cannam@233 124 bool decomposePluginKey(PluginKey key,
cannam@233 125 string &libraryName, string &identifier);
cannam@233 126
cannam@233 127 void *loadLibrary(string path);
cannam@233 128 void unloadLibrary(void *handle);
cannam@233 129 void *lookupInLibrary(void *handle, const char *symbol);
cannam@233 130
cannam@233 131 string splicePath(string a, string b);
cannam@233 132 vector<string> listFiles(string dir, string ext);
cannam@233 133
cannam@233 134 static InstanceCleaner m_cleaner;
cannam@233 135 };
cannam@233 136
cannam@233 137 PluginLoader *
cannam@233 138 PluginLoader::m_instance = 0;
cannam@233 139
cannam@233 140 PluginLoader::Impl::InstanceCleaner
cannam@233 141 PluginLoader::Impl::m_cleaner;
cannam@233 142
cannam@233 143 PluginLoader::PluginLoader()
cannam@233 144 {
cannam@233 145 m_impl = new Impl();
cannam@233 146 }
cannam@233 147
cannam@233 148 PluginLoader::~PluginLoader()
cannam@233 149 {
cannam@233 150 delete m_impl;
cannam@233 151 }
cannam@233 152
cannam@233 153 PluginLoader *
cannam@233 154 PluginLoader::getInstance()
cannam@233 155 {
cannam@233 156 if (!m_instance) {
cannam@233 157 // The cleaner doesn't own the instance, because we leave the
cannam@233 158 // instance pointer in the base class for binary backwards
cannam@233 159 // compatibility reasons and to avoid waste
cannam@233 160 m_instance = new PluginLoader();
cannam@233 161 Impl::setInstanceToClean(m_instance);
cannam@233 162 }
cannam@233 163 return m_instance;
cannam@233 164 }
cannam@233 165
cannam@233 166 vector<PluginLoader::PluginKey>
cannam@233 167 PluginLoader::listPlugins()
cannam@233 168 {
cannam@233 169 return m_impl->listPlugins();
cannam@233 170 }
cannam@233 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
cannam@233 213 vector<PluginLoader::PluginKey>
cannam@233 214 PluginLoader::Impl::listPlugins()
cannam@233 215 {
cannam@233 216 if (!m_allPluginsEnumerated) enumeratePlugins();
cannam@233 217
cannam@233 218 vector<PluginKey> plugins;
cannam@233 219 for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
cannam@233 220 mi != m_pluginLibraryNameMap.end(); ++mi) {
cannam@233 221 plugins.push_back(mi->first);
cannam@233 222 }
cannam@233 223
cannam@233 224 return plugins;
cannam@233 225 }
cannam@233 226
cannam@233 227 void
cannam@233 228 PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
cannam@233 229 {
cannam@233 230 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@233 231
cannam@233 232 string libraryName, identifier;
cannam@233 233 if (forPlugin != "") {
cannam@233 234 if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
cannam@233 235 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@233 236 << forPlugin << "\" in enumerate" << std::endl;
cannam@233 237 return;
cannam@233 238 }
cannam@233 239 }
cannam@233 240
cannam@233 241 for (size_t i = 0; i < path.size(); ++i) {
cannam@233 242
cannam@233 243 vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
cannam@233 244
cannam@233 245 for (vector<string>::iterator fi = files.begin();
cannam@233 246 fi != files.end(); ++fi) {
cannam@233 247
cannam@233 248 if (libraryName != "") {
cannam@233 249 // libraryName is lowercased and lacking an extension,
cannam@233 250 // as it came from the plugin key
cannam@233 251 string temp = *fi;
cannam@233 252 for (size_t i = 0; i < temp.length(); ++i) {
cannam@233 253 temp[i] = tolower(temp[i]);
cannam@233 254 }
cannam@233 255 string::size_type pi = temp.find('.');
cannam@233 256 if (pi == string::npos) {
cannam@233 257 if (libraryName != temp) continue;
cannam@233 258 } else {
cannam@233 259 if (libraryName != temp.substr(0, pi)) continue;
cannam@233 260 }
cannam@233 261 }
cannam@233 262
cannam@233 263 string fullPath = path[i];
cannam@233 264 fullPath = splicePath(fullPath, *fi);
cannam@233 265 void *handle = loadLibrary(fullPath);
cannam@233 266 if (!handle) continue;
cannam@233 267
cannam@233 268 VampGetPluginDescriptorFunction fn =
cannam@233 269 (VampGetPluginDescriptorFunction)lookupInLibrary
cannam@233 270 (handle, "vampGetPluginDescriptor");
cannam@233 271
cannam@233 272 if (!fn) {
cannam@233 273 unloadLibrary(handle);
cannam@233 274 continue;
cannam@233 275 }
cannam@233 276
cannam@233 277 int index = 0;
cannam@233 278 const VampPluginDescriptor *descriptor = 0;
cannam@233 279
cannam@233 280 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@233 281 ++index;
cannam@233 282 if (identifier != "") {
cannam@233 283 if (descriptor->identifier != identifier) continue;
cannam@233 284 }
cannam@233 285 PluginKey key = composePluginKey(*fi, descriptor->identifier);
cannam@233 286 // std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
cannam@233 287 if (m_pluginLibraryNameMap.find(key) ==
cannam@233 288 m_pluginLibraryNameMap.end()) {
cannam@233 289 m_pluginLibraryNameMap[key] = fullPath;
cannam@233 290 }
cannam@233 291 }
cannam@233 292
cannam@233 293 unloadLibrary(handle);
cannam@233 294 }
cannam@233 295 }
cannam@233 296
cannam@233 297 if (forPlugin == "") m_allPluginsEnumerated = true;
cannam@233 298 }
cannam@233 299
cannam@233 300 PluginLoader::PluginKey
cannam@233 301 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
cannam@233 302 {
cannam@233 303 string basename = libraryName;
cannam@233 304
cannam@233 305 string::size_type li = basename.rfind('/');
cannam@233 306 if (li != string::npos) basename = basename.substr(li + 1);
cannam@233 307
cannam@233 308 li = basename.find('.');
cannam@233 309 if (li != string::npos) basename = basename.substr(0, li);
cannam@233 310
cannam@233 311 for (size_t i = 0; i < basename.length(); ++i) {
cannam@233 312 basename[i] = tolower(basename[i]);
cannam@233 313 }
cannam@233 314
cannam@233 315 return basename + ":" + identifier;
cannam@233 316 }
cannam@233 317
cannam@233 318 bool
cannam@233 319 PluginLoader::Impl::decomposePluginKey(PluginKey key,
cannam@233 320 string &libraryName,
cannam@233 321 string &identifier)
cannam@233 322 {
cannam@233 323 string::size_type ki = key.find(':');
cannam@233 324 if (ki == string::npos) {
cannam@233 325 return false;
cannam@233 326 }
cannam@233 327
cannam@233 328 libraryName = key.substr(0, ki);
cannam@233 329 identifier = key.substr(ki + 1);
cannam@233 330 return true;
cannam@233 331 }
cannam@233 332
cannam@233 333 PluginLoader::PluginCategoryHierarchy
cannam@233 334 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
cannam@233 335 {
cannam@233 336 if (m_taxonomy.empty()) generateTaxonomy();
cannam@233 337 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
cannam@233 338 return PluginCategoryHierarchy();
cannam@233 339 }
cannam@233 340 return m_taxonomy[plugin];
cannam@233 341 }
cannam@233 342
cannam@233 343 string
cannam@233 344 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
cannam@233 345 {
cannam@233 346 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 347 if (m_allPluginsEnumerated) return "";
cannam@233 348 enumeratePlugins(plugin);
cannam@233 349 }
cannam@233 350 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
cannam@233 351 return "";
cannam@233 352 }
cannam@233 353 return m_pluginLibraryNameMap[plugin];
cannam@233 354 }
cannam@233 355
cannam@233 356 Plugin *
cannam@233 357 PluginLoader::Impl::loadPlugin(PluginKey key,
cannam@233 358 float inputSampleRate, int adapterFlags)
cannam@233 359 {
cannam@233 360 string libname, identifier;
cannam@233 361 if (!decomposePluginKey(key, libname, identifier)) {
cannam@233 362 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
cannam@233 363 << key << "\" in loadPlugin" << std::endl;
cannam@233 364 return 0;
cannam@233 365 }
cannam@233 366
cannam@233 367 string fullPath = getLibraryPathForPlugin(key);
cannam@233 368 if (fullPath == "") return 0;
cannam@233 369
cannam@233 370 void *handle = loadLibrary(fullPath);
cannam@233 371 if (!handle) return 0;
cannam@233 372
cannam@233 373 VampGetPluginDescriptorFunction fn =
cannam@233 374 (VampGetPluginDescriptorFunction)lookupInLibrary
cannam@233 375 (handle, "vampGetPluginDescriptor");
cannam@233 376
cannam@233 377 if (!fn) {
cannam@233 378 unloadLibrary(handle);
cannam@233 379 return 0;
cannam@233 380 }
cannam@233 381
cannam@233 382 int index = 0;
cannam@233 383 const VampPluginDescriptor *descriptor = 0;
cannam@233 384
cannam@233 385 while ((descriptor = fn(VAMP_API_VERSION, index))) {
cannam@233 386
cannam@233 387 if (string(descriptor->identifier) == identifier) {
cannam@233 388
cannam@233 389 Vamp::PluginHostAdapter *plugin =
cannam@233 390 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
cannam@233 391
cannam@233 392 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
cannam@233 393
cannam@233 394 m_pluginLibraryHandleMap[adapter] = handle;
cannam@233 395
cannam@233 396 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
cannam@233 397 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
cannam@233 398 adapter = new PluginInputDomainAdapter(adapter);
cannam@233 399 }
cannam@233 400 }
cannam@233 401
cannam@233 402 if (adapterFlags & ADAPT_BUFFER_SIZE) {
cannam@233 403 adapter = new PluginBufferingAdapter(adapter);
cannam@233 404 }
cannam@233 405
cannam@233 406 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
cannam@233 407 adapter = new PluginChannelAdapter(adapter);
cannam@233 408 }
cannam@233 409
cannam@233 410 return adapter;
cannam@233 411 }
cannam@233 412
cannam@233 413 ++index;
cannam@233 414 }
cannam@233 415
cannam@233 416 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
cannam@233 417 << identifier << "\" not found in library \""
cannam@233 418 << fullPath << "\"" << endl;
cannam@233 419
cannam@233 420 return 0;
cannam@233 421 }
cannam@233 422
cannam@233 423 void
cannam@233 424 PluginLoader::Impl::generateTaxonomy()
cannam@233 425 {
cannam@233 426 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
cannam@233 427
cannam@233 428 vector<string> path = PluginHostAdapter::getPluginPath();
cannam@233 429 string libfragment = "/lib/";
cannam@233 430 vector<string> catpath;
cannam@233 431
cannam@233 432 string suffix = "cat";
cannam@233 433
cannam@233 434 for (vector<string>::iterator i = path.begin();
cannam@233 435 i != path.end(); ++i) {
cannam@233 436
cannam@233 437 // It doesn't matter that we're using literal forward-slash in
cannam@233 438 // this bit, as it's only relevant if the path contains
cannam@233 439 // "/lib/", which is only meaningful and only plausible on
cannam@233 440 // systems with forward-slash delimiters
cannam@233 441
cannam@233 442 string dir = *i;
cannam@233 443 string::size_type li = dir.find(libfragment);
cannam@233 444
cannam@233 445 if (li != string::npos) {
cannam@233 446 catpath.push_back
cannam@233 447 (dir.substr(0, li)
cannam@233 448 + "/share/"
cannam@233 449 + dir.substr(li + libfragment.length()));
cannam@233 450 }
cannam@233 451
cannam@233 452 catpath.push_back(dir);
cannam@233 453 }
cannam@233 454
cannam@233 455 char buffer[1024];
cannam@233 456
cannam@233 457 for (vector<string>::iterator i = catpath.begin();
cannam@233 458 i != catpath.end(); ++i) {
cannam@233 459
cannam@233 460 vector<string> files = listFiles(*i, suffix);
cannam@233 461
cannam@233 462 for (vector<string>::iterator fi = files.begin();
cannam@233 463 fi != files.end(); ++fi) {
cannam@233 464
cannam@233 465 string filepath = splicePath(*i, *fi);
cannam@233 466 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
cannam@233 467
cannam@233 468 if (is.fail()) {
cannam@233 469 // cerr << "failed to open: " << filepath << endl;
cannam@233 470 continue;
cannam@233 471 }
cannam@233 472
cannam@233 473 // cerr << "opened: " << filepath << endl;
cannam@233 474
cannam@233 475 while (!!is.getline(buffer, 1024)) {
cannam@233 476
cannam@233 477 string line(buffer);
cannam@233 478
cannam@233 479 // cerr << "line = " << line << endl;
cannam@233 480
cannam@233 481 string::size_type di = line.find("::");
cannam@233 482 if (di == string::npos) continue;
cannam@233 483
cannam@233 484 string id = line.substr(0, di);
cannam@233 485 string encodedCat = line.substr(di + 2);
cannam@233 486
cannam@233 487 if (id.substr(0, 5) != "vamp:") continue;
cannam@233 488 id = id.substr(5);
cannam@233 489
cannam@233 490 while (encodedCat.length() >= 1 &&
cannam@233 491 encodedCat[encodedCat.length()-1] == '\r') {
cannam@233 492 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
cannam@233 493 }
cannam@233 494
cannam@233 495 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
cannam@233 496
cannam@233 497 PluginCategoryHierarchy category;
cannam@233 498 string::size_type ai;
cannam@233 499 while ((ai = encodedCat.find(" > ")) != string::npos) {
cannam@233 500 category.push_back(encodedCat.substr(0, ai));
cannam@233 501 encodedCat = encodedCat.substr(ai + 3);
cannam@233 502 }
cannam@233 503 if (encodedCat != "") category.push_back(encodedCat);
cannam@233 504
cannam@233 505 m_taxonomy[id] = category;
cannam@233 506 }
cannam@233 507 }
cannam@233 508 }
cannam@233 509 }
cannam@233 510
cannam@233 511 void *
cannam@233 512 PluginLoader::Impl::loadLibrary(string path)
cannam@233 513 {
cannam@233 514 void *handle = 0;
cannam@233 515 #ifdef _WIN32
cannam@233 516 handle = LoadLibrary(path.c_str());
cannam@233 517 if (!handle) {
cannam@233 518 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
cannam@233 519 << path << "\"" << endl;
cannam@233 520 }
cannam@233 521 #else
cannam@233 522 handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
cannam@233 523 if (!handle) {
cannam@233 524 cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
cannam@233 525 << path << "\": " << dlerror() << endl;
cannam@233 526 }
cannam@233 527 #endif
cannam@233 528 return handle;
cannam@233 529 }
cannam@233 530
cannam@233 531 void
cannam@233 532 PluginLoader::Impl::unloadLibrary(void *handle)
cannam@233 533 {
cannam@233 534 #ifdef _WIN32
cannam@233 535 FreeLibrary((HINSTANCE)handle);
cannam@233 536 #else
cannam@233 537 dlclose(handle);
cannam@233 538 #endif
cannam@233 539 }
cannam@233 540
cannam@233 541 void *
cannam@233 542 PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
cannam@233 543 {
cannam@233 544 #ifdef _WIN32
cannam@233 545 return (void *)GetProcAddress((HINSTANCE)handle, symbol);
cannam@233 546 #else
cannam@233 547 return (void *)dlsym(handle, symbol);
cannam@233 548 #endif
cannam@233 549 }
cannam@233 550
cannam@233 551 string
cannam@233 552 PluginLoader::Impl::splicePath(string a, string b)
cannam@233 553 {
cannam@233 554 #ifdef _WIN32
cannam@233 555 return a + "\\" + b;
cannam@233 556 #else
cannam@233 557 return a + "/" + b;
cannam@233 558 #endif
cannam@233 559 }
cannam@233 560
cannam@233 561 vector<string>
cannam@233 562 PluginLoader::Impl::listFiles(string dir, string extension)
cannam@233 563 {
cannam@233 564 vector<string> files;
cannam@233 565
cannam@233 566 #ifdef _WIN32
cannam@233 567
cannam@233 568 string expression = dir + "\\*." + extension;
cannam@233 569 WIN32_FIND_DATA data;
cannam@233 570 HANDLE fh = FindFirstFile(expression.c_str(), &data);
cannam@233 571 if (fh == INVALID_HANDLE_VALUE) return files;
cannam@233 572
cannam@233 573 bool ok = true;
cannam@233 574 while (ok) {
cannam@233 575 files.push_back(data.cFileName);
cannam@233 576 ok = FindNextFile(fh, &data);
cannam@233 577 }
cannam@233 578
cannam@233 579 FindClose(fh);
cannam@233 580
cannam@233 581 #else
cannam@233 582
cannam@233 583 size_t extlen = extension.length();
cannam@233 584 DIR *d = opendir(dir.c_str());
cannam@233 585 if (!d) return files;
cannam@233 586
cannam@233 587 struct dirent *e = 0;
cannam@233 588 while ((e = readdir(d))) {
cannam@233 589
cannam@233 590 if (!e->d_name) continue;
cannam@233 591
cannam@233 592 size_t len = strlen(e->d_name);
cannam@233 593 if (len < extlen + 2 ||
cannam@233 594 e->d_name + len - extlen - 1 != "." + extension) {
cannam@233 595 continue;
cannam@233 596 }
cannam@233 597
cannam@233 598 files.push_back(e->d_name);
cannam@233 599 }
cannam@233 600
cannam@233 601 closedir(d);
cannam@233 602 #endif
cannam@233 603
cannam@233 604 return files;
cannam@233 605 }
cannam@233 606
cannam@233 607 void
cannam@233 608 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
cannam@233 609 {
cannam@233 610 void *handle = m_pluginLibraryHandleMap[adapter];
cannam@233 611 if (handle) unloadLibrary(handle);
cannam@233 612 m_pluginLibraryHandleMap.erase(adapter);
cannam@233 613 }
cannam@233 614
cannam@233 615 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
cannam@233 616 Impl *loader) :
cannam@233 617 PluginWrapper(plugin),
cannam@233 618 m_loader(loader)
cannam@233 619 {
cannam@233 620 }
cannam@233 621
cannam@233 622 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
cannam@233 623 {
cannam@233 624 // We need to delete the plugin before calling pluginDeleted, as
cannam@233 625 // the delete call may require calling through to the descriptor
cannam@233 626 // (for e.g. cleanup) but pluginDeleted may unload the required
cannam@233 627 // library for the call. To prevent a double deletion when our
cannam@233 628 // parent's destructor runs (after this one), be sure to set
cannam@233 629 // m_plugin to 0 after deletion.
cannam@233 630 delete m_plugin;
cannam@233 631 m_plugin = 0;
cannam@233 632
cannam@233 633 if (m_loader) m_loader->pluginDeleted(this);
cannam@233 634 }
cannam@233 635
cannam@233 636 }
cannam@233 637
cannam@233 638 }
cannam@263 639
cannam@263 640 _VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)
cannam@263 641