comparison plugin/FeatureExtractionPluginFactory.cpp @ 1209:385deb828b4a piper

Bodge in piper-cpp client (not yet working)
author Chris Cannam
date Fri, 14 Oct 2016 14:33:43 +0100
parents 98664afd518b
children 584b2d7d7cd9
comparison
equal deleted inserted replaced
1208:fef49844b3f8 1209:385deb828b4a
34 34
35 using namespace std; 35 using namespace std;
36 36
37 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 37 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
38 38
39 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper {
40 public:
41 PluginDeletionNotifyAdapter(Vamp::Plugin *plugin,
42 FeatureExtractionPluginFactory *factory) :
43 PluginWrapper(plugin), m_factory(factory) { }
44 virtual ~PluginDeletionNotifyAdapter();
45 protected:
46 FeatureExtractionPluginFactory *m_factory;
47 };
48
49 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
50 {
51 // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn
52 Vamp::Plugin *p = m_plugin;
53 delete m_plugin;
54 m_plugin = 0;
55 // acceptable use after free here, as pluginDeleted uses p only as
56 // pointer key and does not deref it
57 if (m_factory) m_factory->pluginDeleted(p);
58 }
59
60 static FeatureExtractionPluginFactory *_nativeInstance = 0; 39 static FeatureExtractionPluginFactory *_nativeInstance = 0;
61 40
62 FeatureExtractionPluginFactory * 41 FeatureExtractionPluginFactory *
63 FeatureExtractionPluginFactory::instance(QString pluginType) 42 FeatureExtractionPluginFactory::instance(QString pluginType)
64 { 43 {
79 QString type, soName, label; 58 QString type, soName, label;
80 PluginIdentifier::parseIdentifier(identifier, type, soName, label); 59 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
81 return instance(type); 60 return instance(type);
82 } 61 }
83 62
84 vector<QString> 63 FeatureExtractionPluginFactory::FeatureExtractionPluginFactory() :
85 FeatureExtractionPluginFactory::getPluginPath() 64 m_transport("piper-cpp/bin/piper-vamp-server"),
65 m_client(&m_transport)
86 { 66 {
87 if (!m_pluginPath.empty()) return m_pluginPath;
88
89 vector<string> p = Vamp::PluginHostAdapter::getPluginPath();
90 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
91 return m_pluginPath;
92 } 67 }
93 68
94 vector<QString> 69 vector<QString>
95 FeatureExtractionPluginFactory::getAllPluginIdentifiers() 70 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
96 { 71 {
115 vector<QString> 90 vector<QString>
116 FeatureExtractionPluginFactory::getPluginIdentifiers() 91 FeatureExtractionPluginFactory::getPluginIdentifiers()
117 { 92 {
118 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); 93 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers");
119 94
95 QMutexLocker locker(&m_mutex);
96
97 if (m_pluginData.empty()) {
98 populate();
99 }
100
120 vector<QString> rv; 101 vector<QString> rv;
121 102
122 QStringList candidates = PluginScan::getInstance()->getCandidateLibrariesFor 103 for (const auto &d: m_pluginData) {
123 (PluginScan::VampPlugin); 104 rv.push_back(QString("vamp:") + QString::fromStdString(d.pluginKey));
124
125 for (QString soname : candidates) {
126
127 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
128
129 if (!libraryHandle) {
130 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl;
131 continue;
132 }
133
134 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
135 DLSYM(libraryHandle, "vampGetPluginDescriptor");
136
137 if (!fn) {
138 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl;
139 if (DLCLOSE(libraryHandle) != 0) {
140 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
141 }
142 continue;
143 }
144
145 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
146 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl;
147 #endif
148
149 const VampPluginDescriptor *descriptor = 0;
150 int index = 0;
151
152 map<string, int> known;
153 bool ok = true;
154
155 while ((descriptor = fn(VAMP_API_VERSION, index))) {
156
157 if (known.find(descriptor->identifier) != known.end()) {
158 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library "
159 << soname
160 << " returns the same plugin identifier \""
161 << descriptor->identifier << "\" at indices "
162 << known[descriptor->identifier] << " and "
163 << index << endl;
164 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl;
165 ok = false;
166 break;
167 } else {
168 known[descriptor->identifier] = index;
169 }
170
171 ++index;
172 }
173
174 if (ok) {
175
176 index = 0;
177
178 while ((descriptor = fn(VAMP_API_VERSION, index))) {
179
180 QString id = PluginIdentifier::createIdentifier
181 ("vamp", soname, descriptor->identifier);
182 rv.push_back(id);
183 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
184 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl;
185 #endif
186 ++index;
187 }
188 }
189
190 if (DLCLOSE(libraryHandle) != 0) {
191 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
192 }
193 } 105 }
194 106
195 generateTaxonomy();
196
197 return rv; 107 return rv;
198 }
199
200 QString
201 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir)
202 {
203 QString file = "";
204
205 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
206 cerr << "FeatureExtractionPluginFactory::findPluginFile(\""
207 << soname << "\", \"" << inDir << "\")"
208 << endl;
209 #endif
210
211 if (inDir != "") {
212
213 QDir dir(inDir, PLUGIN_GLOB,
214 QDir::Name | QDir::IgnoreCase,
215 QDir::Files | QDir::Readable);
216 if (!dir.exists()) return "";
217
218 file = dir.filePath(QFileInfo(soname).fileName());
219
220 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) {
221
222 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
223 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
224 << "found trivially at " << file << endl;
225 #endif
226
227 return file;
228 }
229
230 for (unsigned int j = 0; j < dir.count(); ++j) {
231 file = dir.filePath(dir[j]);
232 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) {
233
234 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
235 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
236 << "found \"" << soname << "\" at " << file << endl;
237 #endif
238
239 return file;
240 }
241 }
242
243 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
244 cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): "
245 << "not found" << endl;
246 #endif
247
248 return "";
249
250 } else {
251
252 QFileInfo fi(soname);
253
254 if (fi.isAbsolute() && fi.exists() && fi.isFile()) {
255 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
256 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
257 << "found trivially at " << soname << endl;
258 #endif
259 return soname;
260 }
261
262 if (fi.isAbsolute() && fi.absolutePath() != "") {
263 file = findPluginFile(soname, fi.absolutePath());
264 if (file != "") return file;
265 }
266
267 vector<QString> path = getPluginPath();
268 for (vector<QString>::iterator i = path.begin();
269 i != path.end(); ++i) {
270 if (*i != "") {
271 file = findPluginFile(soname, *i);
272 if (file != "") return file;
273 }
274 }
275
276 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
277 cerr << "FeatureExtractionPluginFactory::findPluginFile: "
278 << "not found" << endl;
279 #endif
280
281 return "";
282 }
283 } 108 }
284 109
285 Vamp::Plugin * 110 Vamp::Plugin *
286 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, 111 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier,
287 sv_samplerate_t inputSampleRate) 112 sv_samplerate_t inputSampleRate)
288 { 113 {
289 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin"); 114 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin");
290 115
291 Vamp::Plugin *rv = 0;
292 Vamp::PluginHostAdapter *plugin = 0;
293
294 const VampPluginDescriptor *descriptor = 0;
295 int index = 0;
296
297 QString type, soname, label; 116 QString type, soname, label;
298 PluginIdentifier::parseIdentifier(identifier, type, soname, label); 117 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
299 if (type != "vamp") {
300 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
301 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl;
302 #endif
303 return 0;
304 }
305 118
306 QString found = findPluginFile(soname); 119 piper_vamp::LoadRequest request;
120 request.pluginKey = (soname + ":" + label).toStdString();
121 request.inputSampleRate = inputSampleRate;
122 request.adapterFlags = 0;
123 piper_vamp::LoadResponse response = m_client.loadPlugin(request);
307 124
308 if (found == "") { 125 return response.plugin;
309 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl;
310 return 0;
311 } else if (found != soname) {
312
313 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
314 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl;
315 cerr << soname << " -> " << found << endl;
316 #endif
317
318 }
319
320 soname = found;
321
322 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
323
324 if (!libraryHandle) {
325 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl;
326 return 0;
327 }
328
329 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
330 DLSYM(libraryHandle, "vampGetPluginDescriptor");
331
332 if (!fn) {
333 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl;
334 goto done;
335 }
336
337 while ((descriptor = fn(VAMP_API_VERSION, index))) {
338 if (label == descriptor->identifier) break;
339 ++index;
340 }
341
342 if (!descriptor) {
343 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl;
344 goto done;
345 }
346
347 plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate));
348
349 if (plugin) {
350 m_handleMap[plugin] = libraryHandle;
351 rv = new PluginDeletionNotifyAdapter(plugin, this);
352 }
353
354 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl;
355
356 //!!! need to dlclose() when plugins from a given library are unloaded
357
358 done:
359 if (!rv) {
360 if (DLCLOSE(libraryHandle) != 0) {
361 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl;
362 }
363 }
364
365 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
366 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl;
367 #endif
368
369 return rv;
370 }
371
372 void
373 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
374 {
375 void *handle = m_handleMap[plugin];
376 if (handle) {
377 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
378 cerr << "unloading library " << handle << " for plugin " << plugin << endl;
379 #endif
380 DLCLOSE(handle);
381 }
382 m_handleMap.erase(plugin);
383 } 126 }
384 127
385 QString 128 QString
386 FeatureExtractionPluginFactory::getPluginCategory(QString identifier) 129 FeatureExtractionPluginFactory::getPluginCategory(QString identifier)
387 { 130 {
388 return m_taxonomy[identifier]; 131 //!!! (re)implement
132 // return m_taxonomy[identifier];
133 return QString();
389 } 134 }
390 135
391 void 136 void
392 FeatureExtractionPluginFactory::generateTaxonomy() 137 FeatureExtractionPluginFactory::populate()
393 { 138 {
394 vector<QString> pluginPath = getPluginPath(); 139 piper_vamp::ListResponse lr = m_client.listPluginData();
395 vector<QString> path; 140 m_pluginData = lr.available;
141 }
396 142
397 for (size_t i = 0; i < pluginPath.size(); ++i) {
398 if (pluginPath[i].contains("/lib/")) {
399 QString p(pluginPath[i]);
400 path.push_back(p);
401 p.replace("/lib/", "/share/");
402 path.push_back(p);
403 }
404 path.push_back(pluginPath[i]);
405 }
406
407 for (size_t i = 0; i < path.size(); ++i) {
408
409 QDir dir(path[i], "*.cat");
410
411 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl;
412 for (unsigned int j = 0; j < dir.count(); ++j) {
413
414 QFile file(path[i] + "/" + dir[j]);
415
416 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl;
417
418 if (file.open(QIODevice::ReadOnly)) {
419 // cerr << "...opened" << endl;
420 QTextStream stream(&file);
421 QString line;
422
423 while (!stream.atEnd()) {
424 line = stream.readLine();
425 // cerr << "line is: \"" << line << "\"" << endl;
426 QString id = PluginIdentifier::canonicalise
427 (line.section("::", 0, 0));
428 QString cat = line.section("::", 1, 1);
429 m_taxonomy[id] = cat;
430 // cerr << "FeatureExtractionPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl;
431 }
432 }
433 }
434 }
435 }