ardour
control_protocol_manager.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2007 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include <glibmm/module.h>
21 
22 #include <glibmm/fileutils.h>
23 
24 #include "pbd/compose.h"
25 #include "pbd/file_utils.h"
26 #include "pbd/error.h"
27 
28 #include "control_protocol/control_protocol.h"
29 
30 #include "ardour/debug.h"
32 
33 #include "ardour/search_paths.h"
34 
35 
36 using namespace ARDOUR;
37 using namespace std;
38 using namespace PBD;
39 
40 #include "i18n.h"
41 
43 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
44 
46 {
47 }
48 
50 {
51  Glib::Threads::Mutex::Lock lm (protocols_lock);
52 
53  for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
54  delete (*i);
55  }
56 
57  control_protocols.clear ();
58 
59 
60  for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
61  delete (*p);
62  }
63 
64  control_protocol_info.clear();
65 }
66 
67 void
69 {
71 
72  if (_session) {
73  Glib::Threads::Mutex::Lock lm (protocols_lock);
74 
75  for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
76  if ((*i)->requested || (*i)->mandatory) {
77  (void) activate (**i);
78  }
79  }
80  }
81 }
82 
83 int
85 {
86  ControlProtocol* cp;
87 
88  cpi.requested = true;
89 
90  if ((cp = instantiate (cpi)) == 0) {
91  return -1;
92  }
93 
94  /* we split the set_state() and set_active() operations so that
95  protocols that need state to configure themselves (e.g. "What device
96  is connected, or supposed to be connected?") can get it before
97  actually starting any interaction.
98  */
99 
100  if (cpi.state) {
101  /* force this by tweaking the internals of the state
102  * XMLNode. Ugh.
103  */
104  cp->set_state (*cpi.state, Stateful::loading_state_version);
105  } else {
106  /* guarantee a call to
107  set_state() whether we have
108  existing state or not
109  */
110  cp->set_state (XMLNode(""), Stateful::loading_state_version);
111  }
112 
113  cp->set_active (true);
114 
115  return 0;
116 }
117 
118 int
120 {
121  cpi.requested = false;
122  return teardown (cpi);
123 }
124 
125 void
127 {
129 
130  {
131  Glib::Threads::Mutex::Lock lm (protocols_lock);
132 
133  for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
134  delete *p;
135  }
136 
137  control_protocols.clear ();
138 
139  for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
140  // mark existing protocols as requested
141  // otherwise the ControlProtocol instances are not recreated in set_session
142  if ((*p)->protocol) {
143  (*p)->requested = true;
144  (*p)->protocol = 0;
145  }
146  }
147  }
148 }
149 
150 ControlProtocol*
152 {
153  /* CALLER MUST HOLD LOCK */
154 
155  if (_session == 0) {
156  return 0;
157  }
158 
159  cpi.descriptor = get_descriptor (cpi.path);
160 
161  DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
162 
163  if (cpi.descriptor == 0) {
164  error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
165  return 0;
166  }
167 
168  DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("initializing %1\n", cpi.name));
169 
170  if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
171  error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
172  return 0;
173  }
174 
175  control_protocols.push_back (cpi.protocol);
176 
177  ProtocolStatusChange (&cpi);
178 
179  return cpi.protocol;
180 }
181 
182 int
184 {
185  if (!cpi.protocol) {
186  return 0;
187  }
188 
189  if (!cpi.descriptor) {
190  return 0;
191  }
192 
193  if (cpi.mandatory) {
194  return 0;
195  }
196 
197  /* save current state */
198 
199  delete cpi.state;
200  cpi.state = new XMLNode (cpi.protocol->get_state());
201  cpi.state->add_property (X_("active"), "no");
202 
203  cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
204 
205  {
206  Glib::Threads::Mutex::Lock lm (protocols_lock);
207  list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
208  if (p != control_protocols.end()) {
209  control_protocols.erase (p);
210  } else {
211  cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
212  }
213  }
214 
215  cpi.protocol = 0;
216  delete cpi.state;
217  cpi.state = 0;
218  delete (Glib::Module*)cpi.descriptor->module;
219 
220  ProtocolStatusChange (&cpi);
221 
222  return 0;
223 }
224 
225 void
227 {
228  if (_session == 0) {
229  return;
230  }
231 
232  Glib::Threads::Mutex::Lock lm (protocols_lock);
233 
234  for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
235  if ((*i)->mandatory && ((*i)->protocol == 0)) {
237  string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name));
238  instantiate (**i);
239  }
240  }
241 }
242 
243 void
245 {
246  vector<std::string> cp_modules;
247 
248 #ifdef COMPILER_MSVC
249 
255  #if defined (_DEBUG)
256  Glib::PatternSpec dll_extension_pattern("*D.dll");
257  #elif defined (RDC_BUILD)
258  Glib::PatternSpec dll_extension_pattern("*RDC.dll");
259  #elif defined (_WIN64)
260  Glib::PatternSpec dll_extension_pattern("*64.dll");
261  #else
262  Glib::PatternSpec dll_extension_pattern("*32.dll");
263  #endif
264 #else
265  Glib::PatternSpec dll_extension_pattern("*.dll");
266 #endif
267 
268  Glib::PatternSpec so_extension_pattern("*.so");
269  Glib::PatternSpec dylib_extension_pattern("*.dylib");
270 
272  dll_extension_pattern);
273 
275  so_extension_pattern);
276 
278  dylib_extension_pattern);
279 
281  string_compose (_("looking for control protocols in %1\n"), control_protocol_search_path().to_string()));
282 
283  for (vector<std::string>::iterator i = cp_modules.begin(); i != cp_modules.end(); ++i) {
284  control_protocol_discover (*i);
285  }
286 }
287 
288 int
290 {
291  ControlProtocolDescriptor* descriptor;
292 
293 #ifdef __APPLE__
294  /* don't load OS X shared objects that are just symlinks to the real thing.
295  */
296 
297  if (path.find (".dylib") && Glib::file_test (path, Glib::FILE_TEST_IS_SYMLINK)) {
298  return 0;
299  }
300 #endif
301 
302  if ((descriptor = get_descriptor (path)) != 0) {
303 
304  if (!descriptor->probe (descriptor)) {
306  string_compose (_("Control protocol %1 not usable"), descriptor->name));
307  } else {
308 
310 
311  cpi->descriptor = descriptor;
312  cpi->name = descriptor->name;
313  cpi->path = path;
314  cpi->protocol = 0;
315  cpi->requested = false;
316  cpi->mandatory = descriptor->mandatory;
317  cpi->supports_feedback = descriptor->supports_feedback;
318  cpi->state = 0;
319 
320  control_protocol_info.push_back (cpi);
321 
323  string_compose(_("Control surface protocol discovered: \"%1\"\n"), cpi->name));
324  }
325 
326  delete (Glib::Module*)descriptor->module;
327  }
328 
329  return 0;
330 }
331 
332 ControlProtocolDescriptor*
334 {
335  Glib::Module* module = new Glib::Module(path);
336  ControlProtocolDescriptor *descriptor = 0;
337  ControlProtocolDescriptor* (*dfunc)(void);
338  void* func = 0;
339 
340  if (!(*module)) {
341  error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, Glib::Module::get_last_error()) << endmsg;
342  delete module;
343  return 0;
344  }
345 
346  if (!module->get_symbol("protocol_descriptor", func)) {
347  error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
348  error << Glib::Module::get_last_error() << endmsg;
349  delete module;
350  return 0;
351  }
352 
353  dfunc = (ControlProtocolDescriptor* (*)(void))func;
354  descriptor = dfunc();
355 
356  if (descriptor) {
357  descriptor->module = (void*)module;
358  } else {
359  delete module;
360  }
361 
362  return descriptor;
363 }
364 
365 void
367 {
368  for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
369  method (*i);
370  }
371 }
372 
375 {
376  for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
377  if (name == (*i)->name) {
378  return *i;
379  }
380  }
381  return 0;
382 }
383 
384 int
385 ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
386 {
387  XMLNodeList clist;
388  XMLNodeConstIterator citer;
389  XMLProperty* prop;
390 
391  Glib::Threads::Mutex::Lock lm (protocols_lock);
392 
393  clist = node.children();
394 
395  for (citer = clist.begin(); citer != clist.end(); ++citer) {
396  if ((*citer)->name() == X_("Protocol")) {
397 
398  if ((prop = (*citer)->property (X_("active"))) == 0) {
399  continue;
400  }
401 
402  bool active = string_is_affirmative (prop->value());
403 
404  if ((prop = (*citer)->property (X_("name"))) == 0) {
405  continue;
406  }
407 
408  ControlProtocolInfo* cpi = cpi_by_name (prop->value());
409 
410  if (cpi) {
411  cpi->state = new XMLNode (**citer);
412 
413  if (active) {
414  if (_session) {
415  instantiate (*cpi);
416  } else {
417  cpi->requested = true;
418  }
419  } else {
420  if (_session) {
421  teardown (*cpi);
422  } else {
423  cpi->requested = false;
424  }
425  }
426  }
427  }
428  }
429 
430  return 0;
431 }
432 
433 XMLNode&
435 {
436  XMLNode* root = new XMLNode (state_node_name);
437  Glib::Threads::Mutex::Lock lm (protocols_lock);
438 
439  for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
440 
441  if ((*i)->protocol) {
442  XMLNode& child_state ((*i)->protocol->get_state());
443  child_state.add_property (X_("active"), "yes");
444  root->add_child_nocopy (child_state);
445  } else if ((*i)->state) {
446  XMLNode* child_state = new XMLNode (*(*i)->state);
447  child_state->add_property (X_("active"), "no");
448  root->add_child_nocopy (*child_state);
449  } else {
450  XMLNode* child_state = new XMLNode (X_("Protocol"));
451  child_state->add_property (X_("name"), (*i)->name);
452  child_state->add_property (X_("active"), "no");
453  root->add_child_nocopy (*child_state);
454  }
455 
456  }
457 
458  return *root;
459 }
460 
461 
464 {
465  if (_instance == 0) {
466  _instance = new ControlProtocolManager ();
467  }
468 
469  return *_instance;
470 }
471 
472 void
474 {
475  Glib::Threads::Mutex::Lock lm (protocols_lock);
476 
477  for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
478  (*p)->midi_connectivity_established ();
479  }
480 }
std::string to_string(T t, std::ios_base &(*f)(std::ios_base &))
Definition: convert.h:53
ControlProtocolInfo * cpi_by_name(std::string)
virtual void session_going_away()
const std::string & value() const
Definition: xml++.h:159
int control_protocol_discover(std::string path)
int deactivate(ControlProtocolInfo &)
int set_state(const XMLNode &, int version)
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
static ControlProtocolManager & instance()
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
static const char * state_node_name
Definition: chan_count.cc:26
#define X_(Text)
Definition: i18n.h:13
void find_files_matching_pattern(vector< string > &result, const Searchpath &paths, const Glib::PatternSpec &pattern)
Definition: file_utils.cc:168
LIBARDOUR_API PBD::Searchpath control_protocol_search_path()
Definition: search_paths.cc:62
static ControlProtocolManager * _instance
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
Definition: amp.h:29
ControlProtocolDescriptor * descriptor
ControlProtocol * instantiate(ControlProtocolInfo &)
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
static const std::string state_node_name
static int loading_state_version
Definition: stateful.h:90
LIBARDOUR_API PBD::PropertyDescriptor< bool > active
Definition: route_group.cc:43
XMLProperty * add_property(const char *name, const std::string &value)
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
Definition: xml++.h:95
ControlProtocolDescriptor * get_descriptor(std::string path)
Definition: debug.h:30
virtual void set_session(ARDOUR::Session *)
void foreach_known_protocol(boost::function< void(const ControlProtocolInfo *)>)
XMLNodeList::const_iterator XMLNodeConstIterator
Definition: xml++.h:49
LIBARDOUR_API uint64_t ControlProtocols
Definition: debug.cc:55
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
int activate(ControlProtocolInfo &)